diff options
Diffstat (limited to 'Build/source/texk/web2c/mf.tex')
-rw-r--r-- | Build/source/texk/web2c/mf.tex | 34385 |
1 files changed, 34385 insertions, 0 deletions
diff --git a/Build/source/texk/web2c/mf.tex b/Build/source/texk/web2c/mf.tex new file mode 100644 index 00000000000..a1a8bda5e63 --- /dev/null +++ b/Build/source/texk/web2c/mf.tex @@ -0,0 +1,34385 @@ +\input webmac +% This program is copyright (C) 1984 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.) +% In other words, METAFONT is under essentially the same ground rules as TeX. + +% TeX is a trademark of the American Mathematical Society. +% METAFONT is a trademark of Addison-Wesley Publishing Company. + +% Version 0 was completed on July 28, 1984. +% Version 1 was completed on January 4, 1986; it corresponds to "Volume D". +% Version 1.1 trivially corrected the punctuation in one message (June 1986). +% Version 1.2 corrected an arithmetic overflow problem (July 1986). +% Version 1.3 improved rounding when elliptical pens are made (November 1986). +% Version 1.4 corrected scan_declared_variable timing (May 1988). +% Version 1.5 fixed negative halving in allocator when mem_min<0 (June 1988). +% Version 1.6 kept open_log_file from calling fatal_error (November 1988). +% Version 1.7 solved that problem a better way (December 1988). +% Version 1.8 introduced major changes for 8-bit extensions (September 1989). +% Version 1.9 improved skimping and was edited for style (December 1989). +% Version 2.0 fixed bug in addto; released with TeX version 3.0 (March 1990). +% Version 2.7 made consistent with TeX version 3.1 (September 1990). +% Version 2.71 fixed bug in draw, allowed unprintable filenames (March 1992). +% Version 2.718 fixed bug in <Choose a dependent...> (March 1995). +% Version 2.7182 fixed bugs related to "<unprintable char>" (August 1996). +% Version 2.71828 suppressed autorounding in dangerous cases (December 2002). + +% 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 METAFONT 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\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\psqrt#1{\sqrt{\mathstrut#1}} +\def\k{_{k+1}} +\def\pct!{{\char`\%}} % percent sign in ordinary text +\font\tenlogo=logo10 % font used for the METAFONT logo +\font\logos=logosl10 +\font\eightlogo=logo8 +\def\MF{{\tenlogo META}\-{\tenlogo FONT}} +\def\<#1>{$\langle#1\rangle$} +\def\section{\mathhexbox278} +\let\swap=\leftrightarrow +\def\round{\mathop{\rm round}\nolimits} + +\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{{\eightlogo METAFONT}} +\def\topofcontents{\hsize 5.5in + \vglue -30pt 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...>" + + +\N1. \[1] Introduction. +This is \MF, a font compiler intended to produce typefaces of high quality. +The \PASCAL\ program that follows is the definition of \MF84, a standard +version of \MF\ that is designed to be highly portable so that identical output +will be obtainable on a great variety of computers. The conventions +of \MF84 are the same as those of \TeX82. + +The main purpose of the following program is to explain the algorithms of \MF\ +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 \MF\ 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 +\MF\ language itself, since the reader is supposed to be familiar with +{\sl The {\logos METAFONT\/}book}. + +\fi + +\M2. The present implementation has a long ancestry, beginning in the spring +of~1977, when its author wrote a prototype set of subroutines and macros +that were used to develop the first Computer Modern fonts. +This original proto-\MF\ required the user to recompile a {\mc SAIL} program +whenever any character was changed, because it was not a ``language'' for +font design; the language was {\mc SAIL}. After several hundred characters +had been designed in that way, the author developed an interpretable language +called \MF, in which it was possible to express the Computer Modern programs +less cryptically. A complete \MF\ processor was designed and coded by the +author in 1979. This program, written in {\mc SAIL}, was adapted for use +with a variety of typesetting equipment and display terminals by Leo Guibas, +Lyle Ramshaw, and David Fuchs. +Major improvements to the design of Computer Modern fonts were made in the +spring of 1982, after which it became clear that a new language would +better express the needs of letterform designers. Therefore an entirely +new \MF\ language and system were developed in 1984; the present system +retains the name and some of the spirit of \MF79, but all of the details +have changed. + +No doubt there still is plenty of room for improvement, but the author +is firmly committed to keeping \MF84 ``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 \MF84 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 \MF\ +undergoes any modifications, so that it will be clear which version of +\MF\ might be the guilty party when a problem arises. + +If this program is changed, the resulting system should not be called +`\MF\kern.5pt'; the official name `\MF\kern.5pt' by itself is reserved +for software systems that are fully compatible with each other. +A special test suite called the ``\.{TRAP} test'' is available for +helping to determine whether an implementation deserves to be +known as `\MF\kern.5pt' [cf.~Stanford Computer Science report CS1095, +January 1986]. + +\Y\P\D \37$\\{banner}\S\.{\'This\ is\ METAFONT,\ Version\ 2.71828\'}$\C{printed +when \MF\ starts}\par +\fi + +\M3. Different \PASCAL s have slightly different conventions, and the present +program expresses \MF\ in terms of the \PASCAL\ that was +available to the author in 1984. 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 \MF\ 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 +or in the system-dependent \\{paint\_row} procedure; +there are no tag fields on variant records; there are no \\{real} variables; +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. + +\fi + +\M4. The program begins with a normal \PASCAL\ program heading, whose +components will be filled in later, using the conventions of \.{WEB}. +For example, the portion of the program called `\X\glob:Global +variables\X' below will be replaced by a sequence of variable declarations +that starts in $\section\glob$ of this documentation. In this way, we are able +to define each individual global variable when we are prepared to +understand what it means; we do not have to define all of the globals at +once. Cross references in $\section\glob$, where it says ``See also +sections \gglob, \dots,'' also make it possible to look at the set of +all global variables, if desired. Similar remarks apply to the other +portions of the program heading. + +Actually the heading shown here is not quite normal: The \&{program}\ line +does not mention any \\{output} file, because \ph\ would ask the \MF\ user +to specify a file name if \\{output} were specified here. + +\Y\P\D \37$\\{mtype}\S\|t\J\|y\J\|p\J\|e$\C{this is a \.{WEB} coding trick:}\par +\P\F \37$\\{mtype}\S\\{type}$\C{`\&{mtype}' will be equivalent to `\&{type}'}% +\par +\P\F \37$\\{type}\S\\{true}$\C{but `\\{type}' will not be treated as a reserved +word}\par +\Y\P\hbox{\4}\X9:Compiler directives\X\6 +\4\&{program}\1\ \37\\{MF};\C{all file names are defined dynamically}\6 +\4\&{label} \37\X6:Labels in the outer block\X\6 +\4\&{const} \37\X11:Constants in the outer block\X\6 +\4\&{mtype} \37\X18:Types in the outer block\X\6 +\4\&{var} \37\X13:Global variables\X\7 +\4\&{procedure}\1\ \37\\{initialize};\C{this procedure gets things started +properly}\6 +\4\&{var} \37\X19:Local variables for initialization\X\2\6 +\&{begin} \37\X21:Set initial values of key variables\X\6 +\&{end};\7 +\hbox{\4}\X57:Basic printing procedures\X\6 +\hbox{\4}\X73:Error handling procedures\X\par +\fi + +\M5. The overall \MF\ 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 \MF's components as they appear in the +\.{WEB} description you are now reading, since the present ordering is +intended to combine the advantages of the ``bottom up'' and ``top down'' +approaches to the problem of understanding a somewhat complicated system. + +\fi + +\M6. Three labels must be declared in the main program, so we give them +symbolic names. + +\Y\P\D \37$\\{start\_of\_MF}=1$\C{go here when \MF's variables are initialized}% +\par +\P\D \37$\\{end\_of\_MF}=9998$\C{go here to close files and terminate +gracefully}\par +\P\D \37$\\{final\_end}=9999$\C{this label marks the ending of the program}\par +\Y\P$\4\X6:Labels in the outer block\X\S$\6 +$\\{start\_of\_MF}\hbox{\hskip-2pt},\39\\{end\_of\_MF}\hbox{\hskip-2pt},\39\,% +\\{final\_end}$;\C{key control points}\par +\U4.\fi + +\M7. Some of the code below is intended to be used only when diagnosing the +strange behavior that sometimes occurs when \MF\ is being installed or +when system wizards are fooling around with \MF\ without quite knowing +what they are doing. Such code will not normally be compiled; it is +delimited by the codewords `$ \&{debug} \ldots \&{gubed} $', with apologies +to people who wish to preserve the purity of English. + +Similarly, there is some conditional code delimited by +`$ \&{stat} \ldots \&{tats} $' that is intended for use when statistics are to +be +kept about \MF's memory usage. The \&{stat} $\ldots$ \&{tats} code also +implements special diagnostic information that is printed when +$\\{tracingedges}>1$. + +\Y\P\D \37$\\{debug}\S\B$\C{change this to `$\\{debug}\equiv\null$' when +debugging}\par +\P\D \37$\\{gubed}\S\hbox{}\T$\C{change this to `$\\{gubed}\equiv\null$' when +debugging}\par +\P\F \37$\\{debug}\S\\{begin}$\par +\P\F \37$\\{gubed}\S\\{end}$\Y\par +\P\D \37$\\{stat}\S\B$\C{change this to `$\\{stat}\equiv\null$' when gathering + usage statistics}\par +\P\D \37$\\{tats}\S\hbox{}\T$\C{change this to `$\\{tats}\equiv\null$' when +gathering usage statistics}\par +\P\F \37$\\{stat}\S\\{begin}$\par +\P\F \37$\\{tats}\S\\{end}$\par +\fi + +\M8. This program has two important variations: (1) There is a long and slow +version called \.{INIMF}, which does the extra calculations needed to +initialize \MF'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\P\D \37$\\{init}\S$\C{change this to `$\\{init}\equiv\.{@\{}$' in the +production version}\par +\P\D \37$\\{tini}\S$\C{change this to `$\\{tini}\equiv\.{@\}}$' in the +production version}\par +\P\F \37$\\{init}\S\\{begin}$\par +\P\F \37$\\{tini}\S\\{end}$\par +\fi + +\M9. If the first character of a \PASCAL\ comment is a dollar sign, +\ph\ treats the comment as a list of ``compiler directives'' that will +affect the translation of this program into machine language. The +directives shown below specify full checking and inclusion of the \PASCAL\ +debugger when \MF\ is being debugged, but they cause range checking and other +redundant code to be eliminated when the production system is being generated. +Arithmetic overflow will be detected in all cases. + +\Y\P$\4\X9:Compiler directives\X\S$\6 +$\B\J\$\|C-,\39\|A+,\39\|D-\T$\C{no range check, catch arithmetic overflow, no +debug overhead}\6 +\&{debug} \37$\B\J\$\|C+,\39\|D+\T$\ \&{gubed}\C{but turn everything on when +debugging}\par +\U4.\fi + +\M10. This \MF\ implementation conforms to the rules of the {\sl Pascal User +Manual} published by Jensen and Wirth in 1975, except where system-dependent +code is necessary to make a useful system program, and except in another +respect where such conformity would unnecessarily obscure the meaning +and clutter up the code: We assume that \&{case} statements may include a +default case that applies if no matching label is found. Thus, we shall use +constructions like +$$\vbox{\halign{\ignorespaces#\hfil\cr + \&{case} $\|x$ \&{of}\cr +1: $\langle\,$code for $x=1\,\rangle$;\cr +3: $\langle\,$code for $x=3\,\rangle$;\cr + \&{othercases} $\langle\,$code for $\|x\I1$ and $\|x\I3$$\,\rangle$\cr + \&{endcases} \cr}}$$ +since most \PASCAL\ compilers have plugged this hole in the language by +incorporating some sort of default mechanism. For example, the \ph\ +compiler allows `\\{others}:' as a default label, and other \PASCAL s allow +syntaxes like `\&{else}' or `\&{otherwise}' or `\\{otherwise}:', etc. The +definitions of \&{othercases} and \&{endcases} should be changed to agree +with +local conventions. Note that no semicolon appears before \&{endcases} in +this program, so the definition of \&{endcases} should include a semicolon +if the compiler wants one. (Of course, if no default mechanism is +available, the \&{case} statements of \MF\ will have to be laboriously +extended by listing all remaining cases. People who are stuck with such +\PASCAL s have, in fact, done this, successfully but not happily!) + +\Y\P\D \37$\\{othercases}\S\\{others}$: \37\C{default for cases not listed +explicitly}\par +\P\D \37$\\{endcases}\S$\ \&{end} \C{follows the default case in an extended % +\&{case} statement}\par +\P\F \37$\\{othercases}\S\\{else}$\par +\P\F \37$\\{endcases}\S\\{end}$\par +\fi + +\M11. The following parameters can be changed at compile time to extend or +reduce \MF's capacity. They may have different values in \.{INIMF} and +in production versions of \MF. + +\Y\P$\4\X11:Constants in the outer block\X\S$\6 +$\\{mem\_max}=30000$;\C{greatest index in \MF's internal \\{mem} array; must +be strictly less than \\{max\_halfword}; must be equal to \\{mem\_top} in % +\.{INIMF}, otherwise $\G\\{mem\_top}$}\6 +$\\{max\_internal}=100$;\C{maximum number of internal quantities}\6 +$\\{buf\_size}=500$;\C{maximum number of characters simultaneously present in +current lines of open files; must not exceed \\{max\_halfword}}\6 +$\\{error\_line}=72$;\C{width of context lines on terminal error messages}\6 +$\\{half\_error\_line}=42$;\C{width of first lines of contexts in terminal +error messages; should be between 30 and $\\{error\_line}-15$}\6 +$\\{max\_print\_line}=79$;\C{width of longest text lines output; should be at +least 60}\6 +$\\{screen\_width}=768$;\C{number of pixels in each row of screen display}\6 +$\\{screen\_depth}=1024$;\C{number of pixels in each column of screen display}\6 +$\\{stack\_size}=30$;\C{maximum number of simultaneous input sources}\6 +$\\{max\_strings}=2000$;\C{maximum number of strings; must not exceed \\{max% +\_halfword}}\6 +$\\{string\_vacancies}=8000$;\C{the minimum number of characters that should be + available for the user's identifier names and strings, after \MF's own +error messages are stored}\6 +$\\{pool\_size}=32000$;\C{maximum number of characters in strings, including +all error messages and help texts, and the names of all identifiers; must +exceed \\{string\_vacancies} by the total length of \MF's own strings, which +is currently about 22000}\6 +$\\{move\_size}=5000$;\C{space for storing moves in a single octant}\6 +$\\{max\_wiggle}=300$;\C{number of autorounded points per cycle}\6 +$\\{gf\_buf\_size}=800$;\C{size of the output buffer, must be a multiple of 8}\6 +$\\{file\_name\_size}=40$;\C{file names shouldn't be longer than this}\6 +$\\{pool\_name}=\.{\'MFbases:MF.POOL\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ +\ \ \ \'}$;\C{string of length \\{file\_name\_size}; tells where the string +pool appears}\6 +$\\{path\_size}=300$;\C{maximum number of knots between breakpoints of a path}\6 +$\\{bistack\_size}=785$;\C{size of stack for bisection algorithms; should +probably be left at this value}\6 +$\\{header\_size}=100$;\C{maximum number of \.{TFM} header words, times~4}\6 +$\\{lig\_table\_size}=5000$;\C{maximum number of ligature/kern steps, must be +at least 255 and at most 32510}\6 +$\\{max\_kerns}=500$;\C{maximum number of distinct kern amounts}\6 +$\\{max\_font\_dimen}=50$;\C{maximum number of \&{fontdimen} parameters}\par +\U4.\fi + +\M12. Like the preceding parameters, the following quantities can be changed +at compile time to extend or reduce \MF's capacity. But if they are changed, +it is necessary to rerun the initialization program \.{INIMF} +to generate new tables for the production \MF\ program. +One can't simply make helter-skelter changes to the following constants, +since certain rather complex initialization +numbers are computed from them. They are defined here using +\.{WEB} macros, instead of being put into \PASCAL's \&{const} list, in order +to +emphasize this distinction. + +\Y\P\D \37$\\{mem\_min}=0$\C{smallest index in the \\{mem} array, must not be +less than \\{min\_halfword}}\par +\P\D \37$\\{mem\_top}\S30000$\C{largest index in the \\{mem} array dumped by % +\.{INIMF}; must be substantially larger than \\{mem\_min} and not greater +than \\{mem\_max}}\par +\P\D \37$\\{hash\_size}=2100$\C{maximum number of symbolic tokens, must be +less than $\\{max\_halfword}-3\ast\\{param\_size}$}\par +\P\D \37$\\{hash\_prime}=1777$\C{a prime number equal to about 85\pct! of % +\\{hash\_size}}\par +\P\D \37$\\{max\_in\_open}=6$\C{maximum number of input files and error +insertions that can be going on simultaneously}\par +\P\D \37$\\{param\_size}=150$\C{maximum number of simultaneous macro +parameters}\par +\fi + +\M13. In case somebody has inadvertently made bad settings of the +``constants,'' +\MF\ checks them using a global variable called \\{bad}. + +This is the first of many sections of \MF\ where global variables are +defined. + +\Y\P$\4\X13:Global variables\X\S$\6 +\4\\{bad}: \37\\{integer};\C{is some ``constant'' wrong?}\par +\As20, 25, 29, 31, 38, 42, 50, 54, 68, 71, 74, 91, 97, 129, 137, 144, 148, 159, +160, 161, 166, 178, 190, 196, 198, 200, 201, 225, 230, 250, 267, 279, 283, 298, +308, 309, 327, 371, 379, 389, 395, 403, 427, 430, 448, 455, 461, 464, 507, 552, +555, 557, 566, 569, 572, 579, 585, 592, 624, 628, 631, 633, 634, 659, 680, 699, +738, 752, 767, 768, 775, 782, 785, 791, 796, 813, 821, 954, 1077, 1084, 1087, +1096, 1119, 1125, 1130, 1149, 1152, 1162, 1183, 1188\ETs1203. +\U4.\fi + +\M14. Later on we will say `\ignorespaces \&{if} $\\{mem\_max}\G\\{max% +\_halfword}$ \&{then} $\\{bad}\K10$', +or something similar. (We can't do that until \\{max\_halfword} has been +defined.) + +\Y\P$\4\X14:Check the ``constant'' values for consistency\X\S$\6 +$\\{bad}\K0$;\6 +\&{if} $(\\{half\_error\_line}<30)\V(\\{half\_error\_line}>\\{error\_line}-15)$ +\1\&{then}\5 +$\\{bad}\K1$;\2\6 +\&{if} $\\{max\_print\_line}<60$ \1\&{then}\5 +$\\{bad}\K2$;\2\6 +\&{if} $\\{gf\_buf\_size}\mathbin{\&{mod}}8\I0$ \1\&{then}\5 +$\\{bad}\K3$;\2\6 +\&{if} $\\{mem\_min}+1100>\\{mem\_top}$ \1\&{then}\5 +$\\{bad}\K4$;\2\6 +\&{if} $\\{hash\_prime}>\\{hash\_size}$ \1\&{then}\5 +$\\{bad}\K5$;\2\6 +\&{if} $\\{header\_size}\mathbin{\&{mod}}4\I0$ \1\&{then}\5 +$\\{bad}\K6$;\2\6 +\&{if} $(\\{lig\_table\_size}<255)\V(\\{lig\_table\_size}>32510)$ \1\&{then}\5 +$\\{bad}\K7$;\2\par +\As154, 204, 214, 310, 553\ETs777. +\U1204.\fi + +\M15. Labels are given symbolic names by the following definitions, so that +occasional \&{goto} statements will be meaningful. We insert the label +`\\{exit}' just before the `\ignorespaces \&{end} \unskip' of a procedure in +which we have used the `\&{return}' statement defined below; the label +`\\{restart}' is occasionally used at the very beginning of a procedure; and +the label `\\{reswitch}' is occasionally used just prior to a \&{case} +statement in which some cases change the conditions and we wish to branch +to the newly applicable case. Loops that are set up with the \~ \&{loop} +construction defined below are commonly exited by going to `\\{done}' or to +`\\{found}' or to `\\{not\_found}', and they are sometimes repeated by going to +`\\{continue}'. If two or more parts of a subroutine start differently but +end up the same, the shared code may be gathered together at +`\\{common\_ending}'. + +Incidentally, this program never declares a label that isn't actually used, +because some fussy \PASCAL\ compilers will complain about redundant labels. + +\Y\P\D \37$\\{exit}=10$\C{go here to leave a procedure}\par +\P\D \37$\\{restart}=20$\C{go here to start a procedure again}\par +\P\D \37$\\{reswitch}=21$\C{go here to start a case statement again}\par +\P\D \37$\\{continue}=22$\C{go here to resume a loop}\par +\P\D \37$\\{done}=30$\C{go here to exit a loop}\par +\P\D \37$\\{done1}=31$\C{like \\{done}, when there is more than one loop}\par +\P\D \37$\\{done2}=32$\C{for exiting the second loop in a long block}\par +\P\D \37$\\{done3}=33$\C{for exiting the third loop in a very long block}\par +\P\D \37$\\{done4}=34$\C{for exiting the fourth loop in an extremely long +block}\par +\P\D \37$\\{done5}=35$\C{for exiting the fifth loop in an immense block}\par +\P\D \37$\\{done6}=36$\C{for exiting the sixth loop in a block}\par +\P\D \37$\\{found}=40$\C{go here when you've found it}\par +\P\D \37$\\{found1}=41$\C{like \\{found}, when there's more than one per +routine}\par +\P\D \37$\\{found2}=42$\C{like \\{found}, when there's more than two per +routine}\par +\P\D \37$\\{not\_found}=45$\C{go here when you've found nothing}\par +\P\D \37$\\{common\_ending}=50$\C{go here when you want to merge with another +branch}\par +\fi + +\M16. Here are some macros for common programming idioms. + +\Y\P\D \37$\\{incr}(\#)\S\#\K\#+1$\C{increase a variable by unity}\par +\P\D \37$\\{decr}(\#)\S\#\K\#-1$\C{decrease a variable by unity}\par +\P\D \37$\\{negate}(\#)\S\#\K-\#$\C{change the sign of a variable}\par +\P\D \37$\\{double}(\#)\S\#\K\#+\#$\C{multiply a variable by two}\par +\P\D \37$\\{loop}\S$\ \&{while} $\\{true}$ \1\&{do}\ \C{repeat over and over +until a \&{goto} happens}\par +\P\F \37$\\{loop}\S\\{xclause}$\C{\.{WEB}'s \~ \&{xclause} acts like `% +\ignorespaces \&{while} $\\{true}$ \&{do}\unskip'}\par +\P\D \37$\\{do\_nothing}\S$\C{empty statement}\par +\P\D \37$\\{return}\S$\1\5 +\&{goto} \37\\{exit}\C{terminate a procedure call}\2\par +\P\F \37$\\{return}\S\\{nil}$\C{\.{WEB} will henceforth say \&{return} instead +of \\{return}}\par +\fi + +\N17. \[2] The character set. +In order to make \MF\ 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 \MF\ only with respect to +the \&{char} and \&{ASCII} operations, and the comparison of strings. + +\fi + +\M18. Characters of text that have been converted to \MF's internal form +are said to be of type \\{ASCII\_code}, which is a subrange of the integers. + +\Y\P$\4\X18:Types in the outer block\X\S$\6 +$\\{ASCII\_code}=0\to255$;\C{eight-bit numbers}\par +\As24, 37, 101, 105, 106, 156, 186, 565, 571, 627\ETs1151. +\U4.\fi + +\M19. The original \PASCAL\ compiler was designed in the late 60s, when six-bit +character sets were common, so it did not make provision for lowercase +letters. Nowadays, of course, we need to deal with both capital and small +letters in a convenient way, especially in a program for font design; +so the present specification of \MF\ has been written under the assumption +that the \PASCAL\ compiler and run-time system permit the use of text files +with more than 64 distinguishable characters. More precisely, we assume that +the character set contains at least the letters and symbols associated +with ASCII codes \O{40} through \O{176}; all of these characters are now +available on most computer terminals. + +Since we are dealing with more characters than were present in the first +\PASCAL\ compilers, we have to decide what to call the associated data +type. Some \PASCAL s use the original name \\{char} for the +characters in text files, even though there now are more than 64 such +characters, while other \PASCAL s consider \\{char} to be a 64-element +subrange of a larger data type that has some other name. + +In order to accommodate this difference, we shall use the name \\{text\_char} +to stand for the data type of the characters that are converted to and +from \\{ASCII\_code} when they are input and output. We shall also assume +that \\{text\_char} consists of the elements $\\{chr}(\\{first\_text\_char})$ +through +$\\{chr}(\\{last\_text\_char})$, inclusive. The following definitions should be +adjusted if necessary. + +\Y\P\D \37$\\{text\_char}\S\\{char}$\C{the data type of characters in text +files}\par +\P\D \37$\\{first\_text\_char}=0$\C{ordinal number of the smallest element of % +\\{text\_char}}\par +\P\D \37$\\{last\_text\_char}=255$\C{ordinal number of the largest element of % +\\{text\_char}}\par +\Y\P$\4\X19:Local variables for initialization\X\S$\6 +\4\|i: \37\\{integer};\par +\A130. +\U4.\fi + +\M20. The \MF\ processor converts between ASCII code and +the user's external character set by means of arrays \\{xord} and \\{xchr} +that are analogous to \PASCAL's \\{ord} and \\{chr} functions. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{xord}: \37\&{array} $[\\{text\_char}]$ \1\&{of}\5 +\\{ASCII\_code};\C{specifies conversion of input characters}\2\6 +\4\\{xchr}: \37\&{array} $[\\{ASCII\_code}]$ \1\&{of}\5 +\\{text\_char};\C{specifies conversion of output characters}\2\par +\fi + +\M21. Since we are assuming that our \PASCAL\ system is able to read and +write the visible characters of standard ASCII (although not +necessarily using the ASCII codes to represent them), the following +assignment statements initialize the standard part of the \\{xchr} array +properly, without needing any system-dependent changes. On the other +hand, it is possible to implement \MF\ with less complete character +sets, and in such cases it will be necessary to change something here. + +\Y\P$\4\X21:Set initial values of key variables\X\S$\6 +$\\{xchr}[\O{40}]\K\.{\'\ \'}$;\5 +$\\{xchr}[\O{41}]\K\.{\'!\'}$;\5 +$\\{xchr}[\O{42}]\K\.{\'"\'}$;\5 +$\\{xchr}[\O{43}]\K\.{\'\#\'}$;\5 +$\\{xchr}[\O{44}]\K\.{\'\$\'}$;\5 +$\\{xchr}[\O{45}]\K\.{\'\%\'}$;\5 +$\\{xchr}[\O{46}]\K\.{\'\&\'}$;\5 +$\\{xchr}[\O{47}]\K\.{\'\'}\.{\'\'}$;\6 +$\\{xchr}[\O{50}]\K\.{\'(\'}$;\5 +$\\{xchr}[\O{51}]\K\.{\')\'}$;\5 +$\\{xchr}[\O{52}]\K\.{\'*\'}$;\5 +$\\{xchr}[\O{53}]\K\.{\'+\'}$;\5 +$\\{xchr}[\O{54}]\K\.{\',\'}$;\5 +$\\{xchr}[\O{55}]\K\.{\'-\'}$;\5 +$\\{xchr}[\O{56}]\K\.{\'.\'}$;\5 +$\\{xchr}[\O{57}]\K\.{\'/\'}$;\6 +$\\{xchr}[\O{60}]\K\.{\'0\'}$;\5 +$\\{xchr}[\O{61}]\K\.{\'1\'}$;\5 +$\\{xchr}[\O{62}]\K\.{\'2\'}$;\5 +$\\{xchr}[\O{63}]\K\.{\'3\'}$;\5 +$\\{xchr}[\O{64}]\K\.{\'4\'}$;\5 +$\\{xchr}[\O{65}]\K\.{\'5\'}$;\5 +$\\{xchr}[\O{66}]\K\.{\'6\'}$;\5 +$\\{xchr}[\O{67}]\K\.{\'7\'}$;\6 +$\\{xchr}[\O{70}]\K\.{\'8\'}$;\5 +$\\{xchr}[\O{71}]\K\.{\'9\'}$;\5 +$\\{xchr}[\O{72}]\K\.{\':\'}$;\5 +$\\{xchr}[\O{73}]\K\.{\';\'}$;\5 +$\\{xchr}[\O{74}]\K\.{\'<\'}$;\5 +$\\{xchr}[\O{75}]\K\.{\'=\'}$;\5 +$\\{xchr}[\O{76}]\K\.{\'>\'}$;\5 +$\\{xchr}[\O{77}]\K\.{\'?\'}$;\6 +$\\{xchr}[\O{100}]\K\.{\'@\'}$;\5 +$\\{xchr}[\O{101}]\K\.{\'A\'}$;\5 +$\\{xchr}[\O{102}]\K\.{\'B\'}$;\5 +$\\{xchr}[\O{103}]\K\.{\'C\'}$;\5 +$\\{xchr}[\O{104}]\K\.{\'D\'}$;\5 +$\\{xchr}[\O{105}]\K\.{\'E\'}$;\5 +$\\{xchr}[\O{106}]\K\.{\'F\'}$;\5 +$\\{xchr}[\O{107}]\K\.{\'G\'}$;\6 +$\\{xchr}[\O{110}]\K\.{\'H\'}$;\5 +$\\{xchr}[\O{111}]\K\.{\'I\'}$;\5 +$\\{xchr}[\O{112}]\K\.{\'J\'}$;\5 +$\\{xchr}[\O{113}]\K\.{\'K\'}$;\5 +$\\{xchr}[\O{114}]\K\.{\'L\'}$;\5 +$\\{xchr}[\O{115}]\K\.{\'M\'}$;\5 +$\\{xchr}[\O{116}]\K\.{\'N\'}$;\5 +$\\{xchr}[\O{117}]\K\.{\'O\'}$;\6 +$\\{xchr}[\O{120}]\K\.{\'P\'}$;\5 +$\\{xchr}[\O{121}]\K\.{\'Q\'}$;\5 +$\\{xchr}[\O{122}]\K\.{\'R\'}$;\5 +$\\{xchr}[\O{123}]\K\.{\'S\'}$;\5 +$\\{xchr}[\O{124}]\K\.{\'T\'}$;\5 +$\\{xchr}[\O{125}]\K\.{\'U\'}$;\5 +$\\{xchr}[\O{126}]\K\.{\'V\'}$;\5 +$\\{xchr}[\O{127}]\K\.{\'W\'}$;\6 +$\\{xchr}[\O{130}]\K\.{\'X\'}$;\5 +$\\{xchr}[\O{131}]\K\.{\'Y\'}$;\5 +$\\{xchr}[\O{132}]\K\.{\'Z\'}$;\5 +$\\{xchr}[\O{133}]\K\.{\'[\'}$;\5 +$\\{xchr}[\O{134}]\K\.{\'\\\'}$;\5 +$\\{xchr}[\O{135}]\K\.{\']\'}$;\5 +$\\{xchr}[\O{136}]\K\.{\'\^\'}$;\5 +$\\{xchr}[\O{137}]\K\.{\'\_\'}$;\6 +$\\{xchr}[\O{140}]\K\.{\'\`\'}$;\5 +$\\{xchr}[\O{141}]\K\.{\'a\'}$;\5 +$\\{xchr}[\O{142}]\K\.{\'b\'}$;\5 +$\\{xchr}[\O{143}]\K\.{\'c\'}$;\5 +$\\{xchr}[\O{144}]\K\.{\'d\'}$;\5 +$\\{xchr}[\O{145}]\K\.{\'e\'}$;\5 +$\\{xchr}[\O{146}]\K\.{\'f\'}$;\5 +$\\{xchr}[\O{147}]\K\.{\'g\'}$;\6 +$\\{xchr}[\O{150}]\K\.{\'h\'}$;\5 +$\\{xchr}[\O{151}]\K\.{\'i\'}$;\5 +$\\{xchr}[\O{152}]\K\.{\'j\'}$;\5 +$\\{xchr}[\O{153}]\K\.{\'k\'}$;\5 +$\\{xchr}[\O{154}]\K\.{\'l\'}$;\5 +$\\{xchr}[\O{155}]\K\.{\'m\'}$;\5 +$\\{xchr}[\O{156}]\K\.{\'n\'}$;\5 +$\\{xchr}[\O{157}]\K\.{\'o\'}$;\6 +$\\{xchr}[\O{160}]\K\.{\'p\'}$;\5 +$\\{xchr}[\O{161}]\K\.{\'q\'}$;\5 +$\\{xchr}[\O{162}]\K\.{\'r\'}$;\5 +$\\{xchr}[\O{163}]\K\.{\'s\'}$;\5 +$\\{xchr}[\O{164}]\K\.{\'t\'}$;\5 +$\\{xchr}[\O{165}]\K\.{\'u\'}$;\5 +$\\{xchr}[\O{166}]\K\.{\'v\'}$;\5 +$\\{xchr}[\O{167}]\K\.{\'w\'}$;\6 +$\\{xchr}[\O{170}]\K\.{\'x\'}$;\5 +$\\{xchr}[\O{171}]\K\.{\'y\'}$;\5 +$\\{xchr}[\O{172}]\K\.{\'z\'}$;\5 +$\\{xchr}[\O{173}]\K\.{\'\{\'}$;\5 +$\\{xchr}[\O{174}]\K\.{\'|\'}$;\5 +$\\{xchr}[\O{175}]\K\.{\'\}\'}$;\5 +$\\{xchr}[\O{176}]\K\.{\'\~\'}$;\par +\As22, 23, 69, 72, 75, 92, 98, 131, 138, 179, 191, 199, 202, 231, 251, 396, +428, 449, 456, 462, 570, 573, 593, 739, 753, 776, 797, 822, 1078, 1085, 1097, +1150, 1153\ETs1184. +\U4.\fi + +\M22. 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. If \MF\ is being used +on a garden-variety \PASCAL\ for which only standard ASCII +codes will appear in the input and output files, it doesn't really matter +what codes are specified in $\\{xchr}[0\to\O{37}]$, but the safest policy is to +blank everything out by using the code shown below. + +However, other settings of \\{xchr} will make \MF\ more friendly on +computers that have an extended character set, so that users can type things +like `\.^^Z' instead of `\.{<>}'. +People with extended character sets can +assign codes arbitrarily, giving an \\{xchr} equivalent to whatever +characters the users of \MF\ are allowed to have in their input files. +Appropriate changes to \MF's \\{char\_class} table should then be made. +(Unlike \TeX, each installation of \MF\ has a fixed assignment of category +codes, called the \\{char\_class}.) Such changes make portability of programs +more difficult, so they should be introduced cautiously if at all. + +\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +\&{for} $\|i\K0\mathrel{\&{to}}\O{37}$ \1\&{do}\5 +$\\{xchr}[\|i]\K\.{\'\ \'}$;\2\6 +\&{for} $\|i\K\O{177}\mathrel{\&{to}}\O{377}$ \1\&{do}\5 +$\\{xchr}[\|i]\K\.{\'\ \'}$;\2\par +\fi + +\M23. The following system-independent code makes the \\{xord} array contain a +suitable inverse to the information in \\{xchr}. Note that if $\\{xchr}[\|i]=% +\\{xchr}[\|j]$ +where $\|i<\|j<\O{177}$, the value of $\\{xord}[\\{xchr}[\|i]]$ will turn out +to be +\|j or more; hence, standard ASCII code numbers will be used instead of +codes below \O{40} in case there is a coincidence. + +\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +\&{for} $\|i\K\\{first\_text\_char}\mathrel{\&{to}}\\{last\_text\_char}$ \1% +\&{do}\5 +$\\{xord}[\\{chr}(\|i)]\K\O{177}$;\2\6 +\&{for} $\|i\K\O{200}\mathrel{\&{to}}\O{377}$ \1\&{do}\5 +$\\{xord}[\\{xchr}[\|i]]\K\|i$;\2\6 +\&{for} $\|i\K0\mathrel{\&{to}}\O{176}$ \1\&{do}\5 +$\\{xord}[\\{xchr}[\|i]]\K\|i$;\2\par +\fi + +\N24. \[3] Input and output. +The bane of portability is the fact that different operating systems treat +input and output quite differently, perhaps because computer scientists +have not given sufficient attention to this problem. People have felt somehow +that input and output are not part of ``real'' programming. Well, it is true +that some kinds of programming are more fun than others. With existing +input/output conventions being so diverse and so messy, the only sources of +joy in such parts of the code are the rare occasions when one can find a +way to make the program a little less bad than it might have been. We have +two choices, either to attack I/O now and get it over with, or to postpone +I/O until near the end. Neither prospect is very attractive, so let's +get it over with. + +The basic operations we need to do are (1)~inputting and outputting of +text, to or from a file or the user's terminal; (2)~inputting and +outputting of eight-bit bytes, to or from a file; (3)~instructing the +operating system to initiate (``open'') or to terminate (``close'') input or +output from a specified file; (4)~testing whether the end of an input +file has been reached; (5)~display of bits on the user's screen. +The bit-display operation will be discussed in a later section; we shall +deal here only with more traditional kinds of I/O. + +\MF\ needs to deal with two kinds of files. +We shall use the term \\{alpha\_file} for a file that contains textual data, +and the term \\{byte\_file} for a file that contains eight-bit binary +information. +These two types turn out to be the same on many computers, but +sometimes there is a significant distinction, so we shall be careful to +distinguish between them. Standard protocols for transferring +such files from computer to computer, via high-speed networks, are +now becoming available to more and more communities of users. + +The program actually makes use also of a third kind of file, called a +\\{word\_file}, when dumping and reloading base information for its own +initialization. We shall define a word file later; but it will be possible +for us to specify simple operations on word files before they are defined. + +\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6 +$\\{eight\_bits}=0\to255$;\C{unsigned one-byte quantity}\6 +$\\{alpha\_file}=$\1\5 +\&{packed} \37\&{file} \1\&{of}\5 +\\{text\_char};\C{files that contain textual data}\2\2\6 +$\\{byte\_file}=$\1\5 +\&{packed} \37\&{file} \1\&{of}\5 +\\{eight\_bits};\C{files that contain binary data}\2\2\par +\fi + +\M25. 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 +\MF; 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 \MF\ can open a file whose external name is specified by +\\{name\_of\_file}. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{name\_of\_file}: \37\&{packed} \37\&{array} $[1\to\\{file\_name\_size}]$ % +\1\&{of}\5 +\\{char};\2\6 +\C{on some systems this may be a \&{record} variable}\6 +\4\\{name\_length}: \37$0\to\\{file\_name\_size}$;\6 +\C{this many characters are actually relevant in \\{name\_of\_file} (the rest +are blank)}\par +\fi + +\M26. The \ph\ compiler with which the present version of \MF\ 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 `\ignorespaces\&{packed} \&{array} +$[\hbox{\<\\{any}>}]$ \&{of} \\{text\_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)\I0$ after an unsuccessful \\{reset} or \\{rewrite}. This +allows +\MF\ to undertake appropriate corrective action. + +\MF's file-opening procedures return \\{false} if no file identified by +\\{name\_of\_file} could be opened. + +\Y\P\D \37$\\{reset\_OK}(\#)\S\\{erstat}(\#)=0$\par +\P\D \37$\\{rewrite\_OK}(\#)\S\\{erstat}(\#)=0$\par +\Y\P\4\&{function}\1\ \37$\\{a\_open\_in}(\mathop{\&{var}}\|f:\\{alpha% +\_file})$: \37\\{boolean};\C{open a text file for input}\2\6 +\&{begin} \37$\\{reset}(\|f,\39\\{name\_of\_file},\39\.{\'/O\'})$;\5 +$\\{a\_open\_in}\K\\{reset\_OK}(\|f)$;\6 +\&{end};\7 +\4\&{function}\1\ \37$\\{a\_open\_out}(\mathop{\&{var}}\|f:\\{alpha\_file})$: % +\37\\{boolean};\C{open a text file for output}\2\6 +\&{begin} \37$\\{rewrite}(\|f,\39\\{name\_of\_file},\39\.{\'/O\'})$;\5 +$\\{a\_open\_out}\K\\{rewrite\_OK}(\|f)$;\6 +\&{end};\7 +\4\&{function}\1\ \37$\\{b\_open\_out}(\mathop{\&{var}}\|f:\\{byte\_file})$: % +\37\\{boolean};\C{open a binary file for output}\2\6 +\&{begin} \37$\\{rewrite}(\|f,\39\\{name\_of\_file},\39\.{\'/O\'})$;\5 +$\\{b\_open\_out}\K\\{rewrite\_OK}(\|f)$;\6 +\&{end};\7 +\4\&{function}\1\ \37$\\{w\_open\_in}(\mathop{\&{var}}\|f:\\{word\_file})$: % +\37\\{boolean};\C{open a word file for input}\2\6 +\&{begin} \37$\\{reset}(\|f,\39\\{name\_of\_file},\39\.{\'/O\'})$;\5 +$\\{w\_open\_in}\K\\{reset\_OK}(\|f)$;\6 +\&{end};\7 +\4\&{function}\1\ \37$\\{w\_open\_out}(\mathop{\&{var}}\|f:\\{word\_file})$: % +\37\\{boolean};\C{open a word file for output}\2\6 +\&{begin} \37$\\{rewrite}(\|f,\39\\{name\_of\_file},\39\.{\'/O\'})$;\5 +$\\{w\_open\_out}\K\\{rewrite\_OK}(\|f)$;\6 +\&{end};\par +\fi + +\M27. 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. + +\Y\P\4\&{procedure}\1\ \37$\\{a\_close}(\mathop{\&{var}}\|f:\\{alpha\_file})$;% +\C{close a text file}\2\6 +\&{begin} \37$\\{close}(\|f)$;\6 +\&{end};\7 +\4\&{procedure}\1\ \37$\\{b\_close}(\mathop{\&{var}}\|f:\\{byte\_file})$;% +\C{close a binary file}\2\6 +\&{begin} \37$\\{close}(\|f)$;\6 +\&{end};\7 +\4\&{procedure}\1\ \37$\\{w\_close}(\mathop{\&{var}}\|f:\\{word\_file})$;% +\C{close a word file}\2\6 +\&{begin} \37$\\{close}(\|f)$;\6 +\&{end};\par +\fi + +\M28. 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. +\MF's conventions should be efficient, and they should +blend nicely with the user's operating environment. + +\fi + +\M29. Input from text files is read one line at a time, using a routine called +\\{input\_ln}. This function is defined in terms of global variables called +\\{buffer}, \\{first}, and \\{last} that will be described in detail later; for +now, it suffices for us to know that \\{buffer} is an array of \\{ASCII\_code} +values, and that \\{first} and \\{last} are indices into this array +representing the beginning and ending of a line of text. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{buffer}: \37\&{array} $[0\to\\{buf\_size}]$ \1\&{of}\5 +\\{ASCII\_code};\C{lines of characters being read}\2\6 +\4\\{first}: \37$0\to\\{buf\_size}$;\C{the first unused position in \\{buffer}}% +\6 +\4\\{last}: \37$0\to\\{buf\_size}$;\C{end of the line just input to \\{buffer}}% +\6 +\4\\{max\_buf\_stack}: \37$0\to\\{buf\_size}$;\C{largest index used in % +\\{buffer}}\par +\fi + +\M30. The \\{input\_ln} function brings the next line of input from the +specified +field into available positions of the buffer array and returns the value +\\{true}, unless the file has already been entirely read, in which case it +returns \\{false} and sets $\\{last}\K\\{first}$. In general, the \\{ASCII% +\_code} +numbers that represent the next line of the file are input into +$\\{buffer}[\\{first}]$, $\\{buffer}[\\{first}+1]$, \dots, $\\{buffer}[% +\\{last}-1]$; and the +global variable \\{last} is set equal to \\{first} plus the length of the +line. Trailing blanks are removed from the line; thus, either $\\{last}=% +\\{first}$ +(in which case the line was entirely blank) or $\\{buffer}[\\{last}-1]\I\.{"\ +"}$. + +An overflow error is given, however, if the normal actions of \\{input\_ln} +would make $\\{last}\G\\{buf\_size}$; this is done so that other parts of \MF\ +can safely look at the contents of $\\{buffer}[\\{last}+1]$ without +overstepping +the bounds of the \\{buffer} array. Upon entry to \\{input\_ln}, the condition +$\\{first}<\\{buf\_size}$ will always hold, so that there is always room for an +``empty'' line. + +The variable \\{max\_buf\_stack}, which is used to keep track of how large +the \\{buf\_size} parameter must be to accommodate the present job, is +also kept up to date by \\{input\_ln}. + +If the \\{bypass\_eoln} parameter is \\{true}, \\{input\_ln} will do a \\{get} +before looking at the first character of the line; this skips over +an \\{eoln} that was in $\|f\^$. The procedure does not do a \\{get} when it +reaches the end of the line; therefore it can be used to acquire input +from the user's terminal as well as from ordinary text files. + +Standard \PASCAL\ says that a file should have \\{eoln} immediately +before \\{eof}, but \MF\ needs only a weaker restriction: If \\{eof} +occurs in the middle of a line, the system function \\{eoln} should return +a \\{true} result (even though $\|f\^$ will be undefined). + +\Y\P\4\&{function}\1\ \37$\\{input\_ln}(\mathop{\&{var}}\|f:\\{alpha\_file};\,% +\35\\{bypass\_eoln}:\\{boolean})$: \37\\{boolean};\C{inputs the next line or +returns \\{false}}\6 +\4\&{var} \37\\{last\_nonblank}: \37$0\to\\{buf\_size}$;\C{\\{last} with +trailing blanks removed}\2\6 +\&{begin} \37\&{if} $\\{bypass\_eoln}$ \1\&{then}\6 +\&{if} $\R\\{eof}(\|f)$ \1\&{then}\5 +$\\{get}(\|f)$;\C{input the first character of the line into $\|f\^$}\2\2\6 +$\\{last}\K\\{first}$;\C{cf.\ Matthew 19\thinspace:\thinspace30}\6 +\&{if} $\\{eof}(\|f)$ \1\&{then}\5 +$\\{input\_ln}\K\\{false}$\6 +\4\&{else} \&{begin} \37$\\{last\_nonblank}\K\\{first}$;\6 +\&{while} $\R\\{eoln}(\|f)$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{last}\G\\{max\_buf\_stack}$ \1\&{then}\6 +\&{begin} \37$\\{max\_buf\_stack}\K\\{last}+1$;\6 +\&{if} $\\{max\_buf\_stack}=\\{buf\_size}$ \1\&{then}\5 +\X34:Report overflow of the input buffer, and abort\X;\2\6 +\&{end};\2\6 +$\\{buffer}[\\{last}]\K\\{xord}[\|f\^]$;\5 +$\\{get}(\|f)$;\5 +$\\{incr}(\\{last})$;\6 +\&{if} $\\{buffer}[\\{last}-1]\I\.{"\ "}$ \1\&{then}\5 +$\\{last\_nonblank}\K\\{last}$;\2\6 +\&{end};\2\6 +$\\{last}\K\\{last\_nonblank}$;\5 +$\\{input\_ln}\K\\{true}$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M31. The user's terminal acts essentially like other files of text, except +that it is used both for input and for output. When the terminal is +considered an input file, the file variable is called \\{term\_in}, and when it +is considered an output file the file variable is \\{term\_out}. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{term\_in}: \37\\{alpha\_file};\C{the terminal as an input file}\6 +\4\\{term\_out}: \37\\{alpha\_file};\C{the terminal as an output file}\par +\fi + +\M32. Here is how to open the terminal files +in \ph. The `\.{/I}' switch suppresses the first \\{get}. + +\Y\P\D \37$\\{t\_open\_in}\S\\{reset}(\\{term\_in},\39\.{\'TTY:\'},\39\.{\'/O/I% +\'})$\C{open the terminal for text input}\par +\P\D \37$\\{t\_open\_out}\S\\{rewrite}(\\{term\_out},\39\.{\'TTY:\'},\39\.{\'/O% +\'})$\C{open the terminal for text output}\par +\fi + +\M33. 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\P\D \37$\\{update\_terminal}\S\\{break}(\\{term\_out})$\C{empty the terminal +output buffer}\par +\P\D \37$\\{clear\_terminal}\S\\{break\_in}(\\{term\_in},\39\\{true})$\C{clear +the terminal input buffer}\par +\P\D \37$\\{wake\_up\_terminal}\S\\{do\_nothing}$\C{cancel the user's +cancellation of output}\par +\fi + +\M34. We need a special routine to read the first line of \MF\ 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 cmr10}' on the first +line, or if some macro invoked by that line does such an \.{input}, +the transcript file will be named `\.{cmr10.log}'; but if no \.{input} +commands are performed during the first line of terminal input, the transcript +file will acquire its default name `\.{mfput.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 \MF\ differently from a run-of-the-mill \PASCAL\ object +program. It's nice to let the user start running a \MF\ job by typing +a command line like `\.{MF cmr10}'; in such a case, \MF\ will operate +as if the first line of input were `\.{cmr10}', i.e., the first line will +consist of the remainder of the command line, after the part that invoked \MF. + +The first line is special also because it may be read before \MF\ has +input a base 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} , the +statement `\&{goto} \\{final\_end}' should be replaced by something that +quietly terminates the program.) + +\Y\P$\4\X34:Report overflow of the input buffer, and abort\X\S$\6 +\&{if} $\\{base\_ident}=0$ \1\&{then}\6 +\&{begin} \37$\\{write\_ln}(\\{term\_out},\39\.{\'Buffer\ size\ exceeded!\'})$;% +\5 +\&{goto} \37\\{final\_end};\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{cur\_input}.\\{loc\_field}\K\\{first}$;\5 +$\\{cur\_input}.\\{limit\_field}\K\\{last}-1$;\5 +$\\{overflow}(\.{"buffer\ size"},\39\\{buf\_size})$;\6 +\&{end}\2\par +\U30.\fi + +\M35. 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 \MF\ is in $\\{buffer}[\\{loc}]$. This +character should not be blank, and we should have $\\{loc}<\\{last}$. + +\yskip\noindent(It may be necessary to prompt the user several times +before a non-blank line comes in. The prompt is `\.{**}' instead of the +later `\.*' because the meaning is slightly different: `\.{input}' need +not be typed immediately after~`\.{**}'.) + +\Y\P\D \37$\\{loc}\S\\{cur\_input}.\\{loc\_field}$\C{location of first unread +character in \\{buffer}}\par +\fi + +\M36. 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\P\4\&{function}\1\ \37\\{init\_terminal}: \37\\{boolean};\C{gets the +terminal input started}\6 +\4\&{label} \37\\{exit};\2\6 +\&{begin} \37\\{t\_open\_in};\6 +\~ \1\&{loop}\ \&{begin} \37\\{wake\_up\_terminal};\5 +$\\{write}(\\{term\_out},\39\.{\'**\'})$;\5 +\\{update\_terminal};\6 +\&{if} $\R\\{input\_ln}(\\{term\_in},\39\\{true})$ \1\&{then}\C{this shouldn't +happen}\6 +\&{begin} \37$\\{write\_ln}(\\{term\_out})$;\5 +$\\{write}(\\{term\_out},\39\.{\'!\ End\ of\ file\ on\ the\ terminal...\ why?% +\'})$;\5 +$\\{init\_terminal}\K\\{false}$;\5 +\&{return};\6 +\&{end};\2\6 +$\\{loc}\K\\{first}$;\6 +\&{while} $(\\{loc}<\\{last})\W(\\{buffer}[\\{loc}]=\.{"\ "})$ \1\&{do}\5 +$\\{incr}(\\{loc})$;\2\6 +\&{if} $\\{loc}<\\{last}$ \1\&{then}\6 +\&{begin} \37$\\{init\_terminal}\K\\{true}$;\5 +\&{return};\C{return unless the line was all blank}\6 +\&{end};\2\6 +$\\{write\_ln}(\\{term\_out},\39\.{\'Please\ type\ the\ name\ of\ your\ input\ +file.\'})$;\6 +\&{end};\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\N37. \[4] String handling. +Symbolic token names and diagnostic messages are variable-length strings +of eight-bit characters. Since \PASCAL\ does not have a well-developed string +mechanism, \MF\ does all of its string processing by homegrown methods. + +Elaborate facilities for dynamic strings are not needed, so all of the +necessary operations can be handled with a simple data structure. +The array \\{str\_pool} contains all of the (eight-bit) ASCII codes in all +of the strings, and the array \\{str\_start} contains indices of the starting +points of each string. Strings are referred to by integer numbers, so that +string number \|s comprises the characters $\\{str\_pool}[\|j]$ for +$\\{str\_start}[\|s]\L\|j<\\{str\_start}[\|s+1]$. Additional integer variables +\\{pool\_ptr} and \\{str\_ptr} indicate the number of entries used so far +in \\{str\_pool} and \\{str\_start}, respectively; locations +$\\{str\_pool}[\\{pool\_ptr}]$ and $\\{str\_start}[\\{str\_ptr}]$ are +ready for the next string to be allocated. + +String numbers 0 to 255 are reserved for strings that correspond to single +ASCII characters. This is in accordance with the conventions of \.{WEB}, +which converts single-character strings into the ASCII code number of the +single character involved, while it converts other strings into integers +and builds a string pool file. Thus, when the string constant \.{"."} appears +in the program below, \.{WEB} converts it into the integer 46, which is the +ASCII code for a period, while \.{WEB} will convert a string like \.{"hello"} +into some integer greater than~255. String number 46 will presumably be the +single character `\..'\thinspace; but some ASCII codes have no standard visible +representation, and \MF\ may need to be able to print an arbitrary +ASCII character, so the first 256 strings are used to specify exactly what +should be printed for each of the 256 possibilities. + +Elements of the \\{str\_pool} array must be ASCII codes that can actually be +printed; i.e., they must have an \\{xchr} equivalent in the local +character set. (This restriction applies only to preloaded strings, +not to those generated dynamically by the user.) + +Some \PASCAL\ compilers won't pack integers into a single byte unless the +integers lie in the range $-128\to127$. To accommodate such systems +we access the string pool only via macros that can easily be redefined. + +\Y\P\D \37$\\{si}(\#)\S\#$\C{convert from \\{ASCII\_code} to \\{packed\_ASCII% +\_code}}\par +\P\D \37$\\{so}(\#)\S\#$\C{convert from \\{packed\_ASCII\_code} to \\{ASCII% +\_code}}\par +\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6 +$\\{pool\_pointer}=0\to\\{pool\_size}$;\C{for variables that point into \\{str% +\_pool}}\6 +$\\{str\_number}=0\to\\{max\_strings}$;\C{for variables that point into \\{str% +\_start}}\6 +$\\{packed\_ASCII\_code}=0\to255$;\C{elements of \\{str\_pool} array}\par +\fi + +\M38. \P$\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{str\_pool}: \37\&{packed} \37\&{array} $[\\{pool\_pointer}]$ \1\&{of}\5 +\\{packed\_ASCII\_code};\C{the characters}\2\6 +\4\\{str\_start}: \37\&{array} $[\\{str\_number}]$ \1\&{of}\5 +\\{pool\_pointer};\C{the starting pointers}\2\6 +\4\\{pool\_ptr}: \37\\{pool\_pointer};\C{first unused position in \\{str% +\_pool}}\6 +\4\\{str\_ptr}: \37\\{str\_number};\C{number of the current string being +created}\6 +\4\\{init\_pool\_ptr}: \37\\{pool\_pointer};\C{the starting value of \\{pool% +\_ptr}}\6 +\4\\{init\_str\_ptr}: \37\\{str\_number};\C{the starting value of \\{str\_ptr}}% +\6 +\4\\{max\_pool\_ptr}: \37\\{pool\_pointer};\C{the maximum so far of \\{pool% +\_ptr}}\6 +\4\\{max\_str\_ptr}: \37\\{str\_number};\C{the maximum so far of \\{str\_ptr}}% +\par +\fi + +\M39. Several of the elementary string operations are performed using \.{WEB} +macros instead of \PASCAL\ procedures, because many of the +operations are done quite frequently and we want to avoid the +overhead of procedure calls. For example, here is +a simple macro that computes the length of a string. + +\Y\P\D \37$\\{length}(\#)\S(\\{str\_start}[\#+1]-\\{str\_start}[\#])$\C{the +number of characters in string number \#}\par +\fi + +\M40. The length of the current string is called \\{cur\_length}: + +\Y\P\D \37$\\{cur\_length}\S(\\{pool\_ptr}-\\{str\_start}[\\{str\_ptr}])$\par +\fi + +\M41. 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. + +To test if there is room to append \|l more characters to \\{str\_pool}, +we shall write $\\{str\_room}(\|l)$, which aborts \MF\ and gives an +apologetic error message if there isn't enough room. + +\Y\P\D \37$\\{append\_char}(\#)\S$\C{put \\{ASCII\_code} \# at the end of % +\\{str\_pool}}\6 +\&{begin} \37$\\{str\_pool}[\\{pool\_ptr}]\K\\{si}(\#)$;\5 +$\\{incr}(\\{pool\_ptr})$;\6 +\&{end}\par +\P\D \37$\\{str\_room}(\#)\S$\C{make sure that the pool hasn't overflowed}\6 +\&{begin} \37\&{if} $\\{pool\_ptr}+\#>\\{max\_pool\_ptr}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{pool\_ptr}+\#>\\{pool\_size}$ \1\&{then}\5 +$\\{overflow}(\.{"pool\ size"},\39\\{pool\_size}-\\{init\_pool\_ptr})$;\2\6 +$\\{max\_pool\_ptr}\K\\{pool\_ptr}+\#$;\6 +\&{end};\2\6 +\&{end}\par +\fi + +\M42. \MF's string expressions are implemented in a brute-force way: Every +new string or substring that is needed is simply copied into the string pool. + +Such a scheme can be justified because string expressions aren't a big +deal in \MF\ applications; strings rarely need to be saved from one +statement to the next. But it would waste space needlessly if we didn't +try to reclaim the space of strings that are going to be used only once. + +Therefore a simple reference count mechanism is provided: If there are +no references to a certain string from elsewhere in the program, and +if there are no references to any strings created subsequent to it, +then the string space will be reclaimed. + +The number of references to string number \|s will be $\\{str\_ref}[\|s]$. The +special value $\\{str\_ref}[\|s]=\\{max\_str\_ref}=127$ is used to denote an +unknown +positive number of references; such strings will never be recycled. If +a string is ever referred to more than 126 times, simultaneously, we +put it in this category. Hence a single byte suffices to store each \\{str% +\_ref}. + +\Y\P\D \37$\\{max\_str\_ref}=127$\C{``infinite'' number of references}\par +\P\D \37$\\{add\_str\_ref}(\#)\S$\1\6 +\&{begin} \37\&{if} $\\{str\_ref}[\#]<\\{max\_str\_ref}$ \1\&{then}\5 +$\\{incr}(\\{str\_ref}[\#])$;\2\6 +\&{end}\2\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{str\_ref}: \37\&{array} $[\\{str\_number}]$ \1\&{of}\5 +$0\to\\{max\_str\_ref}$;\2\par +\fi + +\M43. Here's what we do when a string reference disappears: + +\Y\P\D \37$\\{delete\_str\_ref}(\#)\S$\1\6 +\&{begin} \37\&{if} $\\{str\_ref}[\#]<\\{max\_str\_ref}$ \1\&{then}\6 +\&{if} $\\{str\_ref}[\#]>1$ \1\&{then}\5 +$\\{decr}(\\{str\_ref}[\#])$\ \&{else} $\\{flush\_string}(\#)$;\2\2\6 +\&{end}\2\par +\Y\P$\4\X43:Declare the procedure called \\{flush\_string}\X\S$\6 +\4\&{procedure}\1\ \37$\\{flush\_string}(\|s:\\{str\_number})$;\2\6 +\&{begin} \37\&{if} $\|s<\\{str\_ptr}-1$ \1\&{then}\5 +$\\{str\_ref}[\|s]\K0$\6 +\4\&{else} \1\&{repeat} \37$\\{decr}(\\{str\_ptr})$;\6 +\4\&{until}\5 +$\\{str\_ref}[\\{str\_ptr}-1]\I0$;\2\2\6 +$\\{pool\_ptr}\K\\{str\_start}[\\{str\_ptr}]$;\6 +\&{end};\par +\U73.\fi + +\M44. Once a sequence of characters has been appended to \\{str\_pool}, it +officially becomes a string when the function \\{make\_string} is called. +This function returns the identification number of the new string as its +value. + +\Y\P\4\&{function}\1\ \37\\{make\_string}: \37\\{str\_number};\C{current +string enters the pool}\2\6 +\&{begin} \37\&{if} $\\{str\_ptr}=\\{max\_str\_ptr}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{str\_ptr}=\\{max\_strings}$ \1\&{then}\5 +$\\{overflow}(\.{"number\ of\ strings"},\39\\{max\_strings}-\\{init\_str% +\_ptr})$;\2\6 +$\\{incr}(\\{max\_str\_ptr})$;\6 +\&{end};\2\6 +$\\{str\_ref}[\\{str\_ptr}]\K1$;\5 +$\\{incr}(\\{str\_ptr})$;\5 +$\\{str\_start}[\\{str\_ptr}]\K\\{pool\_ptr}$;\5 +$\\{make\_string}\K\\{str\_ptr}-1$;\6 +\&{end};\par +\fi + +\M45. 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. + +\Y\P\4\&{function}\1\ \37$\\{str\_eq\_buf}(\|s:\\{str\_number};\,\35\|k:% +\\{integer})$: \37\\{boolean};\C{test equality of strings}\6 +\4\&{label} \37\\{not\_found};\C{loop exit}\6 +\4\&{var} \37\|j: \37\\{pool\_pointer};\C{running index}\6 +\\{result}: \37\\{boolean};\C{result of comparison}\2\6 +\&{begin} \37$\|j\K\\{str\_start}[\|s]$;\6 +\&{while} $\|j<\\{str\_start}[\|s+1]$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{so}(\\{str\_pool}[\|j])\I\\{buffer}[\|k]$ \1\&{then}\6 +\&{begin} \37$\\{result}\K\\{false}$;\5 +\&{goto} \37\\{not\_found};\6 +\&{end};\2\6 +$\\{incr}(\|j)$;\5 +$\\{incr}(\|k)$;\6 +\&{end};\2\6 +$\\{result}\K\\{true}$;\6 +\4\\{not\_found}: \37$\\{str\_eq\_buf}\K\\{result}$;\6 +\&{end};\par +\fi + +\M46. 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. If the first string +is lexicographically greater than, less than, or equal to the second, +the result is respectively positive, negative, or zero. + +\Y\P\4\&{function}\1\ \37$\\{str\_vs\_str}(\|s,\39\|t:\\{str\_number})$: \37% +\\{integer};\C{test equality of strings}\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37$\|j,\39\|k$: \37\\{pool\_pointer};\C{running indices}\6 +$\\{ls},\39\\{lt}$: \37\\{integer};\C{lengths}\6 +\|l: \37\\{integer};\C{length remaining to test}\2\6 +\&{begin} \37$\\{ls}\K\\{length}(\|s)$;\5 +$\\{lt}\K\\{length}(\|t)$;\6 +\&{if} $\\{ls}\L\\{lt}$ \1\&{then}\5 +$\|l\K\\{ls}$\ \&{else} $\|l\K\\{lt}$;\2\6 +$\|j\K\\{str\_start}[\|s]$;\5 +$\|k\K\\{str\_start}[\|t]$;\6 +\&{while} $\|l>0$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{str\_pool}[\|j]\I\\{str\_pool}[\|k]$ \1\&{then}\6 +\&{begin} \37$\\{str\_vs\_str}\K\\{str\_pool}[\|j]-\\{str\_pool}[\|k]$;\5 +\&{return};\6 +\&{end};\2\6 +$\\{incr}(\|j)$;\5 +$\\{incr}(\|k)$;\5 +$\\{decr}(\|l)$;\6 +\&{end};\2\6 +$\\{str\_vs\_str}\K\\{ls}-\\{lt}$;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M47. The initial values of \\{str\_pool}, \\{str\_start}, \\{pool\_ptr}, +and \\{str\_ptr} are computed by the \.{INIMF} program, based in part +on the information that \.{WEB} has output while processing \MF. + +\Y\P\&{init} \37\&{function}\1\ \37\\{get\_strings\_started}: \37\\{boolean};% +\C{initializes the string pool, but returns \\{false} if something goes +wrong}\6 +\4\&{label} \37$\\{done},\39\\{exit}$;\6 +\4\&{var} \37$\|k,\39\|l$: \37$0\to255$;\C{small indices or counters}\6 +$\|m,\39\|n$: \37\\{text\_char};\C{characters input from \\{pool\_file}}\6 +\|g: \37\\{str\_number};\C{garbage}\6 +\|a: \37\\{integer};\C{accumulator for check sum}\6 +\|c: \37\\{boolean};\C{check sum has been checked}\2\6 +\&{begin} \37$\\{pool\_ptr}\K0$;\5 +$\\{str\_ptr}\K0$;\5 +$\\{max\_pool\_ptr}\K0$;\5 +$\\{max\_str\_ptr}\K0$;\5 +$\\{str\_start}[0]\K0$;\5 +\X48:Make the first 256 strings\X;\6 +\X51:Read the other strings from the \.{MF.POOL} file and return \\{true}, or +give an error message and return \\{false}\X;\6 +\4\\{exit}: \37\&{end};\6 +\&{tini}\par +\fi + +\M48. \P\D \37$\\{app\_lc\_hex}(\#)\S\|l\K\#$;\6 +\&{if} $\|l<10$ \1\&{then}\5 +$\\{append\_char}(\|l+\.{"0"})$\ \&{else} $\\{append\_char}(\|l-10+\.{"a"})$\2% +\par +\Y\P$\4\X48:Make the first 256 strings\X\S$\6 +\&{for} $\|k\K0\mathrel{\&{to}}255$ \1\&{do}\6 +\&{begin} \37\&{if} $(\X49:Character \|k cannot be printed\X)$ \1\&{then}\6 +\&{begin} \37$\\{append\_char}(\.{"\^"})$;\5 +$\\{append\_char}(\.{"\^"})$;\6 +\&{if} $\|k<\O{100}$ \1\&{then}\5 +$\\{append\_char}(\|k+\O{100})$\6 +\4\&{else} \&{if} $\|k<\O{200}$ \1\&{then}\5 +$\\{append\_char}(\|k-\O{100})$\6 +\4\&{else} \&{begin} \37$\\{app\_lc\_hex}(\|k\mathbin{\&{div}}16)$;\5 +$\\{app\_lc\_hex}(\|k\mathbin{\&{mod}}16)$;\6 +\&{end};\2\2\6 +\&{end}\6 +\4\&{else} $\\{append\_char}(\|k)$;\2\6 +$\|g\K\\{make\_string}$;\5 +$\\{str\_ref}[\|g]\K\\{max\_str\_ref}$;\6 +\&{end}\2\par +\U47.\fi + +\M49. The first 128 strings will contain 95 standard ASCII characters, and the +other 33 characters will be printed in three-symbol form like `\.{\^\^A}' +unless a system-dependent change is made here. Installations that have +an extended character set, where for example $\\{xchr}[\O{32}]=\hbox{\.{\'^^Z% +\'}}$, +would like string \O{32} to be the single character \O{32} instead of the +three characters \O{136}, \O{136}, \O{132} (\.{\^\^Z}). On the other hand, +even people with an extended character set will want to represent string +\O{15} by \.{\^\^M}, since \O{15} is ASCII's ``carriage return'' code; 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 \MF\ internal +code number~\|k corresponds to a non-troublesome visible symbol in the +local character set. +If character \|k cannot be printed, and $\|k<\O{200}$, then character $\|k+% +\O{100}$ or +$\|k-\O{100}$ must be printable; moreover, ASCII codes $[\O{60}\to\O{71},% +\O{141}\to\O{146}]$ +must be printable. + +\Y\P$\4\X49:Character \|k cannot be printed\X\S$\6 +$(\|k<\.{"\ "})\V(\|k>\.{"\~"})$\par +\U48.\fi + +\M50. When the \.{WEB} system program called \.{TANGLE} processes the % +\.{MF.WEB} +description that you are now reading, it outputs the \PASCAL\ program +\.{MF.PAS} and also a string pool file called \.{MF.POOL}. The \.{INIMF} +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 +\MF's string memory. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\&{init} \37\\{pool\_file}: \37\\{alpha\_file};\C{the string-pool file output +by \.{TANGLE}}\6 +\&{tini}\par +\fi + +\M51. \P\D \37$\\{bad\_pool}(\#)\S$\1\6 +\&{begin} \37\\{wake\_up\_terminal};\5 +$\\{write\_ln}(\\{term\_out},\39\#)$;\5 +$\\{a\_close}(\\{pool\_file})$;\5 +$\\{get\_strings\_started}\K\\{false}$;\5 +\&{return};\6 +\&{end}\2\par +\Y\P$\4\X51:Read the other strings from the \.{MF.POOL} file and return % +\\{true}, or give an error message and return \\{false}\X\S$\6 +$\\{name\_of\_file}\K\\{pool\_name}$;\C{we needn't set \\{name\_length}}\6 +\&{if} $\\{a\_open\_in}(\\{pool\_file})$ \1\&{then}\6 +\&{begin} \37$\|c\K\\{false}$;\6 +\1\&{repeat} \37\X52:Read one string, but return \\{false} if the string memory +space is getting too tight for comfort\X;\6 +\4\&{until}\5 +\|c;\2\6 +$\\{a\_close}(\\{pool\_file})$;\5 +$\\{get\_strings\_started}\K\\{true}$;\6 +\&{end}\6 +\4\&{else} $\\{bad\_pool}(\.{\'!\ I\ can\'}\.{\'t\ read\ MF.POOL.\'})$\2\par +\U47.\fi + +\M52. \P$\X52:Read one string, but return \\{false} if the string memory space +is getting too tight for comfort\X\S$\6 +\&{begin} \37\&{if} $\\{eof}(\\{pool\_file})$ \1\&{then}\5 +$\\{bad\_pool}(\.{\'!\ MF.POOL\ has\ no\ check\ sum.\'})$;\2\6 +$\\{read}(\\{pool\_file},\39\|m,\39\|n)$;\C{read two digits of string length}\6 +\&{if} $\|m=\.{\'*\'}$ \1\&{then}\5 +\X53:Check the pool check sum\X\6 +\4\&{else} \&{begin} \37\&{if} $(\\{xord}[\|m]<\.{"0"})\V(\\{xord}[\|m]>% +\.{"9"})\V\30(\\{xord}[\|n]<\.{"0"})\V(\\{xord}[\|n]>\.{"9"})$ \1\&{then}\5 +$\\{bad\_pool}(\.{\'!\ MF.POOL\ line\ doesn\'}\.{\'t\ begin\ with\ two\ digits.% +\'})$;\2\6 +$\|l\K\\{xord}[\|m]\ast10+\\{xord}[\|n]-\.{"0"}\ast11$;\C{compute the length}\6 +\&{if} $\\{pool\_ptr}+\|l+\\{string\_vacancies}>\\{pool\_size}$ \1\&{then}\5 +$\\{bad\_pool}(\.{\'!\ You\ have\ to\ increase\ POOLSIZE.\'})$;\2\6 +\&{for} $\|k\K1\mathrel{\&{to}}\|l$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{eoln}(\\{pool\_file})$ \1\&{then}\5 +$\|m\K\.{\'\ \'}$\ \&{else} $\\{read}(\\{pool\_file},\39\|m)$;\2\6 +$\\{append\_char}(\\{xord}[\|m])$;\6 +\&{end};\2\6 +$\\{read\_ln}(\\{pool\_file})$;\5 +$\|g\K\\{make\_string}$;\5 +$\\{str\_ref}[\|g]\K\\{max\_str\_ref}$;\6 +\&{end};\2\6 +\&{end}\par +\U51.\fi + +\M53. The \.{WEB} operation \.{@\$} denotes the value that should be at the +end of this \.{MF.POOL} file; any other value means that the wrong pool +file has been loaded. + +\Y\P$\4\X53:Check the pool check sum\X\S$\6 +\&{begin} \37$\|a\K0$;\5 +$\|k\K1$;\6 +\~ \1\&{loop}\ \&{begin} \37\&{if} $(\\{xord}[\|n]<\.{"0"})\V(\\{xord}[\|n]>% +\.{"9"})$ \1\&{then}\5 +$\\{bad\_pool}(\.{\'!\ MF.POOL\ check\ sum\ doesn\'}\.{\'t\ have\ nine\ digits.% +\'})$;\2\6 +$\|a\K10\ast\|a+\\{xord}[\|n]-\.{"0"}$;\6 +\&{if} $\|k=9$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\\{incr}(\|k)$;\5 +$\\{read}(\\{pool\_file},\39\|n)$;\6 +\&{end};\2\6 +\4\\{done}: \37\&{if} $\|a\I\)$ \1\&{then}\5 +$\\{bad\_pool}(\.{\'!\ MF.POOL\ doesn\'}\.{\'t\ match;\ TANGLE\ me\ again.% +\'})$;\2\6 +$\|c\K\\{true}$;\6 +\&{end}\par +\U52.\fi + +\N54. \[5] On-line and off-line printing. +Messages that are sent to a user's terminal and to the transcript-log file +are produced by several `\\{print}' procedures. These procedures will +direct their output to a variety of places, based on the setting of +the global variable \\{selector}, which has the following possible +values: + +\yskip +\hang \\{term\_and\_log}, the normal setting, prints on the terminal and on the +transcript file. + +\hang \\{log\_only}, prints only on the transcript file. + +\hang \\{term\_only}, prints only on the terminal. + +\hang \\{no\_print}, doesn't print at all. This is used only in rare cases +before the transcript file is open. + +\hang \\{pseudo}, puts output into a cyclic buffer that is used +by the \\{show\_context} routine; when we get to that routine we shall discuss +the reasoning behind this curious mode. + +\hang \\{new\_string}, appends the output to the current string in the +string pool. + +\yskip +\noindent The symbolic names `\\{term\_and\_log}', etc., have been assigned +numeric codes that satisfy the convenient relations $\\{no\_print}+1=\\{term% +\_only}$, +$\\{no\_print}+2=\\{log\_only}$, $\\{term\_only}+2=\\{log\_only}+1=\\{term\_and% +\_log}$. + +Three additional global variables, \\{tally} and \\{term\_offset} and +\\{file\_offset}, record the number of characters that have been printed +since they were most recently cleared to zero. We use \\{tally} to record +the length of (possibly very long) stretches of printing; \\{term\_offset} +and \\{file\_offset}, on the other hand, keep track of how many characters +have appeared so far on the current line that has been output to the +terminal or to the transcript file, respectively. + +\Y\P\D \37$\\{no\_print}=0$\C{\\{selector} setting that makes data disappear}% +\par +\P\D \37$\\{term\_only}=1$\C{printing is destined for the terminal only}\par +\P\D \37$\\{log\_only}=2$\C{printing is destined for the transcript file only}% +\par +\P\D \37$\\{term\_and\_log}=3$\C{normal \\{selector} setting}\par +\P\D \37$\\{pseudo}=4$\C{special \\{selector} setting for \\{show\_context}}\par +\P\D \37$\\{new\_string}=5$\C{printing is deflected to the string pool}\par +\P\D \37$\\{max\_selector}=5$\C{highest selector setting}\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{log\_file}: \37\\{alpha\_file};\C{transcript of \MF\ session}\6 +\4\\{selector}: \37$0\to\\{max\_selector}$;\C{where to print a message}\6 +\4\\{dig}: \37\&{array} $[0\to22]$ \1\&{of}\5 +$0\to15$;\C{digits in a number being output}\2\6 +\4\\{tally}: \37\\{integer};\C{the number of characters recently printed}\6 +\4\\{term\_offset}: \37$0\to\\{max\_print\_line}$;\C{the number of characters +on the current terminal line}\6 +\4\\{file\_offset}: \37$0\to\\{max\_print\_line}$;\C{the number of characters +on the current file line}\6 +\4\\{trick\_buf}: \37\&{array} $[0\to\\{error\_line}]$ \1\&{of}\5 +\\{ASCII\_code};\C{circular buffer for pseudoprinting}\2\6 +\4\\{trick\_count}: \37\\{integer};\C{threshold for pseudoprinting, explained +later}\6 +\4\\{first\_count}: \37\\{integer};\C{another variable for pseudoprinting}\par +\fi + +\M55. \P$\X55:Initialize the output routines\X\S$\6 +$\\{selector}\K\\{term\_only}$;\5 +$\\{tally}\K0$;\5 +$\\{term\_offset}\K0$;\5 +$\\{file\_offset}\K0$;\par +\As61, 783\ETs792. +\U1204.\fi + +\M56. 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} here. + +\Y\P\D \37$\\{wterm}(\#)\S\\{write}(\\{term\_out},\39\#)$\par +\P\D \37$\\{wterm\_ln}(\#)\S\\{write\_ln}(\\{term\_out},\39\#)$\par +\P\D \37$\\{wterm\_cr}\S\\{write\_ln}(\\{term\_out})$\par +\P\D \37$\\{wlog}(\#)\S\\{write}(\\{log\_file},\39\#)$\par +\P\D \37$\\{wlog\_ln}(\#)\S\\{write\_ln}(\\{log\_file},\39\#)$\par +\P\D \37$\\{wlog\_cr}\S\\{write\_ln}(\\{log\_file})$\par +\fi + +\M57. To end a line of text output, we call \\{print\_ln}. + +\Y\P$\4\X57:Basic printing procedures\X\S$\6 +\4\&{procedure}\1\ \37\\{print\_ln};\C{prints an end-of-line}\2\6 +\&{begin} \37\&{case} $\\{selector}$ \1\&{of}\6 +\4\\{term\_and\_log}: \37\&{begin} \37\\{wterm\_cr};\5 +\\{wlog\_cr};\5 +$\\{term\_offset}\K0$;\5 +$\\{file\_offset}\K0$;\6 +\&{end};\6 +\4\\{log\_only}: \37\&{begin} \37\\{wlog\_cr};\5 +$\\{file\_offset}\K0$;\6 +\&{end};\6 +\4\\{term\_only}: \37\&{begin} \37\\{wterm\_cr};\5 +$\\{term\_offset}\K0$;\6 +\&{end};\6 +\4$\\{no\_print},\39\\{pseudo},\39\\{new\_string}$: \37\\{do\_nothing};\2\6 +\&{end};\C{there are no other cases}\6 +\&{end};\C{note that \\{tally} is not affected}\par +\As58, 59, 60, 62, 63, 64, 103, 104, 187, 195, 197\ETs773. +\U4.\fi + +\M58. The \\{print\_char} procedure sends one character to the desired +destination, +using the \\{xchr} array to map it into an external character compatible with +\\{input\_ln}. All printing comes through \\{print\_ln} or \\{print\_char}. + +\Y\P$\4\X57:Basic printing procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{print\_char}(\|s:\\{ASCII\_code})$;\C{prints a +single character}\2\6 +\&{begin} \37\&{case} $\\{selector}$ \1\&{of}\6 +\4\\{term\_and\_log}: \37\&{begin} \37$\\{wterm}(\\{xchr}[\|s])$;\5 +$\\{wlog}(\\{xchr}[\|s])$;\5 +$\\{incr}(\\{term\_offset})$;\5 +$\\{incr}(\\{file\_offset})$;\6 +\&{if} $\\{term\_offset}=\\{max\_print\_line}$ \1\&{then}\6 +\&{begin} \37\\{wterm\_cr};\5 +$\\{term\_offset}\K0$;\6 +\&{end};\2\6 +\&{if} $\\{file\_offset}=\\{max\_print\_line}$ \1\&{then}\6 +\&{begin} \37\\{wlog\_cr};\5 +$\\{file\_offset}\K0$;\6 +\&{end};\2\6 +\&{end};\6 +\4\\{log\_only}: \37\&{begin} \37$\\{wlog}(\\{xchr}[\|s])$;\5 +$\\{incr}(\\{file\_offset})$;\6 +\&{if} $\\{file\_offset}=\\{max\_print\_line}$ \1\&{then}\5 +\\{print\_ln};\2\6 +\&{end};\6 +\4\\{term\_only}: \37\&{begin} \37$\\{wterm}(\\{xchr}[\|s])$;\5 +$\\{incr}(\\{term\_offset})$;\6 +\&{if} $\\{term\_offset}=\\{max\_print\_line}$ \1\&{then}\5 +\\{print\_ln};\2\6 +\&{end};\6 +\4\\{no\_print}: \37\\{do\_nothing};\6 +\4\\{pseudo}: \37\&{if} $\\{tally}<\\{trick\_count}$ \1\&{then}\5 +$\\{trick\_buf}[\\{tally}\mathbin{\&{mod}}\\{error\_line}]\K\|s$;\2\6 +\4\\{new\_string}: \37\&{begin} \37\&{if} $\\{pool\_ptr}<\\{pool\_size}$ \1% +\&{then}\5 +$\\{append\_char}(\|s)$;\2\6 +\&{end};\C{we drop characters if the string space is full}\2\6 +\&{end};\C{there are no other cases}\6 +$\\{incr}(\\{tally})$;\6 +\&{end};\par +\fi + +\M59. 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 \MF\ goes directly to the \\{print% +\_char} +routine when it knows that this is safe. (The present implementation +assumes that it is always safe to print a visible ASCII character.) + +\Y\P$\4\X57:Basic printing procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{print}(\|s:\\{integer})$;\C{prints string \|s}\6 +\4\&{var} \37\|j: \37\\{pool\_pointer};\C{current character code position}\2\6 +\&{begin} \37\&{if} $(\|s<0)\V(\|s\G\\{str\_ptr})$ \1\&{then}\5 +$\|s\K\.{"???"}$;\C{this can't happen}\2\6 +\&{if} $(\|s<256)\W(\\{selector}>\\{pseudo})$ \1\&{then}\5 +$\\{print\_char}(\|s)$\6 +\4\&{else} \&{begin} \37$\|j\K\\{str\_start}[\|s]$;\6 +\&{while} $\|j<\\{str\_start}[\|s+1]$ \1\&{do}\6 +\&{begin} \37$\\{print\_char}(\\{so}(\\{str\_pool}[\|j]))$;\5 +$\\{incr}(\|j)$;\6 +\&{end};\2\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M60. Sometimes it's necessary to print a string whose characters +may not be visible ASCII codes. In that case \\{slow\_print} is used. + +\Y\P$\4\X57:Basic printing procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{slow\_print}(\|s:\\{integer})$;\C{prints string \|s}% +\6 +\4\&{var} \37\|j: \37\\{pool\_pointer};\C{current character code position}\2\6 +\&{begin} \37\&{if} $(\|s<0)\V(\|s\G\\{str\_ptr})$ \1\&{then}\5 +$\|s\K\.{"???"}$;\C{this can't happen}\2\6 +\&{if} $(\|s<256)\W(\\{selector}>\\{pseudo})$ \1\&{then}\5 +$\\{print\_char}(\|s)$\6 +\4\&{else} \&{begin} \37$\|j\K\\{str\_start}[\|s]$;\6 +\&{while} $\|j<\\{str\_start}[\|s+1]$ \1\&{do}\6 +\&{begin} \37$\\{print}(\\{so}(\\{str\_pool}[\|j]))$;\5 +$\\{incr}(\|j)$;\6 +\&{end};\2\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M61. Here is the very first thing that \MF\ prints: a headline that identifies +the version number and base name. The \\{term\_offset} variable is temporarily +incorrect, but the discrepancy is not serious since we assume that the banner +and base identifier together will occupy at most \\{max\_print\_line} +character positions. + +\Y\P$\4\X55:Initialize the output routines\X\mathrel{+}\S$\6 +$\\{wterm}(\\{banner})$;\6 +\&{if} $\\{base\_ident}=0$ \1\&{then}\5 +$\\{wterm\_ln}(\.{\'\ (no\ base\ preloaded)\'})$\6 +\4\&{else} \&{begin} \37$\\{slow\_print}(\\{base\_ident})$;\5 +\\{print\_ln};\6 +\&{end};\2\6 +\\{update\_terminal};\par +\fi + +\M62. The procedure \\{print\_nl} is like \\{print}, but it makes sure that the +string appears at the beginning of a new line. + +\Y\P$\4\X57:Basic printing procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{print\_nl}(\|s:\\{str\_number})$;\C{prints string % +\|s at beginning of line}\2\6 +\&{begin} \37\&{if} $((\\{term\_offset}>0)\W(\\{odd}(\\{selector})))\V\30((% +\\{file\_offset}>0)\W(\\{selector}\G\\{log\_only}))$ \1\&{then}\5 +\\{print\_ln};\2\6 +$\\{print}(\|s)$;\6 +\&{end};\par +\fi + +\M63. An array of digits in the range $0\to9$ is printed by \\{print\_the% +\_digs}. + +\Y\P$\4\X57:Basic printing procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{print\_the\_digs}(\|k:\\{eight\_bits})$;\C{prints $% +\\{dig}[\|k-1]$$\,\ldots\,$$\\{dig}[0]$}\2\6 +\&{begin} \37\&{while} $\|k>0$ \1\&{do}\6 +\&{begin} \37$\\{decr}(\|k)$;\5 +$\\{print\_char}(\.{"0"}+\\{dig}[\|k])$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M64. The following procedure, which prints out the decimal representation of a +given integer \|n, has been written carefully so that it works properly +if $\|n=0$ or if $(-\|n)$ would cause overflow. It does not apply $\mathbin{% +\&{mod}}$ or $\mathbin{\&{div}}$ +to negative arguments, since such operations are not implemented consistently +by all \PASCAL\ compilers. + +\Y\P$\4\X57:Basic printing procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{print\_int}(\|n:\\{integer})$;\C{prints an integer +in decimal form}\6 +\4\&{var} \37\|k: \37$0\to23$;\C{index to current digit; we assume that $% +\|n<10^{23}$}\6 +\|m: \37\\{integer};\C{used to negate \|n in possibly dangerous cases}\2\6 +\&{begin} \37$\|k\K0$;\6 +\&{if} $\|n<0$ \1\&{then}\6 +\&{begin} \37$\\{print\_char}(\.{"-"})$;\6 +\&{if} $\|n>-100000000$ \1\&{then}\5 +$\\{negate}(\|n)$\6 +\4\&{else} \&{begin} \37$\|m\K-1-\|n$;\5 +$\|n\K\|m\mathbin{\&{div}}10$;\5 +$\|m\K(\|m\mathbin{\&{mod}}10)+1$;\5 +$\|k\K1$;\6 +\&{if} $\|m<10$ \1\&{then}\5 +$\\{dig}[0]\K\|m$\6 +\4\&{else} \&{begin} \37$\\{dig}[0]\K0$;\5 +$\\{incr}(\|n)$;\6 +\&{end};\2\6 +\&{end};\2\6 +\&{end};\2\6 +\1\&{repeat} \37$\\{dig}[\|k]\K\|n\mathbin{\&{mod}}10$;\5 +$\|n\K\|n\mathbin{\&{div}}10$;\5 +$\\{incr}(\|k)$;\6 +\4\&{until}\5 +$\|n=0$;\2\6 +$\\{print\_the\_digs}(\|k)$;\6 +\&{end};\par +\fi + +\M65. \MF\ also makes use of a trivial procedure to print two digits. The +following subroutine is usually called with a parameter in the range $0\L\|n% +\L99$. + +\Y\P\4\&{procedure}\1\ \37$\\{print\_dd}(\|n:\\{integer})$;\C{prints two least +significant digits}\2\6 +\&{begin} \37$\|n\K\\{abs}(\|n)\mathbin{\&{mod}}100$;\5 +$\\{print\_char}(\.{"0"}+(\|n\mathbin{\&{div}}10))$;\5 +$\\{print\_char}(\.{"0"}+(\|n\mathbin{\&{mod}}10))$;\6 +\&{end};\par +\fi + +\M66. Here is a procedure that asks the user to type a line of input, +assuming that the \\{selector} setting is either \\{term\_only} or \\{term\_and% +\_log}. +The input is placed into locations \\{first} through $\\{last}-1$ of the +\\{buffer} array, and echoed on the transcript file if appropriate. + +This procedure is never called when $\\{interaction}<\\{scroll\_mode}$. + +\Y\P\D \37$\\{prompt\_input}(\#)\S$\1\6 +\&{begin} \37\\{wake\_up\_terminal};\5 +$\\{print}(\#)$;\5 +\\{term\_input};\6 +\&{end}\C{prints a string and gets a line of input}\2\par +\Y\P\4\&{procedure}\1\ \37\\{term\_input};\C{gets a line from the terminal}\6 +\4\&{var} \37\|k: \37$0\to\\{buf\_size}$;\C{index into \\{buffer}}\2\6 +\&{begin} \37\\{update\_terminal};\C{now the user sees the prompt for sure}\6 +\&{if} $\R\\{input\_ln}(\\{term\_in},\39\\{true})$ \1\&{then}\5 +$\\{fatal\_error}(\.{"End\ of\ file\ on\ the\ terminal!"})$;\2\6 +$\\{term\_offset}\K0$;\C{the user's line ended with \<\rm return>}\6 +$\\{decr}(\\{selector})$;\C{prepare to echo the input}\6 +\&{if} $\\{last}\I\\{first}$ \1\&{then}\6 +\&{for} $\|k\K\\{first}\mathrel{\&{to}}\\{last}-1$ \1\&{do}\5 +$\\{print}(\\{buffer}[\|k])$;\2\2\6 +\\{print\_ln};\5 +$\\{buffer}[\\{last}]\K\.{"\%"}$;\5 +$\\{incr}(\\{selector})$;\C{restore previous status}\6 +\&{end};\par +\fi + +\N67. \[6] Reporting errors. +When something anomalous is detected, \MF\ typically does something like this: +$$\vbox{\halign{#\hfil\cr +$\\{print\_err}(\.{"Something\ anomalous\ has\ been\ detected"})$;\cr +$\\{help3}(\.{"This\ is\ the\ first\ line\ of\ my\ offer\ to\ help."})$\cr +$(\.{"This\ is\ the\ second\ line.\ I\'m\ trying\ to"})$\cr +$(\.{"explain\ the\ best\ way\ for\ you\ to\ proceed."})$;\cr +\\{error};\cr}}$$ +A two-line help message would be given using \\{help2}, etc.; these informal +helps should use simple vocabulary that complements the words used in the +official error message that was printed. (Outside the U.S.A., the help +messages should preferably be translated into the local vernacular. Each +line of help is at most 60 characters long, in the present implementation, +so that \\{max\_print\_line} will not be exceeded.) + +The \\{print\_err} procedure supplies a `\.!' before the official message, +and makes sure that the terminal is awake if a stop is going to occur. +The \\{error} procedure supplies a `\..' after the official message, then it +shows the location of the error; and if $\\{interaction}=\\{error\_stop% +\_mode}$, +it also enters into a dialog with the user, during which time the help +message may be printed. + +\fi + +\M68. The global variable \\{interaction} has four settings, representing +increasing +amounts of user interaction: + +\Y\P\D \37$\\{batch\_mode}=0$\C{omits all stops and omits terminal output}\par +\P\D \37$\\{nonstop\_mode}=1$\C{omits all stops}\par +\P\D \37$\\{scroll\_mode}=2$\C{omits error stops}\par +\P\D \37$\\{error\_stop\_mode}=3$\C{stops at every opportunity to interact}\par +\P\D \37$\\{print\_err}(\#)\S$\1\6 +\&{begin} \37\&{if} $\\{interaction}=\\{error\_stop\_mode}$ \1\&{then}\5 +\\{wake\_up\_terminal};\2\6 +$\\{print\_nl}(\.{"!\ "})$;\5 +$\\{print}(\#)$;\6 +\&{end}\2\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{interaction}: \37$\\{batch\_mode}\to\\{error\_stop\_mode}$;\C{current +level of interaction}\par +\fi + +\M69. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{interaction}\K\\{error\_stop\_mode}$;\par +\fi + +\M70. \MF\ is careful not to call \\{error} when the print \\{selector} setting +might be unusual. The only possible values of \\{selector} at the time of +error messages are + +\yskip\hang\\{no\_print} (when $\\{interaction}=\\{batch\_mode}$ +and \\{log\_file} not yet open); + +\hang\\{term\_only} (when $\\{interaction}>\\{batch\_mode}$ and \\{log\_file} +not yet open); + +\hang\\{log\_only} (when $\\{interaction}=\\{batch\_mode}$ and \\{log\_file} is +open); + +\hang\\{term\_and\_log} (when $\\{interaction}>\\{batch\_mode}$ and \\{log% +\_file} is open). + +\Y\P$\4\X70:Initialize the print \\{selector} based on \\{interaction}\X\S$\6 +\&{if} $\\{interaction}=\\{batch\_mode}$ \1\&{then}\5 +$\\{selector}\K\\{no\_print}$\ \&{else} $\\{selector}\K\\{term\_only}$\2\par +\Us1023\ET1211.\fi + +\M71. A global variable \\{deletions\_allowed} is set \\{false} if the \\{get% +\_next} +routine is active when \\{error} is called; this ensures that \\{get\_next} +will never be called recursively. + +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 statement. If \\{error\_count} reaches 100, \MF\ decides +that there is no point in continuing further. + +\Y\P\D \37$\\{spotless}=0$\C{\\{history} value when nothing has been amiss yet}% +\par +\P\D \37$\\{warning\_issued}=1$\C{\\{history} value when \\{begin\_diagnostic} +has been called}\par +\P\D \37$\\{error\_message\_issued}=2$\C{\\{history} value when \\{error} has +been called}\par +\P\D \37$\\{fatal\_error\_stop}=3$\C{\\{history} value when termination was +premature}\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{deletions\_allowed}: \37\\{boolean};\C{is it safe for \\{error} to call % +\\{get\_next}?}\6 +\4\\{history}: \37$\\{spotless}\to\\{fatal\_error\_stop}$;\C{has the source +input been clean so far?}\6 +\4\\{error\_count}: \37$-1\to100$;\C{the number of scrolled errors since the +last statement ended}\par +\fi + +\M72. The value of \\{history} is initially \\{fatal\_error\_stop}, but it will +be changed to \\{spotless} if \MF\ survives the initialization process. + +\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{deletions\_allowed}\K\\{true}$;\5 +$\\{error\_count}\K0$;\C{\\{history} is initialized elsewhere}\par +\fi + +\M73. Since errors can be detected almost anywhere in \MF, 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\_next} is being used to delete a token, and/or if some fatal error +occurs while \MF\ is trying to fix a non-fatal one. But such recursion +is never more than two levels deep. + +\Y\P$\4\X73:Error handling procedures\X\S$\6 +\4\&{procedure}\1\ \37\\{normalize\_selector};\5 +\\{forward};\5 +\hbox{\2}\6 +\4\&{procedure}\1\ \37\\{get\_next};\5 +\\{forward};\5 +\hbox{\2}\6 +\4\&{procedure}\1\ \37\\{term\_input};\5 +\\{forward};\5 +\hbox{\2}\6 +\4\&{procedure}\1\ \37\\{show\_context};\5 +\\{forward};\5 +\hbox{\2}\6 +\4\&{procedure}\1\ \37\\{begin\_file\_reading};\5 +\\{forward};\5 +\hbox{\2}\6 +\4\&{procedure}\1\ \37\\{open\_log\_file};\5 +\\{forward};\5 +\hbox{\2}\6 +\4\&{procedure}\1\ \37\\{close\_files\_and\_terminate};\5 +\\{forward};\5 +\hbox{\2}\6 +\4\&{procedure}\1\ \37\\{clear\_for\_error\_prompt};\5 +\\{forward};\5 +\hbox{\2}\6 +\hbox{\4\hskip-\fontdimen2\font}\ \&{debug} \37\ \&{procedure}\1\ \37\\{debug% +\_help};\5 +\\{forward};\ \&{gubed} \6 +\hbox{\4}\X43:Declare the procedure called \\{flush\_string}\X\par +\As76, 77, 88, 89\ETs90. +\U4.\fi + +\M74. Individual lines of help are recorded in the array \\{help\_line}, which +contains entries in positions $0\to(\\{help\_ptr}-1)$. They should be printed +in reverse order, i.e., with $\\{help\_line}[0]$ appearing last. + +\Y\P\D \37$\\{hlp1}(\#)\S\\{help\_line}[0]\K\#$;\ \&{end} \par +\P\D \37$\\{hlp2}(\#)\S\\{help\_line}[1]\K\#$;\5 +\\{hlp1}\par +\P\D \37$\\{hlp3}(\#)\S\\{help\_line}[2]\K\#$;\5 +\\{hlp2}\par +\P\D \37$\\{hlp4}(\#)\S\\{help\_line}[3]\K\#$;\5 +\\{hlp3}\par +\P\D \37$\\{hlp5}(\#)\S\\{help\_line}[4]\K\#$;\5 +\\{hlp4}\par +\P\D \37$\\{hlp6}(\#)\S\\{help\_line}[5]\K\#$;\5 +\\{hlp5}\par +\P\D \37$\\{help0}\S\\{help\_ptr}\K0$\C{sometimes there might be no help}\par +\P\D \37$\\{help1}\S$\ \&{begin} \37$\\{help\_ptr}\K1$;\5 +\\{hlp1}\C{use this with one help line}\par +\P\D \37$\\{help2}\S$\ \&{begin} \37$\\{help\_ptr}\K2$;\5 +\\{hlp2}\C{use this with two help lines}\par +\P\D \37$\\{help3}\S$\ \&{begin} \37$\\{help\_ptr}\K3$;\5 +\\{hlp3}\C{use this with three help lines}\par +\P\D \37$\\{help4}\S$\ \&{begin} \37$\\{help\_ptr}\K4$;\5 +\\{hlp4}\C{use this with four help lines}\par +\P\D \37$\\{help5}\S$\ \&{begin} \37$\\{help\_ptr}\K5$;\5 +\\{hlp5}\C{use this with five help lines}\par +\P\D \37$\\{help6}\S$\ \&{begin} \37$\\{help\_ptr}\K6$;\5 +\\{hlp6}\C{use this with six help lines}\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{help\_line}: \37\&{array} $[0\to5]$ \1\&{of}\5 +\\{str\_number};\C{helps for the next \\{error}}\2\6 +\4\\{help\_ptr}: \37$0\to6$;\C{the number of help lines present}\6 +\4\\{use\_err\_help}: \37\\{boolean};\C{should the \\{err\_help} string be +shown?}\6 +\4\\{err\_help}: \37\\{str\_number};\C{a string set up by \&{errhelp}}\par +\fi + +\M75. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{help\_ptr}\K0$;\5 +$\\{use\_err\_help}\K\\{false}$;\5 +$\\{err\_help}\K0$;\par +\fi + +\M76. The \\{jump\_out} procedure just cuts across all active procedure levels +and +goes to \\{end\_of\_MF}. This is the only nontrivial \&{goto} statement in the +whole program. It is used when there is no recovery from a particular error. + +Some \PASCAL\ compilers do not implement non-local \&{goto} statements. +In such cases the body of \\{jump\_out} should simply be +`\\{close\_files\_and\_terminate};\thinspace' followed by a call on some system +procedure that quietly terminates the program. + +\Y\P$\4\X73:Error handling procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{jump\_out};\2\6 +\&{begin} \37\&{goto} \37\\{end\_of\_MF};\6 +\&{end};\par +\fi + +\M77. Here now is the general \\{error} routine. + +\Y\P$\4\X73:Error handling procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{error};\C{completes the job of error reporting}\6 +\4\&{label} \37$\\{continue},\39\\{exit}$;\6 +\4\&{var} \37\|c: \37\\{ASCII\_code};\C{what the user types}\6 +$\\{s1},\39\\{s2},\39\\{s3}$: \37\\{integer};\C{used to save global variables +when deleting tokens}\6 +\|j: \37\\{pool\_pointer};\C{character position being printed}\2\6 +\&{begin} \37\&{if} $\\{history}<\\{error\_message\_issued}$ \1\&{then}\5 +$\\{history}\K\\{error\_message\_issued}$;\2\6 +$\\{print\_char}(\.{"."})$;\5 +\\{show\_context};\6 +\&{if} $\\{interaction}=\\{error\_stop\_mode}$ \1\&{then}\5 +\X78:Get user's advice and \&{return}\X;\2\6 +$\\{incr}(\\{error\_count})$;\6 +\&{if} $\\{error\_count}=100$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"(That\ makes\ 100\ errors;\ please\ try\ +again.)"})$;\5 +$\\{history}\K\\{fatal\_error\_stop}$;\5 +\\{jump\_out};\6 +\&{end};\2\6 +\X86:Put help message on the transcript file\X;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M78. \P$\X78:Get user's advice and \&{return}\X\S$\6 +\~ \1\&{loop}\ \&{begin} \37\\{continue}: \37\\{clear\_for\_error\_prompt};\5 +$\\{prompt\_input}(\.{"?\ "})$;\6 +\&{if} $\\{last}=\\{first}$ \1\&{then}\5 +\&{return};\2\6 +$\|c\K\\{buffer}[\\{first}]$;\6 +\&{if} $\|c\G\.{"a"}$ \1\&{then}\5 +$\|c\K\|c+\.{"A"}-\.{"a"}$;\C{convert to uppercase}\2\6 +\X79:Interpret code \|c and \&{return} if done\X;\6 +\&{end}\2\par +\U77.\fi + +\M79. It is desirable to provide an `\.E' option here that gives the user +an easy way to return from \MF\ 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\P$\4\X79:Interpret code \|c and \&{return} if done\X\S$\6 +\&{case} $\|c$ \1\&{of}\6 +\4$\.{"0"},\39\.{"1"},\39\.{"2"},\39\.{"3"},\39\.{"4"},\39\.{"5"},\39\.{"6"},% +\39\.{"7"},\39\.{"8"},\39\.{"9"}$: \37\&{if} $\\{deletions\_allowed}$ \1% +\&{then}\5 +\X83:Delete $\|c-\.{"0"}$ tokens and \&{goto} \\{continue}\X;\2\6 +\hbox{\4\4}\ \&{debug} \37\.{"D"}: \37\&{begin} \37\\{debug\_help};\5 +\&{goto} \37\\{continue};\ \&{end};\ \&{gubed}\6 +\4\.{"E"}: \37\&{if} $\\{file\_ptr}>0$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"You\ want\ to\ edit\ file\ "})$;\5 +$\\{slow\_print}(\\{input\_stack}[\\{file\_ptr}].\\{name\_field})$;\5 +$\\{print}(\.{"\ at\ line\ "})$;\5 +$\\{print\_int}(\\{line})$;\6 +$\\{interaction}\K\\{scroll\_mode}$;\5 +\\{jump\_out};\6 +\&{end};\2\6 +\4\.{"H"}: \37\X84:Print the help information and \&{goto} \\{continue}\X;\6 +\4\.{"I"}: \37\X82:Introduce new material from the terminal and \&{return}\X;\6 +\4$\.{"Q"},\39\.{"R"},\39\.{"S"}$: \37\X81:Change the interaction level and % +\&{return}\X;\6 +\4\.{"X"}: \37\&{begin} \37$\\{interaction}\K\\{scroll\_mode}$;\5 +\\{jump\_out};\6 +\&{end};\6 +\4\&{othercases} \37\\{do\_nothing}\2\6 +\&{endcases};\6 +\X80:Print the menu of available options\X\par +\U78.\fi + +\M80. \P$\X80:Print the menu of available options\X\S$\6 +\&{begin} \37$\\{print}(\.{"Type\ <return>\ to\ proceed,\ S\ to\ scroll\ future% +\ error\ messages,"})$;\6 +$\\{print\_nl}(\.{"R\ to\ run\ without\ stopping,\ Q\ to\ run\ quietly,"})$;\6 +$\\{print\_nl}(\.{"I\ to\ insert\ something,\ "})$;\6 +\&{if} $\\{file\_ptr}>0$ \1\&{then}\5 +$\\{print}(\.{"E\ to\ edit\ your\ file,"})$;\2\6 +\&{if} $\\{deletions\_allowed}$ \1\&{then}\5 +$\\{print\_nl}(\.{"1\ or\ ...\ or\ 9\ to\ ignore\ the\ next\ 1\ to\ 9\ tokens\ +of\ input,"})$;\2\6 +$\\{print\_nl}(\.{"H\ for\ help,\ X\ to\ quit."})$;\6 +\&{end}\par +\U79.\fi + +\M81. Here the author of \MF\ apologizes for making use of the numerical +relation between \.{"Q"}, \.{"R"}, \.{"S"}, and the desired interaction +settings +\\{batch\_mode}, \\{nonstop\_mode}, \\{scroll\_mode}. + +\Y\P$\4\X81:Change the interaction level and \&{return}\X\S$\6 +\&{begin} \37$\\{error\_count}\K0$;\5 +$\\{interaction}\K\\{batch\_mode}+\|c-\.{"Q"}$;\5 +$\\{print}(\.{"OK,\ entering\ "})$;\6 +\&{case} $\|c$ \1\&{of}\6 +\4\.{"Q"}: \37\&{begin} \37$\\{print}(\.{"batchmode"})$;\5 +$\\{decr}(\\{selector})$;\6 +\&{end};\6 +\4\.{"R"}: \37$\\{print}(\.{"nonstopmode"})$;\6 +\4\.{"S"}: \37$\\{print}(\.{"scrollmode"})$;\2\6 +\&{end};\C{there are no other cases}\6 +$\\{print}(\.{"..."})$;\5 +\\{print\_ln};\5 +\\{update\_terminal};\5 +\&{return};\6 +\&{end}\par +\U79.\fi + +\M82. When the following code is executed, $\\{buffer}[(\\{first}+1)\to(% +\\{last}-1)]$ may +contain the material inserted by the user; otherwise another prompt will +be given. In order to understand this part of the program fully, you need +to be familiar with \MF's input stacks. + +\Y\P$\4\X82:Introduce new material from the terminal and \&{return}\X\S$\6 +\&{begin} \37\\{begin\_file\_reading};\C{enter a new syntactic level for +terminal input}\6 +\&{if} $\\{last}>\\{first}+1$ \1\&{then}\6 +\&{begin} \37$\\{loc}\K\\{first}+1$;\5 +$\\{buffer}[\\{first}]\K\.{"\ "}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{prompt\_input}(\.{"insert>"})$;\5 +$\\{loc}\K\\{first}$;\6 +\&{end};\2\6 +$\\{first}\K\\{last}+1$;\5 +$\\{cur\_input}.\\{limit\_field}\K\\{last}$;\5 +\&{return};\6 +\&{end}\par +\U79.\fi + +\M83. We allow deletion of up to 99 tokens at a time. + +\Y\P$\4\X83:Delete $\|c-\.{"0"}$ tokens and \&{goto} \\{continue}\X\S$\6 +\&{begin} \37$\\{s1}\K\\{cur\_cmd}$;\5 +$\\{s2}\K\\{cur\_mod}$;\5 +$\\{s3}\K\\{cur\_sym}$;\5 +$\\{OK\_to\_interrupt}\K\\{false}$;\6 +\&{if} $(\\{last}>\\{first}+1)\W(\\{buffer}[\\{first}+1]\G\.{"0"})\W(% +\\{buffer}[\\{first}+1]\L\.{"9"})$ \1\&{then}\5 +$\|c\K\|c\ast10+\\{buffer}[\\{first}+1]-\.{"0"}\ast11$\6 +\4\&{else} $\|c\K\|c-\.{"0"}$;\2\6 +\&{while} $\|c>0$ \1\&{do}\6 +\&{begin} \37\\{get\_next};\C{one-level recursive call of \\{error} is +possible}\6 +\X743:Decrease the string reference count, if the current token is a string\X;\6 +$\\{decr}(\|c)$;\6 +\&{end};\2\6 +$\\{cur\_cmd}\K\\{s1}$;\5 +$\\{cur\_mod}\K\\{s2}$;\5 +$\\{cur\_sym}\K\\{s3}$;\5 +$\\{OK\_to\_interrupt}\K\\{true}$;\5 +$\\{help2}(\.{"I\ have\ just\ deleted\ some\ text,\ as\ you\ asked."})$\6 +$(\.{"You\ can\ now\ delete\ more,\ or\ insert,\ or\ whatever."})$;\5 +\\{show\_context};\5 +\&{goto} \37\\{continue};\6 +\&{end}\par +\U79.\fi + +\M84. \P$\X84:Print the help information and \&{goto} \\{continue}\X\S$\6 +\&{begin} \37\&{if} $\\{use\_err\_help}$ \1\&{then}\6 +\&{begin} \37\X85:Print the string \\{err\_help}, possibly on several lines\X;\6 +$\\{use\_err\_help}\K\\{false}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37\&{if} $\\{help\_ptr}=0$ \1\&{then}\5 +$\\{help2}(\.{"Sorry,\ I\ don\'t\ know\ how\ to\ help\ in\ this\ situation."})$% +\2\6 +$\hbox{\kern1em}(\.{"Maybe\ you\ should\ try\ asking\ a\ human?"})$;\6 +\1\&{repeat} \37$\\{decr}(\\{help\_ptr})$;\5 +$\\{print}(\\{help\_line}[\\{help\_ptr}])$;\5 +\\{print\_ln};\6 +\4\&{until}\5 +$\\{help\_ptr}=0$;\2\6 +\&{end};\2\6 +$\\{help4}(\.{"Sorry,\ I\ already\ gave\ what\ help\ I\ could..."})$\6 +$(\.{"Maybe\ you\ should\ try\ asking\ a\ human?"})$\6 +$(\.{"An\ error\ might\ have\ occurred\ before\ I\ noticed\ any\ problems."})$\6 +$(\.{"\`\`If\ all\ else\ fails,\ read\ the\ instructions.\'\'"})$;\6 +\&{goto} \37\\{continue};\6 +\&{end}\par +\U79.\fi + +\M85. \P$\X85:Print the string \\{err\_help}, possibly on several lines\X\S$\6 +$\|j\K\\{str\_start}[\\{err\_help}]$;\6 +\&{while} $\|j<\\{str\_start}[\\{err\_help}+1]$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{str\_pool}[\|j]\I\\{si}(\.{"\%"})$ \1\&{then}\5 +$\\{print}(\\{so}(\\{str\_pool}[\|j]))$\6 +\4\&{else} \&{if} $\|j+1=\\{str\_start}[\\{err\_help}+1]$ \1\&{then}\5 +\\{print\_ln}\6 +\4\&{else} \&{if} $\\{str\_pool}[\|j+1]\I\\{si}(\.{"\%"})$ \1\&{then}\5 +\\{print\_ln}\6 +\4\&{else} \&{begin} \37$\\{incr}(\|j)$;\5 +$\\{print\_char}(\.{"\%"})$;\6 +\&{end};\2\2\2\6 +$\\{incr}(\|j)$;\6 +\&{end}\2\par +\Us84\ET86.\fi + +\M86. \P$\X86:Put help message on the transcript file\X\S$\6 +\&{if} $\\{interaction}>\\{batch\_mode}$ \1\&{then}\5 +$\\{decr}(\\{selector})$;\C{avoid terminal output}\2\6 +\&{if} $\\{use\_err\_help}$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{""})$;\5 +\X85:Print the string \\{err\_help}, possibly on several lines\X;\6 +\&{end}\6 +\4\&{else} \&{while} $\\{help\_ptr}>0$ \1\&{do}\6 +\&{begin} \37$\\{decr}(\\{help\_ptr})$;\5 +$\\{print\_nl}(\\{help\_line}[\\{help\_ptr}])$;\6 +\&{end};\2\2\6 +\\{print\_ln};\6 +\&{if} $\\{interaction}>\\{batch\_mode}$ \1\&{then}\5 +$\\{incr}(\\{selector})$;\C{re-enable terminal output}\2\6 +\\{print\_ln}\par +\U77.\fi + +\M87. In anomalous cases, the print selector might be in an unknown state; +the following subroutine is called to fix things just enough to keep +running a bit longer. + +\Y\P\4\&{procedure}\1\ \37\\{normalize\_selector};\2\6 +\&{begin} \37\&{if} $\\{log\_opened}$ \1\&{then}\5 +$\\{selector}\K\\{term\_and\_log}$\6 +\4\&{else} $\\{selector}\K\\{term\_only}$;\2\6 +\&{if} $\\{job\_name}=0$ \1\&{then}\5 +\\{open\_log\_file};\2\6 +\&{if} $\\{interaction}=\\{batch\_mode}$ \1\&{then}\5 +$\\{decr}(\\{selector})$;\2\6 +\&{end};\par +\fi + +\M88. The following procedure prints \MF's last words before dying. + +\Y\P\D \37$\\{succumb}\S$\1\6 +\&{begin} \37\&{if} $\\{interaction}=\\{error\_stop\_mode}$ \1\&{then}\5 +$\\{interaction}\K\\{scroll\_mode}$;\C{no more interaction}\2\6 +\&{if} $\\{log\_opened}$ \1\&{then}\5 +\\{error};\2\6 +\&{debug} \37\&{if} $\\{interaction}>\\{batch\_mode}$ \1\&{then}\5 +\\{debug\_help};\2\ \&{gubed}\6 +$\\{history}\K\\{fatal\_error\_stop}$;\5 +\\{jump\_out};\C{irrecoverable error}\6 +\&{end}\2\par +\Y\P$\4\X73:Error handling procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{fatal\_error}(\|s:\\{str\_number})$;\C{prints \|s, +and that's it}\2\6 +\&{begin} \37\\{normalize\_selector};\6 +$\\{print\_err}(\.{"Emergency\ stop"})$;\5 +$\\{help1}(\|s)$;\5 +\\{succumb};\6 +\&{end};\par +\fi + +\M89. Here is the most dreaded error message. + +\Y\P$\4\X73:Error handling procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{overflow}(\|s:\\{str\_number};\,\35\|n:% +\\{integer})$;\C{stop due to finiteness}\2\6 +\&{begin} \37\\{normalize\_selector};\5 +$\\{print\_err}(\.{"METAFONT\ capacity\ exceeded,\ sorry\ ["})$;\5 +$\\{print}(\|s)$;\5 +$\\{print\_char}(\.{"="})$;\5 +$\\{print\_int}(\|n)$;\5 +$\\{print\_char}(\.{"]"})$;\5 +$\\{help2}(\.{"If\ you\ really\ absolutely\ need\ more\ capacity,"})$\6 +$(\.{"you\ can\ ask\ a\ wizard\ to\ enlarge\ me."})$;\5 +\\{succumb};\6 +\&{end};\par +\fi + +\M90. 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 \MF\ +maintenance person instead of the user (unless the user has been +particularly diabolical). The index entries for `this can't happen' may +help to pinpoint the problem. + +\Y\P$\4\X73:Error handling procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{confusion}(\|s:\\{str\_number})$;\C{consistency +check violated; \|s tells where}\2\6 +\&{begin} \37\\{normalize\_selector};\6 +\&{if} $\\{history}<\\{error\_message\_issued}$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"This\ can\'t\ happen\ ("})$;\5 +$\\{print}(\|s)$;\5 +$\\{print\_char}(\.{")"})$;\5 +$\\{help1}(\.{"I\'m\ broken.\ Please\ show\ this\ to\ someone\ who\ can\ fix\ +can\ fix"})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{print\_err}(\.{"I\ can\'t\ go\ on\ meeting\ you\ +like\ this"})$;\5 +$\\{help2}(\.{"One\ of\ your\ faux\ pas\ seems\ to\ have\ wounded\ me\ +deeply..."})$\6 +$(\.{"in\ fact,\ I\'m\ barely\ conscious.\ Please\ fix\ it\ and\ try\ +again."})$;\6 +\&{end};\2\6 +\\{succumb};\6 +\&{end};\par +\fi + +\M91. Users occasionally want to interrupt \MF\ while it's running. +If the \PASCAL\ runtime system allows this, one can implement +a routine that sets the global variable \\{interrupt} to some nonzero value +when such an interrupt is signalled. Otherwise there is probably at least +a way to make \\{interrupt} nonzero using the \PASCAL\ debugger. + +\Y\P\D \37$\\{check\_interrupt}\S$\1\6 +\&{begin} \37\&{if} $\\{interrupt}\I0$ \1\&{then}\5 +\\{pause\_for\_instructions};\2\6 +\&{end}\2\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{interrupt}: \37\\{integer};\C{should \MF\ pause for instructions?}\6 +\4\\{OK\_to\_interrupt}: \37\\{boolean};\C{should interrupts be observed?}\par +\fi + +\M92. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{interrupt}\K0$;\5 +$\\{OK\_to\_interrupt}\K\\{true}$;\par +\fi + +\M93. When an interrupt has been detected, the program goes into its +highest interaction level and lets the user have the full flexibility of +the \\{error} routine. \MF\ checks for interrupts only at times when it is +safe to do this. + +\Y\P\4\&{procedure}\1\ \37\\{pause\_for\_instructions};\2\6 +\&{begin} \37\&{if} $\\{OK\_to\_interrupt}$ \1\&{then}\6 +\&{begin} \37$\\{interaction}\K\\{error\_stop\_mode}$;\6 +\&{if} $(\\{selector}=\\{log\_only})\V(\\{selector}=\\{no\_print})$ \1\&{then}\5 +$\\{incr}(\\{selector})$;\2\6 +$\\{print\_err}(\.{"Interruption"})$;\5 +$\\{help3}(\.{"You\ rang?"})$\6 +$(\.{"Try\ to\ insert\ some\ instructions\ for\ me\ (e.g.,\`I\ show\ x\'),"})$\6 +$(\.{"unless\ you\ just\ want\ to\ quit\ by\ typing\ \`X\'."})$;\5 +$\\{deletions\_allowed}\K\\{false}$;\5 +\\{error};\5 +$\\{deletions\_allowed}\K\\{true}$;\5 +$\\{interrupt}\K0$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M94. Many of \MF's error messages state that a missing token has been +inserted behind the scenes. We can save string space and program space +by putting this common code into a subroutine. + +\Y\P\4\&{procedure}\1\ \37$\\{missing\_err}(\|s:\\{str\_number})$;\2\6 +\&{begin} \37$\\{print\_err}(\.{"Missing\ \`"})$;\5 +$\\{print}(\|s)$;\5 +$\\{print}(\.{"\'\ has\ been\ inserted"})$;\6 +\&{end};\par +\fi + +\N95. \[7] Arithmetic with scaled numbers. +The principal computations performed by \MF\ are done entirely in terms of +integers less than $2^{31}$ in magnitude; 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. + +But \PASCAL\ does not define the $\mathbin{\&{div}}$ +operation in the case of negative dividends; for example, the result of +$(-2\ast\|n-1)\mathbin{\&{div}}2$ is $-(\|n+1)$ on some computers and $-\|n$ on +others. +There are two principal types of arithmetic: ``translation-preserving,'' +in which the identity $(\|a+\|q\ast\|b)\mathbin{\&{div}}\|b=(\|a\mathbin{% +\&{div}}\|b)+\|q$ is valid; and +``negation-preserving,'' in which $(-\|a)\mathbin{\&{div}}\|b=-(\|a\mathbin{% +\&{div}}\|b)$. This leads to +two \MF s, which can produce different results, although the differences +should be negligible when the language is being used properly. +The \TeX\ processor has been defined carefully so that both varieties +of arithmetic will produce identical output, but it would be too +inefficient to constrain \MF\ in a similar way. + +\Y\P\D \37$\\{el\_gordo}\S\O{17777777777}$\C{$2^{31}-1$, the largest value that +\MF\ likes}\par +\fi + +\M96. One of \MF's most common operations is the calculation of +$\lfloor{a+b\over2}\rfloor$, +the midpoint of two given integers \|a and~\|b. The only decent way to do +this in \PASCAL\ is to write `$(\|a+\|b)\mathbin{\&{div}}2$'; but on most +machines it is +far more efficient to calculate `$(\|a+\|b)$ right shifted one bit'. + +Therefore the midpoint operation will always be denoted by `$\\{half}(\|a+% +\|b)$' +in this program. If \MF\ is being implemented with languages that permit +binary shifting, the \\{half} macro should be changed to make this operation +as efficient as possible. + +\Y\P\D \37$\\{half}(\#)\S(\#)\mathbin{\&{div}}2$\par +\fi + +\M97. 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 below set the global variable \\{arith\_error} to % +\\{true} +instead of reporting errors directly to the user. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{arith\_error}: \37\\{boolean};\C{has arithmetic overflow occurred +recently?}\par +\fi + +\M98. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{arith\_error}\K\\{false}$;\par +\fi + +\M99. At crucial points the program will say \\{check\_arith}, to test if +an arithmetic error has been detected. + +\Y\P\D \37$\\{check\_arith}\S$\1\6 +\&{begin} \37\&{if} $\\{arith\_error}$ \1\&{then}\5 +\\{clear\_arith};\ \2\6 +\&{end}\2\par +\Y\P\4\&{procedure}\1\ \37\\{clear\_arith};\2\6 +\&{begin} \37$\\{print\_err}(\.{"Arithmetic\ overflow"})$;\5 +$\\{help4}(\.{"Uh,\ oh.\ A\ little\ while\ ago\ one\ of\ the\ quantities\ that\ +I\ was"})$\6 +$(\.{"computing\ got\ too\ large,\ so\ I\'m\ afraid\ your\ answers\ will\ +be"})$\6 +$(\.{"somewhat\ askew.\ You\'ll\ probably\ have\ to\ adopt\ different"})$\6 +$(\.{"tactics\ next\ time.\ But\ I\ shall\ try\ to\ carry\ on\ anyway."})$;\5 +\\{error};\5 +$\\{arith\_error}\K\\{false}$;\6 +\&{end};\par +\fi + +\M100. Addition is not always checked to make sure that it doesn't overflow, +but in places where overflow isn't too unlikely the \\{slow\_add} routine +is used. + +\Y\P\4\&{function}\1\ \37$\\{slow\_add}(\|x,\39\|y:\\{integer})$: \37% +\\{integer};\2\6 +\&{begin} \37\&{if} $\|x\G0$ \1\&{then}\6 +\&{if} $\|y\L\\{el\_gordo}-\|x$ \1\&{then}\5 +$\\{slow\_add}\K\|x+\|y$\6 +\4\&{else} \&{begin} \37$\\{arith\_error}\K\\{true}$;\5 +$\\{slow\_add}\K\\{el\_gordo}$;\6 +\&{end}\2\6 +\4\&{else} \&{if} $-\|y\L\\{el\_gordo}+\|x$ \1\&{then}\5 +$\\{slow\_add}\K\|x+\|y$\6 +\4\&{else} \&{begin} \37$\\{arith\_error}\K\\{true}$;\5 +$\\{slow\_add}\K-\\{el\_gordo}$;\6 +\&{end};\2\2\6 +\&{end};\par +\fi + +\M101. Fixed-point arithmetic is done on {\sl scaled integers\/} that are +multiples +of $2^{-16}$. In other words, a binary point is assumed to be sixteen bit +positions from the right end of a binary computer word. + +\Y\P\D \37$\\{quarter\_unit}\S\O{40000}$\C{$2^{14}$, represents 0.250000}\par +\P\D \37$\\{half\_unit}\S\O{100000}$\C{$2^{15}$, represents 0.50000}\par +\P\D \37$\\{three\_quarter\_unit}\S\O{140000}$\C{$3\cdot2^{14}$, represents +0.75000}\par +\P\D \37$\\{unity}\S\O{200000}$\C{$2^{16}$, represents 1.00000}\par +\P\D \37$\\{two}\S\O{400000}$\C{$2^{17}$, represents 2.00000}\par +\P\D \37$\\{three}\S\O{600000}$\C{$2^{17}+2^{16}$, represents 3.00000}\par +\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6 +$\\{scaled}=\\{integer}$;\C{this type is used for scaled integers}\6 +$\\{small\_number}=0\to63$;\C{this type is self-explanatory}\par +\fi + +\M102. The following function is used to create a scaled integer from a given +decimal +fraction $(.d_0d_1\ldots d_{k-1})$, where $0\L\|k\L17$. The digit $d_i$ is +given in $\\{dig}[\|i]$, and the calculation produces a correctly rounded +result. + +\Y\P\4\&{function}\1\ \37$\\{round\_decimals}(\|k:\\{small\_number})$: \37% +\\{scaled};\C{converts a decimal fraction}\6 +\4\&{var} \37\|a: \37\\{integer};\C{the accumulator}\2\6 +\&{begin} \37$\|a\K0$;\6 +\&{while} $\|k>0$ \1\&{do}\6 +\&{begin} \37$\\{decr}(\|k)$;\5 +$\|a\K(\|a+\\{dig}[\|k]\ast\\{two})\mathbin{\&{div}}10$;\6 +\&{end};\2\6 +$\\{round\_decimals}\K\\{half}(\|a+1)$;\6 +\&{end};\par +\fi + +\M103. Conversely, here is a procedure analogous to \\{print\_int}. If the +output +of this procedure is subsequently read by \MF\ and converted by the +\\{round\_decimals} routine above, it turns out that the original value will +be reproduced exactly. A decimal point is printed only if the value is +not an integer. If there is more than one way to print the result with +the optimum number of digits following the decimal point, the closest +possible value is given. + +The invariant relation in the \&{repeat} loop is that a sequence of +decimal digits yet to be printed will yield the original number if and only if +they form a fraction~$f$ in the range $s-\delta\L10\cdot2^{16}f<s$. +We can stop if and only if $f=0$ satisfies this condition; the loop will +terminate before $s$ can possibly become zero. + +\Y\P$\4\X57:Basic printing procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{print\_scaled}(\|s:\\{scaled})$;\C{prints scaled +real, rounded to five digits}\6 +\4\&{var} \37\\{delta}: \37\\{scaled};\C{amount of allowable inaccuracy}\2\6 +\&{begin} \37\&{if} $\|s<0$ \1\&{then}\6 +\&{begin} \37$\\{print\_char}(\.{"-"})$;\5 +$\\{negate}(\|s)$;\C{print the sign, if negative}\6 +\&{end};\2\6 +$\\{print\_int}(\|s\mathbin{\&{div}}\\{unity})$;\C{print the integer part}\6 +$\|s\K10\ast(\|s\mathbin{\&{mod}}\\{unity})+5$;\6 +\&{if} $\|s\I5$ \1\&{then}\6 +\&{begin} \37$\\{delta}\K10$;\5 +$\\{print\_char}(\.{"."})$;\6 +\1\&{repeat} \37\&{if} $\\{delta}>\\{unity}$ \1\&{then}\5 +$\|s\K\|s+\O{100000}-(\\{delta}\mathbin{\&{div}}2)$;\C{round the final digit}\2% +\6 +$\\{print\_char}(\.{"0"}+(\|s\mathbin{\&{div}}\\{unity}))$;\5 +$\|s\K10\ast(\|s\mathbin{\&{mod}}\\{unity})$;\5 +$\\{delta}\K\\{delta}\ast10$;\6 +\4\&{until}\5 +$\|s\L\\{delta}$;\2\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M104. We often want to print two scaled quantities in parentheses, +separated by a comma. + +\Y\P$\4\X57:Basic printing procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{print\_two}(\|x,\39\|y:\\{scaled})$;\C{prints `$(% +\|x,\|y)$'}\2\6 +\&{begin} \37$\\{print\_char}(\.{"("})$;\5 +$\\{print\_scaled}(\|x)$;\5 +$\\{print\_char}(\.{","})$;\5 +$\\{print\_scaled}(\|y)$;\5 +$\\{print\_char}(\.{")"})$;\6 +\&{end};\par +\fi + +\M105. The \\{scaled} quantities in \MF\ programs are generally supposed to be +less than $2^{12}$ in absolute value, so \MF\ does much of its internal +arithmetic with 28~significant bits of precision. A \\{fraction} denotes +a scaled integer whose binary point is assumed to be 28 bit positions +from the right. + +\Y\P\D \37$\\{fraction\_half}\S\O{1000000000}$\C{$2^{27}$, represents +0.50000000}\par +\P\D \37$\\{fraction\_one}\S\O{2000000000}$\C{$2^{28}$, represents 1.00000000}% +\par +\P\D \37$\\{fraction\_two}\S\O{4000000000}$\C{$2^{29}$, represents 2.00000000}% +\par +\P\D \37$\\{fraction\_three}\S\O{6000000000}$\C{$3\cdot2^{28}$, represents +3.00000000}\par +\P\D \37$\\{fraction\_four}\S\O{10000000000}$\C{$2^{30}$, represents +4.00000000}\par +\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6 +$\\{fraction}=\\{integer}$;\C{this type is used for scaled fractions}\par +\fi + +\M106. In fact, the two sorts of scaling discussed above aren't quite +sufficient; \MF\ has yet another, used internally to keep track of angles +in units of $2^{-20}$ degrees. + +\Y\P\D \37$\\{forty\_five\_deg}\S\O{264000000}$\C{$45\cdot2^{20}$, represents +$45^\circ$}\par +\P\D \37$\\{ninety\_deg}\S\O{550000000}$\C{$90\cdot2^{20}$, represents $90^% +\circ$}\par +\P\D \37$\\{one\_eighty\_deg}\S\O{1320000000}$\C{$180\cdot2^{20}$, represents +$180^\circ$}\par +\P\D \37$\\{three\_sixty\_deg}\S\O{2640000000}$\C{$360\cdot2^{20}$, represents +$360^\circ$}\par +\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6 +$\\{angle}=\\{integer}$;\C{this type is used for scaled angles}\par +\fi + +\M107. The \\{make\_fraction} routine produces the \\{fraction} equivalent of +$\|p/\|q$, given integers \|p and~\|q; it computes the integer +$f=\lfloor2^{28}p/q+{1\over2}\rfloor$, when $p$ and $q$ are +positive. If \|p and \|q are both of the same scaled type \|t, +the ``type relation'' $\\{make\_fraction}(\|t,\|t)=\\{fraction}$ is valid; +and it's also possible to use the subroutine ``backwards,'' using +the relation $\\{make\_fraction}(\|t,\\{fraction})=\|t$ between scaled types. + +If the result would have magnitude $2^{31}$ or more, \\{make\_fraction} +sets $\\{arith\_error}\K\\{true}$. Most of \MF's internal computations have +been designed to avoid this sort of error. + +Notice that if 64-bit integer arithmetic were available, +we could simply compute $(\hbox{$(2^{29}$}\ast\|p+\|q)\mathbin{\&{div}}(2\ast% +\|q)$. +But when we are restricted to \PASCAL's 32-bit arithmetic we +must either resort to multiple-precision maneuvering +or use a simple but slow iteration. The multiple-precision technique +would be about three times faster than the code adopted here, but it +would be comparatively long and tricky, involving about sixteen +additional multiplications and divisions. + +This operation is part of \MF's ``inner loop''; indeed, it will +consume nearly 10\pct! of the running time (exclusive of input and output) +if the code below is left unchanged. A machine-dependent recoding +will therefore make \MF\ run faster. The present implementation +is highly portable, but slow; it avoids multiplication and division +except in the initial stage. System wizards should be careful to +replace it with a routine that is guaranteed to produce identical +results in all cases. + +As noted below, a few more routines should also be replaced by +machine-dependent +code, for efficiency. But when a procedure is not part of the ``inner loop,'' +such changes aren't advisable; simplicity and robustness are +preferable to trickery, unless the cost is too high. + +\Y\P\4\&{function}\1\ \37$\\{make\_fraction}(\|p,\39\|q:\\{integer})$: \37% +\\{fraction};\6 +\4\&{var} \37\|f: \37\\{integer};\C{the fraction bits, with a leading 1 bit}\6 +\|n: \37\\{integer};\C{the integer part of $\vert p/q\vert$}\6 +\\{negative}: \37\\{boolean};\C{should the result be negated?}\6 +\\{be\_careful}: \37\\{integer};\C{disables certain compiler optimizations}\2\6 +\&{begin} \37\&{if} $\|p\G0$ \1\&{then}\5 +$\\{negative}\K\\{false}$\6 +\4\&{else} \&{begin} \37$\\{negate}(\|p)$;\5 +$\\{negative}\K\\{true}$;\6 +\&{end};\2\6 +\&{if} $\|q\L0$ \1\&{then}\6 +\&{begin} \37\&{debug} \37\&{if} $\|q=0$ \1\&{then}\5 +$\\{confusion}(\.{"/"})$;\2\ \&{gubed}\6 +$\\{negate}(\|q)$;\5 +$\\{negative}\K\R\\{negative}$;\6 +\&{end};\2\6 +$\|n\K\|p\mathbin{\&{div}}\|q$;\5 +$\|p\K\|p\mathbin{\&{mod}}\|q$;\6 +\&{if} $\|n\G8$ \1\&{then}\6 +\&{begin} \37$\\{arith\_error}\K\\{true}$;\6 +\&{if} $\\{negative}$ \1\&{then}\5 +$\\{make\_fraction}\K-\\{el\_gordo}$\ \&{else} $\\{make\_fraction}\K\\{el% +\_gordo}$;\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|n\K(\|n-1)\ast\\{fraction\_one}$;\5 +\X108:Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$\X;\6 +\&{if} $\\{negative}$ \1\&{then}\5 +$\\{make\_fraction}\K-(\|f+\|n)$\ \&{else} $\\{make\_fraction}\K\|f+\|n$;\2\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M108. The \&{repeat} loop here preserves the following invariant relations +between \|f, \|p, and~\|q: +(i)~$0\L\|p<\|q$; (ii)~$fq+p=2^k(q+p_0)$, where $k$ is an integer and +$p_0$ is the original value of~$p$. + +Notice that the computation specifies +$(\|p-\|q)+\|p$ instead of $(\|p+\|p)-\|q$, because the latter could overflow. +Let us hope that optimizing compilers do not miss this point; a +special variable \\{be\_careful} is used to emphasize the necessary +order of computation. Optimizing compilers should keep \\{be\_careful} +in a register, not store it in memory. + +\Y\P$\4\X108:Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$\X\S$\6 +$\|f\K1$;\6 +\1\&{repeat} \37$\\{be\_careful}\K\|p-\|q$;\5 +$\|p\K\\{be\_careful}+\|p$;\6 +\&{if} $\|p\G0$ \1\&{then}\5 +$\|f\K\|f+\|f+1$\6 +\4\&{else} \&{begin} \37$\\{double}(\|f)$;\5 +$\|p\K\|p+\|q$;\6 +\&{end};\2\6 +\4\&{until}\5 +$\|f\G\\{fraction\_one}$;\2\6 +$\\{be\_careful}\K\|p-\|q$;\6 +\&{if} $\\{be\_careful}+\|p\G0$ \1\&{then}\5 +$\\{incr}(\|f)$\2\par +\U107.\fi + +\M109. The dual of \\{make\_fraction} is \\{take\_fraction}, which multiplies a +given integer~\|q by a fraction~\|f. When the operands are positive, it +computes $p=\lfloor qf/2^{28}+{1\over2}\rfloor$, a symmetric function +of \|q and~\|f. + +This routine is even more ``inner loopy'' than \\{make\_fraction}; +the present implementation consumes almost 20\pct! of \MF's computation +time during typical jobs, so a machine-language or 64-bit +substitute is advisable. + +\Y\P\4\&{function}\1\ \37$\\{take\_fraction}(\|q:\\{integer};\,\35\|f:% +\\{fraction})$: \37\\{integer};\6 +\4\&{var} \37\|p: \37\\{integer};\C{the fraction so far}\6 +\\{negative}: \37\\{boolean};\C{should the result be negated?}\6 +\|n: \37\\{integer};\C{additional multiple of $q$}\6 +\\{be\_careful}: \37\\{integer};\C{disables certain compiler optimizations}\2\6 +\&{begin} \37\X110:Reduce to the case that $\|f\G0$ and $\|q>0$\X;\6 +\&{if} $\|f<\\{fraction\_one}$ \1\&{then}\5 +$\|n\K0$\6 +\4\&{else} \&{begin} \37$\|n\K\|f\mathbin{\&{div}}\\{fraction\_one}$;\5 +$\|f\K\|f\mathbin{\&{mod}}\\{fraction\_one}$;\6 +\&{if} $\|q\L\\{el\_gordo}\mathbin{\&{div}}\|n$ \1\&{then}\5 +$\|n\K\|n\ast\|q$\6 +\4\&{else} \&{begin} \37$\\{arith\_error}\K\\{true}$;\5 +$\|n\K\\{el\_gordo}$;\6 +\&{end};\2\6 +\&{end};\2\6 +$\|f\K\|f+\\{fraction\_one}$;\5 +\X111:Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$\X;\6 +$\\{be\_careful}\K\|n-\\{el\_gordo}$;\6 +\&{if} $\\{be\_careful}+\|p>0$ \1\&{then}\6 +\&{begin} \37$\\{arith\_error}\K\\{true}$;\5 +$\|n\K\\{el\_gordo}-\|p$;\6 +\&{end};\2\6 +\&{if} $\\{negative}$ \1\&{then}\5 +$\\{take\_fraction}\K-(\|n+\|p)$\6 +\4\&{else} $\\{take\_fraction}\K\|n+\|p$;\2\6 +\&{end};\par +\fi + +\M110. \P$\X110:Reduce to the case that $\|f\G0$ and $\|q>0$\X\S$\6 +\&{if} $\|f\G0$ \1\&{then}\5 +$\\{negative}\K\\{false}$\6 +\4\&{else} \&{begin} \37$\\{negate}(\|f)$;\5 +$\\{negative}\K\\{true}$;\6 +\&{end};\2\6 +\&{if} $\|q<0$ \1\&{then}\6 +\&{begin} \37$\\{negate}(\|q)$;\5 +$\\{negative}\K\R\\{negative}$;\6 +\&{end};\2\par +\Us109\ET112.\fi + +\M111. The invariant relations in this case are (i)~$\lfloor(qf+p)/2^k\rfloor +=\lfloor qf_0/2^{28}+{1\over2}\rfloor$, where $k$ is an integer and +$f_0$ is the original value of~$f$; (ii)~$2^k\L f<2^{k+1}$. + +\Y\P$\4\X111:Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$\X\S$\6 +$\|p\K\\{fraction\_half}$;\C{that's $2^{27}$; the invariants hold now with +$k=28$}\6 +\&{if} $\|q<\\{fraction\_four}$ \1\&{then}\6 +\1\&{repeat} \37\&{if} $\\{odd}(\|f)$ \1\&{then}\5 +$\|p\K\\{half}(\|p+\|q)$\ \&{else} $\|p\K\\{half}(\|p)$;\2\6 +$\|f\K\\{half}(\|f)$;\6 +\4\&{until}\5 +$\|f=1$\2\6 +\4\&{else} \1\&{repeat} \37\&{if} $\\{odd}(\|f)$ \1\&{then}\5 +$\|p\K\|p+\\{half}(\|q-\|p)$\ \&{else} $\|p\K\\{half}(\|p)$;\2\6 +$\|f\K\\{half}(\|f)$;\6 +\4\&{until}\5 +$\|f=1$\2\2\par +\U109.\fi + +\M112. When we want to multiply something by a \\{scaled} quantity, we use a +scheme +analogous to \\{take\_fraction} but with a different scaling. +Given positive operands, \\{take\_scaled} +computes the quantity $p=\lfloor qf/2^{16}+{1\over2}\rfloor$. + +Once again it is a good idea to use 64-bit arithmetic if +possible; otherwise \\{take\_scaled} will use more than 2\pct! of the running +time +when the Computer Modern fonts are being generated. + +\Y\P\4\&{function}\1\ \37$\\{take\_scaled}(\|q:\\{integer};\,\35\|f:% +\\{scaled})$: \37\\{integer};\6 +\4\&{var} \37\|p: \37\\{integer};\C{the fraction so far}\6 +\\{negative}: \37\\{boolean};\C{should the result be negated?}\6 +\|n: \37\\{integer};\C{additional multiple of $q$}\6 +\\{be\_careful}: \37\\{integer};\C{disables certain compiler optimizations}\2\6 +\&{begin} \37\X110:Reduce to the case that $\|f\G0$ and $\|q>0$\X;\6 +\&{if} $\|f<\\{unity}$ \1\&{then}\5 +$\|n\K0$\6 +\4\&{else} \&{begin} \37$\|n\K\|f\mathbin{\&{div}}\\{unity}$;\5 +$\|f\K\|f\mathbin{\&{mod}}\\{unity}$;\6 +\&{if} $\|q\L\\{el\_gordo}\mathbin{\&{div}}\|n$ \1\&{then}\5 +$\|n\K\|n\ast\|q$\6 +\4\&{else} \&{begin} \37$\\{arith\_error}\K\\{true}$;\5 +$\|n\K\\{el\_gordo}$;\6 +\&{end};\2\6 +\&{end};\2\6 +$\|f\K\|f+\\{unity}$;\5 +\X113:Compute $p=\lfloor qf/2^{16}+{1\over2}\rfloor-q$\X;\6 +$\\{be\_careful}\K\|n-\\{el\_gordo}$;\6 +\&{if} $\\{be\_careful}+\|p>0$ \1\&{then}\6 +\&{begin} \37$\\{arith\_error}\K\\{true}$;\5 +$\|n\K\\{el\_gordo}-\|p$;\6 +\&{end};\2\6 +\&{if} $\\{negative}$ \1\&{then}\5 +$\\{take\_scaled}\K-(\|n+\|p)$\6 +\4\&{else} $\\{take\_scaled}\K\|n+\|p$;\2\6 +\&{end};\par +\fi + +\M113. \P$\X113:Compute $p=\lfloor qf/2^{16}+{1\over2}\rfloor-q$\X\S$\6 +$\|p\K\\{half\_unit}$;\C{that's $2^{15}$; the invariants hold now with $k=16$}\6 +\&{if} $\|q<\\{fraction\_four}$ \1\&{then}\6 +\1\&{repeat} \37\&{if} $\\{odd}(\|f)$ \1\&{then}\5 +$\|p\K\\{half}(\|p+\|q)$\ \&{else} $\|p\K\\{half}(\|p)$;\2\6 +$\|f\K\\{half}(\|f)$;\6 +\4\&{until}\5 +$\|f=1$\2\6 +\4\&{else} \1\&{repeat} \37\&{if} $\\{odd}(\|f)$ \1\&{then}\5 +$\|p\K\|p+\\{half}(\|q-\|p)$\ \&{else} $\|p\K\\{half}(\|p)$;\2\6 +$\|f\K\\{half}(\|f)$;\6 +\4\&{until}\5 +$\|f=1$\2\2\par +\U112.\fi + +\M114. For completeness, there's also \\{make\_scaled}, which computes a +quotient as a \\{scaled} number instead of as a \\{fraction}. +In other words, the result is $\lfloor2^{16}p/q+{1\over2}\rfloor$, if the +operands are positive. \ (This procedure is not used especially often, +so it is not part of \MF's inner loop.) + +\Y\P\4\&{function}\1\ \37$\\{make\_scaled}(\|p,\39\|q:\\{integer})$: \37% +\\{scaled};\6 +\4\&{var} \37\|f: \37\\{integer};\C{the fraction bits, with a leading 1 bit}\6 +\|n: \37\\{integer};\C{the integer part of $\vert p/q\vert$}\6 +\\{negative}: \37\\{boolean};\C{should the result be negated?}\6 +\\{be\_careful}: \37\\{integer};\C{disables certain compiler optimizations}\2\6 +\&{begin} \37\&{if} $\|p\G0$ \1\&{then}\5 +$\\{negative}\K\\{false}$\6 +\4\&{else} \&{begin} \37$\\{negate}(\|p)$;\5 +$\\{negative}\K\\{true}$;\6 +\&{end};\2\6 +\&{if} $\|q\L0$ \1\&{then}\6 +\&{begin} \37\&{debug} \37\&{if} $\|q=0$ \1\&{then}\5 +$\\{confusion}(\.{"/"})$;\ \2\6 +\&{gubed}\6 +$\\{negate}(\|q)$;\5 +$\\{negative}\K\R\\{negative}$;\6 +\&{end};\2\6 +$\|n\K\|p\mathbin{\&{div}}\|q$;\5 +$\|p\K\|p\mathbin{\&{mod}}\|q$;\6 +\&{if} $\|n\G\O{100000}$ \1\&{then}\6 +\&{begin} \37$\\{arith\_error}\K\\{true}$;\6 +\&{if} $\\{negative}$ \1\&{then}\5 +$\\{make\_scaled}\K-\\{el\_gordo}$\ \&{else} $\\{make\_scaled}\K\\{el\_gordo}$;% +\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|n\K(\|n-1)\ast\\{unity}$;\5 +\X115:Compute $f=\lfloor 2^{16}(1+p/q)+{1\over2}\rfloor$\X;\6 +\&{if} $\\{negative}$ \1\&{then}\5 +$\\{make\_scaled}\K-(\|f+\|n)$\ \&{else} $\\{make\_scaled}\K\|f+\|n$;\2\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M115. \P$\X115:Compute $f=\lfloor 2^{16}(1+p/q)+{1\over2}\rfloor$\X\S$\6 +$\|f\K1$;\6 +\1\&{repeat} \37$\\{be\_careful}\K\|p-\|q$;\5 +$\|p\K\\{be\_careful}+\|p$;\6 +\&{if} $\|p\G0$ \1\&{then}\5 +$\|f\K\|f+\|f+1$\6 +\4\&{else} \&{begin} \37$\\{double}(\|f)$;\5 +$\|p\K\|p+\|q$;\6 +\&{end};\2\6 +\4\&{until}\5 +$\|f\G\\{unity}$;\2\6 +$\\{be\_careful}\K\|p-\|q$;\6 +\&{if} $\\{be\_careful}+\|p\G0$ \1\&{then}\5 +$\\{incr}(\|f)$\2\par +\U114.\fi + +\M116. Here is a typical example of how the routines above can be used. +It computes the function +$${1\over3\tau}f(\theta,\phi)= +{\tau^{-1}\bigl(2+\sqrt2\,(\sin\theta-{1\over16}\sin\phi) +(\sin\phi-{1\over16}\sin\theta)(\cos\theta-\cos\phi)\bigr)\over +3\,\bigl(1+{1\over2}(\sqrt5-1)\cos\theta+{1\over2}(3-\sqrt5\,)\cos\phi% +\bigr)},$$ +where $\tau$ is a \\{scaled} ``tension'' parameter. This is \MF's magic +fudge factor for placing the first control point of a curve that starts +at an angle $\theta$ and ends at an angle $\phi$ from the straight path. +(Actually, if the stated quantity exceeds 4, \MF\ reduces it to~4.) + +The trigonometric quantity to be multiplied by $\sqrt2$ is less than $\sqrt2$. +(It's a sum of eight terms whose absolute values can be bounded using +relations such as $\sin\theta\cos\theta\L{1\over2}$.) Thus the numerator +is positive; and since the tension $\tau$ is constrained to be at least +$3\over4$, the numerator is less than $16\over3$. The denominator is +nonnegative and at most~6. Hence the fixed-point calculations below +are guaranteed to stay within the bounds of a 32-bit computer word. + +The angles $\theta$ and $\phi$ are given implicitly in terms of \\{fraction} +arguments \\{st}, \\{ct}, \\{sf}, and \\{cf}, representing $\sin\theta$, $\cos% +\theta$, +$\sin\phi$, and $\cos\phi$, respectively. + +\Y\P\4\&{function}\1\ \37$\\{velocity}(\\{st},\39\\{ct},\39\\{sf},\39\\{cf}:% +\\{fraction};\,\35\|t:\\{scaled})$: \37\\{fraction};\6 +\4\&{var} \37$\\{acc},\39\\{num},\39\\{denom}$: \37\\{integer};\C{registers for +intermediate calculations}\2\6 +\&{begin} \37$\\{acc}\K\\{take\_fraction}(\\{st}-(\\{sf}\mathbin{\&{div}}16),% +\39\\{sf}-(\\{st}\mathbin{\&{div}}16))$;\5 +$\\{acc}\K\\{take\_fraction}(\\{acc},\39\\{ct}-\\{cf})$;\5 +$\\{num}\K\\{fraction\_two}+\\{take\_fraction}(\\{acc},\39379625062)$;% +\C{$2^{28}\sqrt2\approx379625062.497$}\6 +$\\{denom}\K\\{fraction\_three}+\\{take\_fraction}(\\{ct},\39497706707)+\\{take% +\_fraction}(\\{cf},\39307599661)$;\C{$3\cdot2^{27}\cdot(\sqrt5-1)% +\approx497706706.78$ and $3\cdot2^{27}\cdot(3-\sqrt5\,)% +\approx307599661.22$}\6 +\&{if} $\|t\I\\{unity}$ \1\&{then}\5 +$\\{num}\K\\{make\_scaled}(\\{num},\39\|t)$;\C{$\\{make\_scaled}(\\{fraction},% +\\{scaled})=\\{fraction}$}\2\6 +\&{if} $\\{num}\mathbin{\&{div}}4\G\\{denom}$ \1\&{then}\5 +$\\{velocity}\K\\{fraction\_four}$\6 +\4\&{else} $\\{velocity}\K\\{make\_fraction}(\\{num},\39\\{denom})$;\2\6 +\&{end};\par +\fi + +\M117. The following somewhat different subroutine tests rigorously if $ab$ is +greater than, equal to, or less than~$cd$, +given integers $(a,b,c,d)$. In most cases a quick decision is reached. +The result is $+1$, 0, or~$-1$ in the three respective cases. + +\Y\P\D \37$\\{return\_sign}(\#)\S$\1\6 +\&{begin} \37$\\{ab\_vs\_cd}\K\#$;\5 +\&{return};\6 +\&{end}\2\par +\Y\P\4\&{function}\1\ \37$\\{ab\_vs\_cd}(\|a,\39\|b,\39\|c,\39\|d:% +\\{integer})$: \37\\{integer};\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37$\|q,\39\|r$: \37\\{integer};\C{temporary registers}\2\6 +\&{begin} \37\X118:Reduce to the case that $\|a,\|c\G0$, $\|b,\|d>0$\X;\6 +\~ \1\&{loop}\ \&{begin} \37$\|q\K\|a\mathbin{\&{div}}\|d$;\5 +$\|r\K\|c\mathbin{\&{div}}\|b$;\6 +\&{if} $\|q\I\|r$ \1\&{then}\6 +\&{if} $\|q>\|r$ \1\&{then}\5 +$\\{return\_sign}(1)$\ \&{else} $\\{return\_sign}(-1)$;\2\2\6 +$\|q\K\|a\mathbin{\&{mod}}\|d$;\5 +$\|r\K\|c\mathbin{\&{mod}}\|b$;\6 +\&{if} $\|r=0$ \1\&{then}\6 +\&{if} $\|q=0$ \1\&{then}\5 +$\\{return\_sign}(0)$\ \&{else} $\\{return\_sign}(1)$;\2\2\6 +\&{if} $\|q=0$ \1\&{then}\5 +$\\{return\_sign}(-1)$;\2\6 +$\|a\K\|b$;\5 +$\|b\K\|q$;\5 +$\|c\K\|d$;\5 +$\|d\K\|r$;\6 +\&{end};\C{now $\|a>\|d>0$ and $\|c>\|b>0$}\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M118. \P$\X118:Reduce to the case that $\|a,\|c\G0$, $\|b,\|d>0$\X\S$\6 +\&{if} $\|a<0$ \1\&{then}\6 +\&{begin} \37$\\{negate}(\|a)$;\5 +$\\{negate}(\|b)$;\6 +\&{end};\2\6 +\&{if} $\|c<0$ \1\&{then}\6 +\&{begin} \37$\\{negate}(\|c)$;\5 +$\\{negate}(\|d)$;\6 +\&{end};\2\6 +\&{if} $\|d\L0$ \1\&{then}\6 +\&{begin} \37\&{if} $\|b\G0$ \1\&{then}\6 +\&{if} $((\|a=0)\V(\|b=0))\W((\|c=0)\V(\|d=0))$ \1\&{then}\5 +$\\{return\_sign}(0)$\6 +\4\&{else} $\\{return\_sign}(1)$;\2\2\6 +\&{if} $\|d=0$ \1\&{then}\6 +\&{if} $\|a=0$ \1\&{then}\5 +$\\{return\_sign}(0)$\ \&{else} $\\{return\_sign}(-1)$;\2\2\6 +$\|q\K\|a$;\5 +$\|a\K\|c$;\5 +$\|c\K\|q$;\5 +$\|q\K-\|b$;\5 +$\|b\K-\|d$;\5 +$\|d\K\|q$;\6 +\&{end}\6 +\4\&{else} \&{if} $\|b\L0$ \1\&{then}\6 +\&{begin} \37\&{if} $\|b<0$ \1\&{then}\6 +\&{if} $\|a>0$ \1\&{then}\5 +$\\{return\_sign}(-1)$;\2\2\6 +\&{if} $\|c=0$ \1\&{then}\5 +$\\{return\_sign}(0)$\6 +\4\&{else} $\\{return\_sign}(-1)$;\2\6 +\&{end}\2\2\par +\U117.\fi + +\M119. We conclude this set of elementary routines with some simple rounding +and truncation operations that are coded in a machine-independent fashion. +The routines are slightly complicated because we want them to work +without overflow whenever $-2^{31}\L x<2^{31}$. + +\Y\P\4\&{function}\1\ \37$\\{floor\_scaled}(\|x:\\{scaled})$: \37\\{scaled};% +\C{$2^{16}\lfloor x/2^{16}\rfloor$}\6 +\4\&{var} \37\\{be\_careful}: \37\\{integer};\C{temporary register}\2\6 +\&{begin} \37\&{if} $\|x\G0$ \1\&{then}\5 +$\\{floor\_scaled}\K\|x-(\|x\mathbin{\&{mod}}\\{unity})$\6 +\4\&{else} \&{begin} \37$\\{be\_careful}\K\|x+1$;\5 +$\\{floor\_scaled}\K\|x+((-\\{be\_careful})\mathbin{\&{mod}}\\{unity})+1-% +\\{unity}$;\6 +\&{end};\2\6 +\&{end};\7 +\4\&{function}\1\ \37$\\{floor\_unscaled}(\|x:\\{scaled})$: \37\\{integer};% +\C{$\lfloor x/2^{16}\rfloor$}\6 +\4\&{var} \37\\{be\_careful}: \37\\{integer};\C{temporary register}\2\6 +\&{begin} \37\&{if} $\|x\G0$ \1\&{then}\5 +$\\{floor\_unscaled}\K\|x\mathbin{\&{div}}\\{unity}$\6 +\4\&{else} \&{begin} \37$\\{be\_careful}\K\|x+1$;\5 +$\\{floor\_unscaled}\K-(1+((-\\{be\_careful})\mathbin{\&{div}}\\{unity}))$;\6 +\&{end};\2\6 +\&{end};\7 +\4\&{function}\1\ \37$\\{round\_unscaled}(\|x:\\{scaled})$: \37\\{integer};% +\C{$\lfloor x/2^{16}+.5\rfloor$}\6 +\4\&{var} \37\\{be\_careful}: \37\\{integer};\C{temporary register}\2\6 +\&{begin} \37\&{if} $\|x\G\\{half\_unit}$ \1\&{then}\5 +$\\{round\_unscaled}\K1+((\|x-\\{half\_unit})\mathbin{\&{div}}\\{unity})$\6 +\4\&{else} \&{if} $\|x\G-\\{half\_unit}$ \1\&{then}\5 +$\\{round\_unscaled}\K0$\6 +\4\&{else} \&{begin} \37$\\{be\_careful}\K\|x+1$;\5 +$\\{round\_unscaled}\K-(1+((-\\{be\_careful}-\\{half\_unit})\mathbin{\&{div}}% +\\{unity}))$;\6 +\&{end};\2\2\6 +\&{end};\7 +\4\&{function}\1\ \37$\\{round\_fraction}(\|x:\\{fraction})$: \37\\{scaled};% +\C{$\lfloor x/2^{12}+.5\rfloor$}\6 +\4\&{var} \37\\{be\_careful}: \37\\{integer};\C{temporary register}\2\6 +\&{begin} \37\&{if} $\|x\G2048$ \1\&{then}\5 +$\\{round\_fraction}\K1+((\|x-2048)\mathbin{\&{div}}4096)$\6 +\4\&{else} \&{if} $\|x\G-2048$ \1\&{then}\5 +$\\{round\_fraction}\K0$\6 +\4\&{else} \&{begin} \37$\\{be\_careful}\K\|x+1$;\5 +$\\{round\_fraction}\K-(1+((-\\{be\_careful}-2048)\mathbin{\&{div}}4096))$;\6 +\&{end};\2\2\6 +\&{end};\par +\fi + +\N120. \[8] Algebraic and transcendental functions. +\MF\ computes all of the necessary special functions from scratch, without +relying on \\{real} arithmetic or system subroutines for sines, cosines, etc. + +\fi + +\M121. To get the square root of a \\{scaled} number \|x, we want to calculate +$s=\lfloor 2^8\!\sqrt x +{1\over2}\rfloor$. If $x>0$, this is the unique +integer such that $2^{16}x-s\L s^2<2^{16}x+s$. The following subroutine +determines $s$ by an iterative method that maintains the invariant +relations $x=2^{46-2k}x_0\bmod 2^{30}$, $0<y=\lfloor 2^{16-2k}x_0\rfloor +-s^2+s\L q=2s$, where $x_0$ is the initial value of $x$. The value of~$y$ +might, however, be zero at the start of the first iteration. + +\Y\P\4\&{function}\1\ \37$\\{square\_rt}(\|x:\\{scaled})$: \37\\{scaled};\6 +\4\&{var} \37\|k: \37\\{small\_number};\C{iteration control counter}\6 +$\|y,\39\|q$: \37\\{integer};\C{registers for intermediate calculations}\2\6 +\&{begin} \37\&{if} $\|x\L0$ \1\&{then}\5 +\X122:Handle square root of zero or negative argument\X\6 +\4\&{else} \&{begin} \37$\|k\K23$;\5 +$\|q\K2$;\6 +\&{while} $\|x<\\{fraction\_two}$ \1\&{do}\C{i.e., \&{while} $\|x<% +\hbox{$2^{29}$}$\unskip}\6 +\&{begin} \37$\\{decr}(\|k)$;\5 +$\|x\K\|x+\|x+\|x+\|x$;\6 +\&{end};\2\6 +\&{if} $\|x<\\{fraction\_four}$ \1\&{then}\5 +$\|y\K0$\6 +\4\&{else} \&{begin} \37$\|x\K\|x-\\{fraction\_four}$;\5 +$\|y\K1$;\6 +\&{end};\2\6 +\1\&{repeat} \37\X123:Decrease \|k by 1, maintaining the invariant relations +between \|x, \|y, and~\|q\X;\6 +\4\&{until}\5 +$\|k=0$;\2\6 +$\\{square\_rt}\K\\{half}(\|q)$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M122. \P$\X122:Handle square root of zero or negative argument\X\S$\6 +\&{begin} \37\&{if} $\|x<0$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"Square\ root\ of\ "})$;\5 +$\\{print\_scaled}(\|x)$;\5 +$\\{print}(\.{"\ has\ been\ replaced\ by\ 0"})$;\5 +$\\{help2}(\.{"Since\ I\ don\'t\ take\ square\ roots\ of\ negative\ +numbers,"})$\6 +$(\.{"I\'m\ zeroing\ this\ one.\ Proceed,\ with\ fingers\ crossed."})$;\5 +\\{error};\6 +\&{end};\2\6 +$\\{square\_rt}\K0$;\6 +\&{end}\par +\U121.\fi + +\M123. \P$\X123:Decrease \|k by 1, maintaining the invariant relations between % +\|x, \|y, and~\|q\X\S$\6 +$\\{double}(\|x)$;\5 +$\\{double}(\|y)$;\6 +\&{if} $\|x\G\\{fraction\_four}$ \1\&{then}\C{note that $\\{fraction\_four}=% +\hbox{$2^{30}$}$}\6 +\&{begin} \37$\|x\K\|x-\\{fraction\_four}$;\5 +$\\{incr}(\|y)$;\6 +\&{end};\2\6 +$\\{double}(\|x)$;\5 +$\|y\K\|y+\|y-\|q$;\5 +$\\{double}(\|q)$;\6 +\&{if} $\|x\G\\{fraction\_four}$ \1\&{then}\6 +\&{begin} \37$\|x\K\|x-\\{fraction\_four}$;\5 +$\\{incr}(\|y)$;\6 +\&{end};\2\6 +\&{if} $\|y>\|q$ \1\&{then}\6 +\&{begin} \37$\|y\K\|y-\|q$;\5 +$\|q\K\|q+2$;\6 +\&{end}\6 +\4\&{else} \&{if} $\|y\L0$ \1\&{then}\6 +\&{begin} \37$\|q\K\|q-2$;\5 +$\|y\K\|y+\|q$;\6 +\&{end};\2\2\6 +$\\{decr}(\|k)$\par +\U121.\fi + +\M124. Pythagorean addition $\psqrt{a^2+b^2}$ is implemented by an elegant +iterative scheme due to Cleve Moler and Donald Morrison [{\sl IBM Journal +of Research and Development\/ \bf27} (1983), 577--581]. It modifies \|a and~\|b +in such a way that their Pythagorean sum remains invariant, while the +smaller argument decreases. + +\Y\P\4\&{function}\1\ \37$\\{pyth\_add}(\|a,\39\|b:\\{integer})$: \37% +\\{integer};\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37\|r: \37\\{fraction};\C{register used to transform \|a and \|b}\6 +\\{big}: \37\\{boolean};\C{is the result dangerously near $2^{31}$?}\2\6 +\&{begin} \37$\|a\K\\{abs}(\|a)$;\5 +$\|b\K\\{abs}(\|b)$;\6 +\&{if} $\|a<\|b$ \1\&{then}\6 +\&{begin} \37$\|r\K\|b$;\5 +$\|b\K\|a$;\5 +$\|a\K\|r$;\6 +\&{end};\C{now $0\L\|b\L\|a$}\2\6 +\&{if} $\|b>0$ \1\&{then}\6 +\&{begin} \37\&{if} $\|a<\\{fraction\_two}$ \1\&{then}\5 +$\\{big}\K\\{false}$\6 +\4\&{else} \&{begin} \37$\|a\K\|a\mathbin{\&{div}}4$;\5 +$\|b\K\|b\mathbin{\&{div}}4$;\5 +$\\{big}\K\\{true}$;\6 +\&{end};\C{we reduced the precision to avoid arithmetic overflow}\2\6 +\X125:Replace \|a by an approximation to $\psqrt{a^2+b^2}$\X;\6 +\&{if} $\\{big}$ \1\&{then}\6 +\&{if} $\|a<\\{fraction\_two}$ \1\&{then}\5 +$\|a\K\|a+\|a+\|a+\|a$\6 +\4\&{else} \&{begin} \37$\\{arith\_error}\K\\{true}$;\5 +$\|a\K\\{el\_gordo}$;\6 +\&{end};\2\2\6 +\&{end};\2\6 +$\\{pyth\_add}\K\|a$;\6 +\&{end};\par +\fi + +\M125. The key idea here is to reflect the vector $(a,b)$ about the +line through $(a,b/2)$. + +\Y\P$\4\X125:Replace \|a by an approximation to $\psqrt{a^2+b^2}$\X\S$\6 +\~ \1\&{loop}\ \&{begin} \37$\|r\K\\{make\_fraction}(\|b,\39\|a)$;\5 +$\|r\K\\{take\_fraction}(\|r,\39\|r)$;\C{now $r\approx b^2/a^2$}\6 +\&{if} $\|r=0$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\|r\K\\{make\_fraction}(\|r,\39\\{fraction\_four}+\|r)$;\5 +$\|a\K\|a+\\{take\_fraction}(\|a+\|a,\39\|r)$;\5 +$\|b\K\\{take\_fraction}(\|b,\39\|r)$;\6 +\&{end};\2\6 +\4\\{done}: \37\par +\U124.\fi + +\M126. Here is a similar algorithm for $\psqrt{a^2-b^2}$. +It converges slowly when $b$ is near $a$, but otherwise it works fine. + +\Y\P\4\&{function}\1\ \37$\\{pyth\_sub}(\|a,\39\|b:\\{integer})$: \37% +\\{integer};\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37\|r: \37\\{fraction};\C{register used to transform \|a and \|b}\6 +\\{big}: \37\\{boolean};\C{is the input dangerously near $2^{31}$?}\2\6 +\&{begin} \37$\|a\K\\{abs}(\|a)$;\5 +$\|b\K\\{abs}(\|b)$;\6 +\&{if} $\|a\L\|b$ \1\&{then}\5 +\X128:Handle erroneous \\{pyth\_sub} and set $\|a\K0$\X\6 +\4\&{else} \&{begin} \37\&{if} $\|a<\\{fraction\_four}$ \1\&{then}\5 +$\\{big}\K\\{false}$\6 +\4\&{else} \&{begin} \37$\|a\K\\{half}(\|a)$;\5 +$\|b\K\\{half}(\|b)$;\5 +$\\{big}\K\\{true}$;\6 +\&{end};\2\6 +\X127:Replace \|a by an approximation to $\psqrt{a^2-b^2}$\X;\6 +\&{if} $\\{big}$ \1\&{then}\5 +$\|a\K\|a+\|a$;\2\6 +\&{end};\2\6 +$\\{pyth\_sub}\K\|a$;\6 +\&{end};\par +\fi + +\M127. \P$\X127:Replace \|a by an approximation to $\psqrt{a^2-b^2}$\X\S$\6 +\~ \1\&{loop}\ \&{begin} \37$\|r\K\\{make\_fraction}(\|b,\39\|a)$;\5 +$\|r\K\\{take\_fraction}(\|r,\39\|r)$;\C{now $r\approx b^2/a^2$}\6 +\&{if} $\|r=0$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\|r\K\\{make\_fraction}(\|r,\39\\{fraction\_four}-\|r)$;\5 +$\|a\K\|a-\\{take\_fraction}(\|a+\|a,\39\|r)$;\5 +$\|b\K\\{take\_fraction}(\|b,\39\|r)$;\6 +\&{end};\2\6 +\4\\{done}: \37\par +\U126.\fi + +\M128. \P$\X128:Handle erroneous \\{pyth\_sub} and set $\|a\K0$\X\S$\6 +\&{begin} \37\&{if} $\|a<\|b$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"Pythagorean\ subtraction\ "})$;\5 +$\\{print\_scaled}(\|a)$;\5 +$\\{print}(\.{"+-+"})$;\5 +$\\{print\_scaled}(\|b)$;\5 +$\\{print}(\.{"\ has\ been\ replaced\ by\ 0"})$;\5 +$\\{help2}(\.{"Since\ I\ don\'t\ take\ square\ roots\ of\ negative\ +numbers,"})$\6 +$(\.{"I\'m\ zeroing\ this\ one.\ Proceed,\ with\ fingers\ crossed."})$;\5 +\\{error};\6 +\&{end};\2\6 +$\|a\K0$;\6 +\&{end}\par +\U126.\fi + +\M129. The subroutines for logarithm and exponential involve two tables. +The first is simple: $\\{two\_to\_the}[\|k]$ equals $2^k$. The second involves +a bit more calculation, which the author claims to have done correctly: +$\\{spec\_log}[\|k]$ is $2^{27}$ times $\ln\bigl(1/(1-2^{-k})\bigr)= +2^{-k}+{1\over2}2^{-2k}+{1\over3}2^{-3k}+\cdots\,$, rounded to the +nearest integer. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{two\_to\_the}: \37\&{array} $[0\to30]$ \1\&{of}\5 +\\{integer};\C{powers of two}\2\6 +\4\\{spec\_log}: \37\&{array} $[1\to28]$ \1\&{of}\5 +\\{integer};\C{special logarithms}\2\par +\fi + +\M130. \P$\X19:Local variables for initialization\X\mathrel{+}\S$\6 +\4\|k: \37\\{integer};\C{all-purpose loop index}\par +\fi + +\M131. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{two\_to\_the}[0]\K1$;\6 +\&{for} $\|k\K1\mathrel{\&{to}}30$ \1\&{do}\5 +$\\{two\_to\_the}[\|k]\K2\ast\\{two\_to\_the}[\|k-1]$;\2\6 +$\\{spec\_log}[1]\K93032640$;\5 +$\\{spec\_log}[2]\K38612034$;\5 +$\\{spec\_log}[3]\K17922280$;\5 +$\\{spec\_log}[4]\K8662214$;\5 +$\\{spec\_log}[5]\K4261238$;\5 +$\\{spec\_log}[6]\K2113709$;\5 +$\\{spec\_log}[7]\K1052693$;\5 +$\\{spec\_log}[8]\K525315$;\5 +$\\{spec\_log}[9]\K262400$;\5 +$\\{spec\_log}[10]\K131136$;\5 +$\\{spec\_log}[11]\K65552$;\5 +$\\{spec\_log}[12]\K32772$;\5 +$\\{spec\_log}[13]\K16385$;\6 +\&{for} $\|k\K14\mathrel{\&{to}}27$ \1\&{do}\5 +$\\{spec\_log}[\|k]\K\\{two\_to\_the}[27-\|k]$;\2\6 +$\\{spec\_log}[28]\K1$;\par +\fi + +\M132. Here is the routine that calculates $2^8$ times the natural logarithm +of a \\{scaled} quantity; it is an integer approximation to $2^{24}% +\ln(x/2^{16})$, +when \|x is a given positive integer. + +The method is based on exercise 1.2.2--25 in {\sl The Art of Computer +Programming\/}: During the main iteration we have $1\L 2^{-30}x<1/(1-2^{1-k})$, +and the logarithm of $2^{30}x$ remains to be added to an accumulator +register called~$y$. Three auxiliary bits of accuracy are retained in~$y$ +during the calculation, and sixteen auxiliary bits to extend \|y are +kept in~\|z during the initial argument reduction. (We add +$100\cdot2^{16}=6553600$ to~\|z and subtract 100 from~\|y so that \|z will +not become negative; also, the actual amount subtracted from~\|y is~96, +not~100, because we want to add~4 for rounding before the final division by~8.) + +\Y\P\4\&{function}\1\ \37$\\{m\_log}(\|x:\\{scaled})$: \37\\{scaled};\6 +\4\&{var} \37$\|y,\39\|z$: \37\\{integer};\C{auxiliary registers}\6 +\|k: \37\\{integer};\C{iteration counter}\2\6 +\&{begin} \37\&{if} $\|x\L0$ \1\&{then}\5 +\X134:Handle non-positive logarithm\X\6 +\4\&{else} \&{begin} \37$\|y\K1302456956+4-100$;\C{$14\times2^{27}\ln2% +\approx1302456956.421063$}\6 +$\|z\K27595+6553600$;\C{and $2^{16}\times .421063\approx 27595$}\6 +\&{while} $\|x<\\{fraction\_four}$ \1\&{do}\6 +\&{begin} \37$\\{double}(\|x)$;\5 +$\|y\K\|y-93032639$;\5 +$\|z\K\|z-48782$;\6 +\&{end};\C{$2^{27}\ln2\approx 93032639.74436163$ and $2^{16}% +\times.74436163\approx 48782$}\2\6 +$\|y\K\|y+(\|z\mathbin{\&{div}}\\{unity})$;\5 +$\|k\K2$;\6 +\&{while} $\|x>\\{fraction\_four}+4$ \1\&{do}\5 +\X133:Increase \|k until \|x can be multiplied by a factor of $2^{-k}$, and +adjust $y$ accordingly\X;\2\6 +$\\{m\_log}\K\|y\mathbin{\&{div}}8$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M133. \P$\X133:Increase \|k until \|x can be multiplied by a factor of +$2^{-k}$, and adjust $y$ accordingly\X\S$\6 +\&{begin} \37$\|z\K((\|x-1)\mathbin{\&{div}}\\{two\_to\_the}[\|k])+1$;\C{$z=% +\lceil x/2^k\rceil$}\6 +\&{while} $\|x<\\{fraction\_four}+\|z$ \1\&{do}\6 +\&{begin} \37$\|z\K\\{half}(\|z+1)$;\5 +$\|k\K\|k+1$;\6 +\&{end};\2\6 +$\|y\K\|y+\\{spec\_log}[\|k]$;\5 +$\|x\K\|x-\|z$;\6 +\&{end}\par +\U132.\fi + +\M134. \P$\X134:Handle non-positive logarithm\X\S$\6 +\&{begin} \37$\\{print\_err}(\.{"Logarithm\ of\ "})$;\5 +$\\{print\_scaled}(\|x)$;\5 +$\\{print}(\.{"\ has\ been\ replaced\ by\ 0"})$;\5 +$\\{help2}(\.{"Since\ I\ don\'t\ take\ logs\ of\ non-positive\ numbers,"})$\6 +$(\.{"I\'m\ zeroing\ this\ one.\ Proceed,\ with\ fingers\ crossed."})$;\5 +\\{error};\5 +$\\{m\_log}\K0$;\6 +\&{end}\par +\U132.\fi + +\M135. Conversely, the exponential routine calculates $\exp(x/2^8)$, +when \|x is \\{scaled}. The result is an integer approximation to +$2^{16}\exp(x/2^{24})$, when \|x is regarded as an integer. + +\Y\P\4\&{function}\1\ \37$\\{m\_exp}(\|x:\\{scaled})$: \37\\{scaled};\6 +\4\&{var} \37\|k: \37\\{small\_number};\C{loop control index}\6 +$\|y,\39\|z$: \37\\{integer};\C{auxiliary registers}\2\6 +\&{begin} \37\&{if} $\|x>174436200$ \1\&{then}\C{$2^{24}\ln((2^{31}-1)/2^{16})% +\approx 174436199.51$}\6 +\&{begin} \37$\\{arith\_error}\K\\{true}$;\5 +$\\{m\_exp}\K\\{el\_gordo}$;\6 +\&{end}\6 +\4\&{else} \&{if} $\|x<-197694359$ \1\&{then}\5 +$\\{m\_exp}\K0$\C{$2^{24}\ln(2^{-1}/2^{16})\approx-197694359.45$}\6 +\4\&{else} \&{begin} \37\&{if} $\|x\L0$ \1\&{then}\6 +\&{begin} \37$\|z\K-8\ast\|x$;\5 +$\|y\K\O{4000000}$;\C{$y=2^{20}$}\6 +\&{end}\6 +\4\&{else} \&{begin} \37\&{if} $\|x\L127919879$ \1\&{then}\5 +$\|z\K1023359037-8\ast\|x$\C{$2^{27}\ln((2^{31}-1)/2^{20})\approx +1023359037.125$}\6 +\4\&{else} $\|z\K8\ast(174436200-\|x)$;\C{\|z is always nonnegative}\2\6 +$\|y\K\\{el\_gordo}$;\6 +\&{end};\2\6 +\X136:Multiply \|y by $\exp(-z/2^{27})$\X;\6 +\&{if} $\|x\L127919879$ \1\&{then}\5 +$\\{m\_exp}\K(\|y+8)\mathbin{\&{div}}16$\ \&{else} $\\{m\_exp}\K\|y$;\2\6 +\&{end};\2\2\6 +\&{end};\par +\fi + +\M136. The idea here is that subtracting $\\{spec\_log}[\|k]$ from \|z +corresponds +to multiplying \|y by $1-2^{-k}$. + +A subtle point (which had to be checked) was that if $x=127919879$, the +value of~\|y will decrease so that $\|y+8$ doesn't overflow. In fact, +$z$ will be 5 in this case, and \|y will decrease by~64 when $\|k=25$ +and by~16 when $\|k=27$. + +\Y\P$\4\X136:Multiply \|y by $\exp(-z/2^{27})$\X\S$\6 +$\|k\K1$;\6 +\&{while} $\|z>0$ \1\&{do}\6 +\&{begin} \37\&{while} $\|z\G\\{spec\_log}[\|k]$ \1\&{do}\6 +\&{begin} \37$\|z\K\|z-\\{spec\_log}[\|k]$;\5 +$\|y\K\|y-1-((\|y-\\{two\_to\_the}[\|k-1])\mathbin{\&{div}}\\{two\_to\_the}[% +\|k])$;\6 +\&{end};\2\6 +$\\{incr}(\|k)$;\6 +\&{end}\2\par +\U135.\fi + +\M137. The trigonometric subroutines use an auxiliary table such that +$\\{spec\_atan}[\|k]$ contains an approximation to the \\{angle} whose tangent +is~$1/2^k$. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{spec\_atan}: \37\&{array} $[1\to26]$ \1\&{of}\5 +\\{angle};\C{$\arctan2^{-k}$ times $2^{20}\cdot180/\pi$}\2\par +\fi + +\M138. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{spec\_atan}[1]\K27855475$;\5 +$\\{spec\_atan}[2]\K14718068$;\5 +$\\{spec\_atan}[3]\K7471121$;\5 +$\\{spec\_atan}[4]\K3750058$;\5 +$\\{spec\_atan}[5]\K1876857$;\5 +$\\{spec\_atan}[6]\K938658$;\5 +$\\{spec\_atan}[7]\K469357$;\5 +$\\{spec\_atan}[8]\K234682$;\5 +$\\{spec\_atan}[9]\K117342$;\5 +$\\{spec\_atan}[10]\K58671$;\5 +$\\{spec\_atan}[11]\K29335$;\5 +$\\{spec\_atan}[12]\K14668$;\5 +$\\{spec\_atan}[13]\K7334$;\5 +$\\{spec\_atan}[14]\K3667$;\5 +$\\{spec\_atan}[15]\K1833$;\5 +$\\{spec\_atan}[16]\K917$;\5 +$\\{spec\_atan}[17]\K458$;\5 +$\\{spec\_atan}[18]\K229$;\5 +$\\{spec\_atan}[19]\K115$;\5 +$\\{spec\_atan}[20]\K57$;\5 +$\\{spec\_atan}[21]\K29$;\5 +$\\{spec\_atan}[22]\K14$;\5 +$\\{spec\_atan}[23]\K7$;\5 +$\\{spec\_atan}[24]\K4$;\5 +$\\{spec\_atan}[25]\K2$;\5 +$\\{spec\_atan}[26]\K1$;\par +\fi + +\M139. Given integers \|x and \|y, not both zero, the \\{n\_arg} function +returns the \\{angle} whose tangent points in the direction $(x,y)$. +This subroutine first determines the correct octant, then solves the +problem for $0\L\|y\L\|x$, then converts the result appropriately to +return an answer in the range $-\\{one\_eighty\_deg}\L\hbox{$\theta$}\L\\{one% +\_eighty\_deg}$. +(The answer is $+\\{one\_eighty\_deg}$ if $\|y=0$ and $\|x<0$, but an answer of +$-\\{one\_eighty\_deg}$ is possible if, for example, $\|y=-1$ and $x=-2^{30}$.) + +The octants are represented in a ``Gray code,'' since that turns out +to be computationally simplest. + +\Y\P\D \37$\\{negate\_x}=1$\par +\P\D \37$\\{negate\_y}=2$\par +\P\D \37$\\{switch\_x\_and\_y}=4$\par +\P\D \37$\\{first\_octant}=1$\par +\P\D \37$\\{second\_octant}=\\{first\_octant}+\\{switch\_x\_and\_y}$\par +\P\D \37$\\{third\_octant}=\\{first\_octant}+\\{switch\_x\_and\_y}+\\{negate% +\_x}$\par +\P\D \37$\\{fourth\_octant}=\\{first\_octant}+\\{negate\_x}$\par +\P\D \37$\\{fifth\_octant}=\\{first\_octant}+\\{negate\_x}+\\{negate\_y}$\par +\P\D \37$\\{sixth\_octant}=\\{first\_octant}+\\{switch\_x\_and\_y}+\\{negate% +\_x}+\\{negate\_y}$\par +\P\D \37$\\{seventh\_octant}=\\{first\_octant}+\\{switch\_x\_and\_y}+\\{negate% +\_y}$\par +\P\D \37$\\{eighth\_octant}=\\{first\_octant}+\\{negate\_y}$\par +\Y\P\4\&{function}\1\ \37$\\{n\_arg}(\|x,\39\|y:\\{integer})$: \37\\{angle};\6 +\4\&{var} \37\|z: \37\\{angle};\C{auxiliary register}\6 +\|t: \37\\{integer};\C{temporary storage}\6 +\|k: \37\\{small\_number};\C{loop counter}\6 +\\{octant}: \37$\\{first\_octant}\to\\{sixth\_octant}$;\C{octant code}\2\6 +\&{begin} \37\&{if} $\|x\G0$ \1\&{then}\5 +$\\{octant}\K\\{first\_octant}$\6 +\4\&{else} \&{begin} \37$\\{negate}(\|x)$;\5 +$\\{octant}\K\\{first\_octant}+\\{negate\_x}$;\6 +\&{end};\2\6 +\&{if} $\|y<0$ \1\&{then}\6 +\&{begin} \37$\\{negate}(\|y)$;\5 +$\\{octant}\K\\{octant}+\\{negate\_y}$;\6 +\&{end};\2\6 +\&{if} $\|x<\|y$ \1\&{then}\6 +\&{begin} \37$\|t\K\|y$;\5 +$\|y\K\|x$;\5 +$\|x\K\|t$;\5 +$\\{octant}\K\\{octant}+\\{switch\_x\_and\_y}$;\6 +\&{end};\2\6 +\&{if} $\|x=0$ \1\&{then}\5 +\X140:Handle undefined arg\X\6 +\4\&{else} \&{begin} \37\X142:Set variable \|z to the arg of $(x,y)$\X;\6 +\X141:Return an appropriate answer based on \|z and \\{octant}\X;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M140. \P$\X140:Handle undefined arg\X\S$\6 +\&{begin} \37$\\{print\_err}(\.{"angle(0,0)\ is\ taken\ as\ zero"})$;\5 +$\\{help2}(\.{"The\ \`angle\'\ between\ two\ identical\ points\ is\ +undefined."})$\6 +$(\.{"I\'m\ zeroing\ this\ one.\ Proceed,\ with\ fingers\ crossed."})$;\5 +\\{error};\5 +$\\{n\_arg}\K0$;\6 +\&{end}\par +\U139.\fi + +\M141. \P$\X141:Return an appropriate answer based on \|z and \\{octant}\X\S$\6 +\&{case} $\\{octant}$ \1\&{of}\6 +\4\\{first\_octant}: \37$\\{n\_arg}\K\|z$;\6 +\4\\{second\_octant}: \37$\\{n\_arg}\K\\{ninety\_deg}-\|z$;\6 +\4\\{third\_octant}: \37$\\{n\_arg}\K\\{ninety\_deg}+\|z$;\6 +\4\\{fourth\_octant}: \37$\\{n\_arg}\K\\{one\_eighty\_deg}-\|z$;\6 +\4\\{fifth\_octant}: \37$\\{n\_arg}\K\|z-\\{one\_eighty\_deg}$;\6 +\4\\{sixth\_octant}: \37$\\{n\_arg}\K-\|z-\\{ninety\_deg}$;\6 +\4\\{seventh\_octant}: \37$\\{n\_arg}\K\|z-\\{ninety\_deg}$;\6 +\4\\{eighth\_octant}: \37$\\{n\_arg}\K-\|z$;\2\6 +\&{end}\C{there are no other cases}\par +\U139.\fi + +\M142. At this point we have $\|x\G\|y\G0$, and $\|x>0$. The numbers are scaled +up +or down until $2^{28}\L x<2^{29}$, so that accurate fixed-point calculations +will be made. + +\Y\P$\4\X142:Set variable \|z to the arg of $(x,y)$\X\S$\6 +\&{while} $\|x\G\\{fraction\_two}$ \1\&{do}\6 +\&{begin} \37$\|x\K\\{half}(\|x)$;\5 +$\|y\K\\{half}(\|y)$;\6 +\&{end};\2\6 +$\|z\K0$;\6 +\&{if} $\|y>0$ \1\&{then}\6 +\&{begin} \37\&{while} $\|x<\\{fraction\_one}$ \1\&{do}\6 +\&{begin} \37$\\{double}(\|x)$;\5 +$\\{double}(\|y)$;\6 +\&{end};\2\6 +\X143:Increase \|z to the arg of $(x,y)$\X;\6 +\&{end}\2\par +\U139.\fi + +\M143. During the calculations of this section, variables \|x and~\|y +represent actual coordinates $(x,2^{-k}y)$. We will maintain the +condition $\|x\G\|y$, so that the tangent will be at most $2^{-k}$. +If $x<2y$, the tangent is greater than $2^{-k-1}$. The transformation +$(a,b)\mapsto(a+b\tan\phi,b-a\tan\phi)$ replaces $(a,b)$ by +coordinates whose angle has decreased by~$\phi$; in the special case +$a=x$, $b=2^{-k}y$, and $\tan\phi=2^{-k-1}$, this operation reduces +to the particularly simple iteration shown here. [Cf.~John E. Meggitt, +{\sl IBM Journal of Research and Development\/ \bf6} (1962), 210--226.] + +The initial value of \|x will be multiplied by at most +$(1+{1\over2})(1+{1\over8})(1+{1\over32})\cdots\approx 1.7584$; hence +there is no chance of integer overflow. + +\Y\P$\4\X143:Increase \|z to the arg of $(x,y)$\X\S$\6 +$\|k\K0$;\6 +\1\&{repeat} \37$\\{double}(\|y)$;\5 +$\\{incr}(\|k)$;\6 +\&{if} $\|y>\|x$ \1\&{then}\6 +\&{begin} \37$\|z\K\|z+\\{spec\_atan}[\|k]$;\5 +$\|t\K\|x$;\5 +$\|x\K\|x+(\|y\mathbin{\&{div}}\\{two\_to\_the}[\|k+\|k])$;\5 +$\|y\K\|y-\|t$;\6 +\&{end};\2\6 +\4\&{until}\5 +$\|k=15$;\2\6 +\1\&{repeat} \37$\\{double}(\|y)$;\5 +$\\{incr}(\|k)$;\6 +\&{if} $\|y>\|x$ \1\&{then}\6 +\&{begin} \37$\|z\K\|z+\\{spec\_atan}[\|k]$;\5 +$\|y\K\|y-\|x$;\6 +\&{end};\2\6 +\4\&{until}\5 +$\|k=26$\2\par +\U142.\fi + +\M144. Conversely, the \\{n\_sin\_cos} routine takes an \\{angle} and produces +the sine +and cosine of that angle. The results of this routine are +stored in global integer variables \\{n\_sin} and \\{n\_cos}. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4$\\{n\_sin},\39\\{n\_cos}$: \37\\{fraction};\C{results computed by \\{n\_sin% +\_cos}}\par +\fi + +\M145. Given an integer \|z that is $2^{20}$ times an angle $\theta$ in +degrees, +the purpose of $\\{n\_sin\_cos}(\|z)$ is to set +$\|x=\hbox{$r\cos\theta$}$ and $\|y=\hbox{$r\sin\theta$}$ (approximately), +for some rather large number~\|r. The maximum of \|x and \|y +will be between $2^{28}$ and $2^{30}$, so that there will be hardly +any loss of accuracy. Then \|x and~\|y are divided by~\|r. + +\Y\P\4\&{procedure}\1\ \37$\\{n\_sin\_cos}(\|z:\\{angle})$;\C{computes a +multiple of the sine and cosine}\6 +\4\&{var} \37\|k: \37\\{small\_number};\C{loop control variable}\6 +\|q: \37$0\to7$;\C{specifies the quadrant}\6 +\|r: \37\\{fraction};\C{magnitude of $(\|x,\|y)$}\6 +$\|x,\39\|y,\39\|t$: \37\\{integer};\C{temporary registers}\2\6 +\&{begin} \37\&{while} $\|z<0$ \1\&{do}\5 +$\|z\K\|z+\\{three\_sixty\_deg}$;\2\6 +$\|z\K\|z\mathbin{\&{mod}}\\{three\_sixty\_deg}$;\C{now $0\L\|z<\\{three\_sixty% +\_deg}$}\6 +$\|q\K\|z\mathbin{\&{div}}\\{forty\_five\_deg}$;\5 +$\|z\K\|z\mathbin{\&{mod}}\\{forty\_five\_deg}$;\5 +$\|x\K\\{fraction\_one}$;\5 +$\|y\K\|x$;\6 +\&{if} $\R\\{odd}(\|q)$ \1\&{then}\5 +$\|z\K\\{forty\_five\_deg}-\|z$;\2\6 +\X147:Subtract angle \|z from $(\|x,\|y)$\X;\6 +\X146:Convert $(\|x,\|y)$ to the octant determined by~\|q\X;\6 +$\|r\K\\{pyth\_add}(\|x,\39\|y)$;\5 +$\\{n\_cos}\K\\{make\_fraction}(\|x,\39\|r)$;\5 +$\\{n\_sin}\K\\{make\_fraction}(\|y,\39\|r)$;\6 +\&{end};\par +\fi + +\M146. In this case the octants are numbered sequentially. + +\Y\P$\4\X146:Convert $(\|x,\|y)$ to the octant determined by~\|q\X\S$\6 +\&{case} $\|q$ \1\&{of}\6 +\40: \37\\{do\_nothing};\6 +\41: \37\&{begin} \37$\|t\K\|x$;\5 +$\|x\K\|y$;\5 +$\|y\K\|t$;\6 +\&{end};\6 +\42: \37\&{begin} \37$\|t\K\|x$;\5 +$\|x\K-\|y$;\5 +$\|y\K\|t$;\6 +\&{end};\6 +\43: \37$\\{negate}(\|x)$;\6 +\44: \37\&{begin} \37$\\{negate}(\|x)$;\5 +$\\{negate}(\|y)$;\6 +\&{end};\6 +\45: \37\&{begin} \37$\|t\K\|x$;\5 +$\|x\K-\|y$;\5 +$\|y\K-\|t$;\6 +\&{end};\6 +\46: \37\&{begin} \37$\|t\K\|x$;\5 +$\|x\K\|y$;\5 +$\|y\K-\|t$;\6 +\&{end};\6 +\47: \37$\\{negate}(\|y)$;\2\6 +\&{end}\C{there are no other cases}\par +\U145.\fi + +\M147. The main iteration of \\{n\_sin\_cos} is similar to that of \\{n\_arg} +but +applied in reverse. The values of $\\{spec\_atan}[\|k]$ decrease slowly enough +that this loop is guaranteed to terminate before the (nonexistent) value +$\\{spec\_atan}[27]$ would be required. + +\Y\P$\4\X147:Subtract angle \|z from $(\|x,\|y)$\X\S$\6 +$\|k\K1$;\6 +\&{while} $\|z>0$ \1\&{do}\6 +\&{begin} \37\&{if} $\|z\G\\{spec\_atan}[\|k]$ \1\&{then}\6 +\&{begin} \37$\|z\K\|z-\\{spec\_atan}[\|k]$;\5 +$\|t\K\|x$;\6 +$\|x\K\|t+\|y\mathbin{\&{div}}\\{two\_to\_the}[\|k]$;\5 +$\|y\K\|y-\|t\mathbin{\&{div}}\\{two\_to\_the}[\|k]$;\6 +\&{end};\2\6 +$\\{incr}(\|k)$;\6 +\&{end};\2\6 +\&{if} $\|y<0$ \1\&{then}\5 +$\|y\K0$\C{this precaution may never be needed}\2\par +\U145.\fi + +\M148. And now let's complete our collection of numeric utility routines +by considering random number generation. +\MF\ generates pseudo-random numbers with the additive scheme recommended +in Section 3.6 of {\sl The Art of Computer Programming}; however, the +results are random fractions between 0 and $\\{fraction\_one}-1$, inclusive. + +There's an auxiliary array \\{randoms} that contains 55 pseudo-random +fractions. Using the recurrence $x_n=(x_{n-55}-x_{n-24})\bmod 2^{28}$, +we generate batches of 55 new $x_n$'s at a time by calling \\{new\_randoms}. +The global variable \\{j\_random} tells which element has most recently +been consumed. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{randoms}: \37\&{array} $[0\to54]$ \1\&{of}\5 +\\{fraction};\C{the last 55 random values generated}\2\6 +\4\\{j\_random}: \37$0\to54$;\C{the number of unused \\{randoms}}\par +\fi + +\M149. To consume a random fraction, the program below will say `\\{next% +\_random}' +and then it will fetch $\\{randoms}[\\{j\_random}]$. The \\{next\_random} macro +actually accesses the numbers backwards; blocks of 55~$x$'s are +essentially being ``flipped.'' But that doesn't make them less random. + +\Y\P\D \37$\\{next\_random}\S$\1\6 +\&{if} $\\{j\_random}=0$ \1\&{then}\5 +\\{new\_randoms}\6 +\4\&{else} $\\{decr}(\\{j\_random})$\2\2\par +\Y\P\4\&{procedure}\1\ \37\\{new\_randoms};\6 +\4\&{var} \37\|k: \37$0\to54$;\C{index into \\{randoms}}\6 +\|x: \37\\{fraction};\C{accumulator}\2\6 +\&{begin} \37\&{for} $\|k\K0\mathrel{\&{to}}23$ \1\&{do}\6 +\&{begin} \37$\|x\K\\{randoms}[\|k]-\\{randoms}[\|k+31]$;\6 +\&{if} $\|x<0$ \1\&{then}\5 +$\|x\K\|x+\\{fraction\_one}$;\2\6 +$\\{randoms}[\|k]\K\|x$;\6 +\&{end};\2\6 +\&{for} $\|k\K24\mathrel{\&{to}}54$ \1\&{do}\6 +\&{begin} \37$\|x\K\\{randoms}[\|k]-\\{randoms}[\|k-24]$;\6 +\&{if} $\|x<0$ \1\&{then}\5 +$\|x\K\|x+\\{fraction\_one}$;\2\6 +$\\{randoms}[\|k]\K\|x$;\6 +\&{end};\2\6 +$\\{j\_random}\K54$;\6 +\&{end};\par +\fi + +\M150. To initialize the \\{randoms} table, we call the following routine. + +\Y\P\4\&{procedure}\1\ \37$\\{init\_randoms}(\\{seed}:\\{scaled})$;\6 +\4\&{var} \37$\|j,\39\\{jj},\39\|k$: \37\\{fraction};\C{more or less random +integers}\6 +\|i: \37$0\to54$;\C{index into \\{randoms}}\2\6 +\&{begin} \37$\|j\K\\{abs}(\\{seed})$;\6 +\&{while} $\|j\G\\{fraction\_one}$ \1\&{do}\5 +$\|j\K\\{half}(\|j)$;\2\6 +$\|k\K1$;\6 +\&{for} $\|i\K0\mathrel{\&{to}}54$ \1\&{do}\6 +\&{begin} \37$\\{jj}\K\|k$;\5 +$\|k\K\|j-\|k$;\5 +$\|j\K\\{jj}$;\6 +\&{if} $\|k<0$ \1\&{then}\5 +$\|k\K\|k+\\{fraction\_one}$;\2\6 +$\\{randoms}[(\|i\ast21)\mathbin{\&{mod}}55]\K\|j$;\6 +\&{end};\2\6 +\\{new\_randoms};\5 +\\{new\_randoms};\5 +\\{new\_randoms};\C{``warm up'' the array}\6 +\&{end};\par +\fi + +\M151. To produce a uniform random number in the range $0\L\|u<\|x$ or $0\G\|u>% +\|x$ +or $0=\|u=\|x$, given a \\{scaled} value~\|x, we proceed as shown here. + +Note that the call of \\{take\_fraction} will produce the values 0 and~\|x +with about half the probability that it will produce any other particular +values between 0 and~\|x, because it rounds its answers. + +\Y\P\4\&{function}\1\ \37$\\{unif\_rand}(\|x:\\{scaled})$: \37\\{scaled};\6 +\4\&{var} \37\|y: \37\\{scaled};\C{trial value}\2\6 +\&{begin} \37\\{next\_random};\5 +$\|y\K\\{take\_fraction}(\\{abs}(\|x),\39\\{randoms}[\\{j\_random}])$;\6 +\&{if} $\|y=\\{abs}(\|x)$ \1\&{then}\5 +$\\{unif\_rand}\K0$\6 +\4\&{else} \&{if} $\|x>0$ \1\&{then}\5 +$\\{unif\_rand}\K\|y$\6 +\4\&{else} $\\{unif\_rand}\K-\|y$;\2\2\6 +\&{end};\par +\fi + +\M152. Finally, a normal deviate with mean zero and unit standard deviation +can readily be obtained with the ratio method (Algorithm 3.4.1R in +{\sl The Art of Computer Programming\/}). + +\Y\P\4\&{function}\1\ \37\\{norm\_rand}: \37\\{scaled};\6 +\4\&{var} \37$\|x,\39\|u,\39\|l$: \37\\{integer};\C{what the book would call +$2^{16}X$, $2^{28}U$, and $-2^{24}\ln U$}\2\6 +\&{begin} \37\1\&{repeat} \37\1\&{repeat} \37\\{next\_random};\5 +$\|x\K\\{take\_fraction}(112429,\39\\{randoms}[\\{j\_random}]-\\{fraction% +\_half})$;\C{$2^{16}\sqrt{8/e}\approx 112428.82793$}\6 +\\{next\_random};\5 +$\|u\K\\{randoms}[\\{j\_random}]$;\6 +\4\&{until}\5 +$\\{abs}(\|x)<\|u$;\2\6 +$\|x\K\\{make\_fraction}(\|x,\39\|u)$;\5 +$\|l\K139548960-\\{m\_log}(\|u)$;\C{$2^{24}\cdot12\ln2\approx139548959.6165$}\6 +\4\&{until}\5 +$\\{ab\_vs\_cd}(1024,\39\|l,\39\|x,\39\|x)\G0$;\2\6 +$\\{norm\_rand}\K\|x$;\6 +\&{end};\par +\fi + +\N153. \[9] Packed data. +In order to make efficient use of storage space, \MF\ bases its major data +structures on a \\{memory\_word}, which contains either a (signed) integer, +possibly scaled, or a small number of fields that are one half or one +quarter of the size used for storing integers. + +If \|x is a variable of type \\{memory\_word}, it contains up to four +fields that can be referred to as follows: +$$\vbox{\halign{\hfil#&#\hfil&#\hfil\cr +\|x&.\\{int}&(an \\{integer})\cr +\|x&.\\{sc}\qquad&(a \\{scaled} integer)\cr +\|x.\\{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. \MF\ 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. + +N.B.: Valuable memory space will be dreadfully wasted unless \MF\ is compiled +by a \PASCAL\ that packs all of the \\{memory\_word} variants into +the space of a single integer. Some \PASCAL\ compilers will pack an +integer whose subrange is `$0\to255$' into an eight-bit field, but others +insist on allocating space for an additional sign bit; on such systems you +can get 256 values into a quarterword only if the subrange is `$-128\to127$'. + +The present implementation tries to accommodate as many variations as possible, +so it makes few assumptions. If integers having the subrange +`$\\{min\_quarterword}\to\\{max\_quarterword}$' can be packed into a +quarterword, +and if integers having the subrange `$\\{min\_halfword}\to\\{max\_halfword}$' +can be packed into a halfword, everything should work satisfactorily. + +It is usually most efficient to have $\\{min\_quarterword}=\\{min% +\_halfword}=0$, +so one should try to achieve this unless it causes a severe problem. +The values defined here are recommended for most 32-bit computers. + +\Y\P\D \37$\\{min\_quarterword}=0$\C{smallest allowable value in a % +\\{quarterword}}\par +\P\D \37$\\{max\_quarterword}=255$\C{largest allowable value in a % +\\{quarterword}}\par +\P\D \37$\\{min\_halfword}\S0$\C{smallest allowable value in a \\{halfword}}\par +\P\D \37$\\{max\_halfword}\S65535$\C{largest allowable value in a \\{halfword}}% +\par +\fi + +\M154. Here are the inequalities that the quarterword and halfword values +must satisfy (or rather, the inequalities that they mustn't satisfy): + +\Y\P$\4\X14:Check the ``constant'' values for consistency\X\mathrel{+}\S$\6 +\&{init} \37\&{if} $\\{mem\_max}\I\\{mem\_top}$ \1\&{then}\5 +$\\{bad}\K10$;\ \2\6 +\&{tini}\6 +\&{if} $\\{mem\_max}<\\{mem\_top}$ \1\&{then}\5 +$\\{bad}\K10$;\2\6 +\&{if} $(\\{min\_quarterword}>0)\V(\\{max\_quarterword}<127)$ \1\&{then}\5 +$\\{bad}\K11$;\2\6 +\&{if} $(\\{min\_halfword}>0)\V(\\{max\_halfword}<32767)$ \1\&{then}\5 +$\\{bad}\K12$;\2\6 +\&{if} $(\\{min\_quarterword}<\\{min\_halfword})\V\30(\\{max\_quarterword}>% +\\{max\_halfword})$ \1\&{then}\5 +$\\{bad}\K13$;\2\6 +\&{if} $(\\{mem\_min}<\\{min\_halfword})\V(\\{mem\_max}\G\\{max\_halfword})$ \1% +\&{then}\5 +$\\{bad}\K14$;\2\6 +\&{if} $\\{max\_strings}>\\{max\_halfword}$ \1\&{then}\5 +$\\{bad}\K15$;\2\6 +\&{if} $\\{buf\_size}>\\{max\_halfword}$ \1\&{then}\5 +$\\{bad}\K16$;\2\6 +\&{if} $(\\{max\_quarterword}-\\{min\_quarterword}<255)\V\30(\\{max\_halfword}-% +\\{min\_halfword}<65535)$ \1\&{then}\5 +$\\{bad}\K17$;\2\par +\fi + +\M155. The operation of subtracting \\{min\_halfword} occurs rather frequently +in +\MF, so it is convenient to abbreviate this operation by using the macro +\\{ho} defined here. \MF\ will run faster with respect to compilers that +don't optimize the expression `$\|x-0$', if this macro is simplified in the +obvious way when $\\{min\_halfword}=0$. Similarly, \\{qi} and \\{qo} are used +for +input to and output from quarterwords. + +\Y\P\D \37$\\{ho}(\#)\S\#-\\{min\_halfword}$\C{to take a sixteen-bit item from +a halfword}\par +\P\D \37$\\{qo}(\#)\S\#-\\{min\_quarterword}$\C{to read eight bits from a +quarterword}\par +\P\D \37$\\{qi}(\#)\S\#+\\{min\_quarterword}$\C{to store eight bits in a +quarterword}\par +\fi + +\M156. The reader should study the following definitions closely: + +\Y\P\D \37$\\{sc}\S\\{int}$\C{\\{scaled} data is equivalent to \\{integer}}\par +\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6 +$\\{quarterword}=\\{min\_quarterword}\to\\{max\_quarterword}$;\C{1/4 of a word}% +\6 +$\\{halfword}=\\{min\_halfword}\to\\{max\_halfword}$;\C{1/2 of a word}\6 +$\\{two\_choices}=1\to2$;\C{used when there are two variants in a record}\6 +$\\{three\_choices}=1\to3$;\C{used when there are three variants in a record}\6 +$\\{two\_halves}=$\1\5 +\&{packed} \37\1\&{record} \37\\{rh}: \37\\{halfword};\2\6 +\&{case} $\\{two\_choices}$ \1\&{of}\6 +\41: \37$(\\{lh}:\\{halfword})$;\6 +\42: \37$(\\{b0}:\\{quarterword};\,\35\\{b1}:\\{quarterword})$;\2\6 +\&{end};\2\6 +$\\{four\_quarters}=$\1\5 +\&{packed} \37\1\&{record} \37\\{b0}: \37\\{quarterword};\6 +\4\\{b1}: \37\\{quarterword};\6 +\4\\{b2}: \37\\{quarterword};\6 +\4\\{b3}: \37\\{quarterword};\2\6 +\&{end};\2\6 +$\\{memory\_word}=$\1\5 +\1\&{record} \37\2\6 +\&{case} $\\{three\_choices}$ \1\&{of}\6 +\41: \37$(\\{int}:\\{integer})$;\6 +\42: \37$(\\{hh}:\\{two\_halves})$;\6 +\43: \37$(\\{qqqq}:\\{four\_quarters})$;\2\6 +\&{end};\2\6 +$\\{word\_file}=$\1\5 +\&{file} \1\&{of}\5 +\\{memory\_word};\2\2\par +\fi + +\M157. When debugging, we may want to print a \\{memory\_word} without knowing +what type it is; so we print it in all modes. + +\Y\P\&{debug} \37\&{procedure}\1\ \37$\\{print\_word}(\|w:\\{memory\_word})$;% +\C{prints \|w in all ways}\2\6 +\&{begin} \37$\\{print\_int}(\|w.\\{int})$;\5 +$\\{print\_char}(\.{"\ "})$;\6 +$\\{print\_scaled}(\|w.\\{sc})$;\5 +$\\{print\_char}(\.{"\ "})$;\5 +$\\{print\_scaled}(\|w.\\{sc}\mathbin{\&{div}}\O{10000})$;\5 +\\{print\_ln};\6 +$\\{print\_int}(\|w.\\{hh}.\\{lh})$;\5 +$\\{print\_char}(\.{"="})$;\5 +$\\{print\_int}(\|w.\\{hh}.\\{b0})$;\5 +$\\{print\_char}(\.{":"})$;\5 +$\\{print\_int}(\|w.\\{hh}.\\{b1})$;\5 +$\\{print\_char}(\.{";"})$;\5 +$\\{print\_int}(\|w.\\{hh}.\\{rh})$;\5 +$\\{print\_char}(\.{"\ "})$;\6 +$\\{print\_int}(\|w.\\{qqqq}.\\{b0})$;\5 +$\\{print\_char}(\.{":"})$;\5 +$\\{print\_int}(\|w.\\{qqqq}.\\{b1})$;\5 +$\\{print\_char}(\.{":"})$;\5 +$\\{print\_int}(\|w.\\{qqqq}.\\{b2})$;\5 +$\\{print\_char}(\.{":"})$;\5 +$\\{print\_int}(\|w.\\{qqqq}.\\{b3})$;\6 +\&{end};\6 +\&{gubed}\par +\fi + +\N158. \[10] Dynamic memory allocation. +The \MF\ 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 \MF\ are handled by providing a large array \\{mem} in +which consecutive blocks of words are used as nodes by the \MF\ 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 memory +index represents a null pointer. + +\Y\P\D \37$\\{pointer}\S\\{halfword}$\C{a flag or a location in \\{mem} or % +\\{eqtb}}\par +\P\D \37$\\{null}\S\\{mem\_min}$\C{the null pointer}\par +\fi + +\M159. 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\_min} and \\{mem\_top} may be dumped as +part +of preloaded format files, by the \.{INIMF} preprocessor. +Production versions of \MF\ may extend the memory at the top end in order to +provide more space; these 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: +$$\hbox{$\\{null}=\\{mem\_min}<\\{lo\_mem\_max}<\\{hi\_mem\_min}<\\{mem\_top}\L% +\\{mem\_end}\L\\{mem\_max}$.}$$ + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{mem}: \37\&{array} $[\\{mem\_min}\to\\{mem\_max}]$ \1\&{of}\5 +\\{memory\_word};\C{the big dynamic storage area}\2\6 +\4\\{lo\_mem\_max}: \37\\{pointer};\C{the largest location of variable-size +memory in use}\6 +\4\\{hi\_mem\_min}: \37\\{pointer};\C{the smallest location of one-word memory +in use}\par +\fi + +\M160. Users who wish to study the memory requirements of specific applications +can +use optional special features that keep track of current and +maximum memory usage. When code between the delimiters \&{stat} $\ldots$ + \&{tats} is not ``commented out,'' \MF\ will run a bit slower but it will +report these statistics when \\{tracing\_stats} is positive. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4$\\{var\_used},\39\\{dyn\_used}$: \37\\{integer};\C{how much memory is in +use}\par +\fi + +\M161. Let's consider the one-word memory region first, since it's the +simplest. The pointer variable \\{mem\_end} holds the highest-numbered location +of \\{mem} that has ever been used. The free locations of \\{mem} that +occur between \\{hi\_mem\_min} and \\{mem\_end}, inclusive, are of type +\\{two\_halves}, and we write $\\{info}(\|p)$ and $\\{link}(\|p)$ for the % +\\{lh} +and \\{rh} fields of $\\{mem}[\|p]$ when it is of this type. The single-word +free locations form a linked list +$$\\{avail},\;\hbox{$\\{link}(\\{avail})$},\;\hbox{$\\{link}(\\{link}(% +\\{avail}))$},\;\ldots$$ +terminated by \\{null}. + +\Y\P\D \37$\\{link}(\#)\S\\{mem}[\#].\\{hh}.\\{rh}$\C{the \\{link} field of a +memory word}\par +\P\D \37$\\{info}(\#)\S\\{mem}[\#].\\{hh}.\\{lh}$\C{the \\{info} field of a +memory word}\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{avail}: \37\\{pointer};\C{head of the list of available one-word nodes}\6 +\4\\{mem\_end}: \37\\{pointer};\C{the last one-word node used in \\{mem}}\par +\fi + +\M162. If one-word memory is exhausted, it might mean that the user has +forgotten +a token like `\&{enddef}' or `\&{endfor}'. We will define some procedures +later that try to help pinpoint the trouble. + +\Y\P\hbox{\4}\X217:Declare the procedure called \\{show\_token\_list}\X\6 +\hbox{\4}\X665:Declare the procedure called \\{runaway}\X\par +\fi + +\M163. The function \\{get\_avail} returns a pointer to a new one-word node +whose +\\{link} field is null. However, \MF\ will halt if there is no more room left. + +\Y\P\4\&{function}\1\ \37\\{get\_avail}: \37\\{pointer};\C{single-word node +allocation}\6 +\4\&{var} \37\|p: \37\\{pointer};\C{the new node being got}\2\6 +\&{begin} \37$\|p\K\\{avail}$;\C{get top location in the \\{avail} stack}\6 +\&{if} $\|p\I\\{null}$ \1\&{then}\5 +$\\{avail}\K\\{link}(\\{avail})$\C{and pop it off}\6 +\4\&{else} \&{if} $\\{mem\_end}<\\{mem\_max}$ \1\&{then}\C{or go into virgin +territory}\6 +\&{begin} \37$\\{incr}(\\{mem\_end})$;\5 +$\|p\K\\{mem\_end}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{decr}(\\{hi\_mem\_min})$;\5 +$\|p\K\\{hi\_mem\_min}$;\6 +\&{if} $\\{hi\_mem\_min}\L\\{lo\_mem\_max}$ \1\&{then}\6 +\&{begin} \37\\{runaway};\C{if memory is exhausted, display possible runaway +text}\6 +$\\{overflow}(\.{"main\ memory\ size"},\39\\{mem\_max}+1-\\{mem\_min})$;% +\C{quit; all one-word nodes are busy}\6 +\&{end};\2\6 +\&{end};\2\2\6 +$\\{link}(\|p)\K\\{null}$;\C{provide an oft-desired initialization of the new +node}\6 +\&{stat} \37$\\{incr}(\\{dyn\_used})$;\ \&{tats}\C{maintain statistics}\6 +$\\{get\_avail}\K\|p$;\6 +\&{end};\par +\fi + +\M164. Conversely, a one-word node is recycled by calling \\{free\_avail}. + +\Y\P\D \37$\\{free\_avail}(\#)\S$\C{single-word node liberation}\6 +\&{begin} \37$\\{link}(\#)\K\\{avail}$;\5 +$\\{avail}\K\#$;\6 +\&{stat} \37$\\{decr}(\\{dyn\_used})$;\ \&{tats}\6 +\&{end}\par +\fi + +\M165. There's also a \\{fast\_get\_avail} routine, which saves the +procedure-call +overhead at the expense of extra programming. This macro is used in +the places that would otherwise account for the most calls of \\{get\_avail}. + +\Y\P\D \37$\\{fast\_get\_avail}(\#)\S\hbox{}$\6 +\&{begin} \37$\#\K\\{avail}$;\C{avoid \\{get\_avail} if possible, to save time}% +\6 +\&{if} $\#=\\{null}$ \1\&{then}\5 +$\#\K\\{get\_avail}$\6 +\4\&{else} \&{begin} \37$\\{avail}\K\\{link}(\#)$;\5 +$\\{link}(\#)\K\\{null}$;\6 +\&{stat} \37$\\{incr}(\\{dyn\_used})$;\ \&{tats}\6 +\&{end};\2\6 +\&{end}\par +\fi + +\M166. The available-space list that keeps track of the variable-size portion +of \\{mem} is a nonempty, doubly-linked circular list of empty nodes, +pointed to by the roving pointer \\{rover}. + +Each empty node has size 2 or more; the first word contains the special +value \\{max\_halfword} in its \\{link} field and the size in its \\{info} +field; +the second word contains the two pointers for double linking. + +Each nonempty node also has size 2 or more. Its first word is of type +\\{two\_halves}\kern-1pt, and its \\{link} field is never equal to \\{max% +\_halfword}. +Otherwise there is complete flexibility with respect to the contents +of its other fields and its other words. + +(We require $\\{mem\_max}<\\{max\_halfword}$ because terrible things can happen +when \\{max\_halfword} appears in the \\{link} field of a nonempty node.) + +\Y\P\D \37$\\{empty\_flag}\S\\{max\_halfword}$\C{the \\{link} of an empty +variable-size node}\par +\P\D \37$\\{is\_empty}(\#)\S(\\{link}(\#)=\\{empty\_flag})$\C{tests for empty +node}\par +\P\D \37$\\{node\_size}\S\\{info}$\C{the size field in empty variable-size +nodes}\par +\P\D \37$\\{llink}(\#)\S\\{info}(\#+1)$\C{left link in doubly-linked list of +empty nodes}\par +\P\D \37$\\{rlink}(\#)\S\\{link}(\#+1)$\C{right link in doubly-linked list of +empty nodes}\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{rover}: \37\\{pointer};\C{points to some node in the list of empties}\par +\fi + +\M167. A call to \\{get\_node} with argument \|s returns a pointer to a new +node +of size~\|s, which must be 2~or more. The \\{link} field of the first word +of this new node is set to null. An overflow stop occurs if no suitable +space exists. + +If \\{get\_node} is called with $s=2^{30}$, it simply merges adjacent free +areas and returns the value \\{max\_halfword}. + +\Y\P\4\&{function}\1\ \37$\\{get\_node}(\|s:\\{integer})$: \37\\{pointer};% +\C{variable-size node allocation}\6 +\4\&{label} \37$\\{found},\39\\{exit},\39\\{restart}$;\6 +\4\&{var} \37\|p: \37\\{pointer};\C{the node currently under inspection}\6 +\|q: \37\\{pointer};\C{the node physically after node \|p}\6 +\|r: \37\\{integer};\C{the newly allocated node, or a candidate for this honor}% +\6 +$\|t,\39\\{tt}$: \37\\{integer};\C{temporary registers}\2\6 +\&{begin} \37\\{restart}: \37$\|p\K\\{rover}$;\C{start at some free node in the +ring}\6 +\1\&{repeat} \37\X169:Try to allocate within node \|p and its physical +successors, and \&{goto} \\{found} if allocation was possible\X;\6 +$\|p\K\\{rlink}(\|p)$;\C{move to the next node in the ring}\6 +\4\&{until}\5 +$\|p=\\{rover}$;\C{repeat until the whole list has been traversed}\2\6 +\&{if} $\|s=\O{10000000000}$ \1\&{then}\6 +\&{begin} \37$\\{get\_node}\K\\{max\_halfword}$;\5 +\&{return};\6 +\&{end};\2\6 +\&{if} $\\{lo\_mem\_max}+2<\\{hi\_mem\_min}$ \1\&{then}\6 +\&{if} $\\{lo\_mem\_max}+2\L\\{mem\_min}+\\{max\_halfword}$ \1\&{then}\5 +\X168:Grow more variable-size memory and \&{goto} \\{restart}\X;\2\2\6 +$\\{overflow}(\.{"main\ memory\ size"},\39\\{mem\_max}+1-\\{mem\_min})$;% +\C{sorry, nothing satisfactory is left}\6 +\4\\{found}: \37$\\{link}(\|r)\K\\{null}$;\C{this node is now nonempty}\6 +\&{stat} \37$\\{var\_used}\K\\{var\_used}+\|s$;\C{maintain usage statistics}\6 +\&{tats}\6 +$\\{get\_node}\K\|r$;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M168. 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 \MF\ is +implemented on ``virtual memory'' systems. + +\Y\P$\4\X168:Grow more variable-size memory and \&{goto} \\{restart}\X\S$\6 +\&{begin} \37\&{if} $\\{hi\_mem\_min}-\\{lo\_mem\_max}\G1998$ \1\&{then}\5 +$\|t\K\\{lo\_mem\_max}+1000$\6 +\4\&{else} $\|t\K\\{lo\_mem\_max}+1+(\\{hi\_mem\_min}-\\{lo\_mem\_max})% +\mathbin{\&{div}}2$;\C{$\\{lo\_mem\_max}+2\L\|t<\\{hi\_mem\_min}$}\2\6 +\&{if} $\|t>\\{mem\_min}+\\{max\_halfword}$ \1\&{then}\5 +$\|t\K\\{mem\_min}+\\{max\_halfword}$;\2\6 +$\|p\K\\{llink}(\\{rover})$;\5 +$\|q\K\\{lo\_mem\_max}$;\5 +$\\{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\|t-\\{lo\_mem\_max}$;\6 +$\\{lo\_mem\_max}\K\|t$;\5 +$\\{link}(\\{lo\_mem\_max})\K\\{null}$;\5 +$\\{info}(\\{lo\_mem\_max})\K\\{null}$;\5 +$\\{rover}\K\|q$;\5 +\&{goto} \37\\{restart};\6 +\&{end}\par +\U167.\fi + +\M169. \P$\X169:Try to allocate within node \|p and its physical successors, +and \&{goto} \\{found} if allocation was possible\X\S$\6 +$\|q\K\|p+\\{node\_size}(\|p)$;\C{find the physical successor}\6 +\&{while} $\\{is\_empty}(\|q)$ \1\&{do}\C{merge node \|p with node \|q}\6 +\&{begin} \37$\|t\K\\{rlink}(\|q)$;\5 +$\\{tt}\K\\{llink}(\|q)$;\6 +\&{if} $\|q=\\{rover}$ \1\&{then}\5 +$\\{rover}\K\|t$;\2\6 +$\\{llink}(\|t)\K\\{tt}$;\5 +$\\{rlink}(\\{tt})\K\|t$;\6 +$\|q\K\|q+\\{node\_size}(\|q)$;\6 +\&{end};\2\6 +$\|r\K\|q-\|s$;\6 +\&{if} $\|r>\|p+1$ \1\&{then}\5 +\X170:Allocate from the top of node \|p and \&{goto} \\{found}\X;\2\6 +\&{if} $\|r=\|p$ \1\&{then}\6 +\&{if} $\\{rlink}(\|p)\I\|p$ \1\&{then}\5 +\X171: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 +\U167.\fi + +\M170. \P$\X170:Allocate from the top of node \|p and \&{goto} \\{found}\X\S$\6 +\&{begin} \37$\\{node\_size}(\|p)\K\|r-\|p$;\C{store the remaining size}\6 +$\\{rover}\K\|p$;\C{start searching here next time}\6 +\&{goto} \37\\{found};\6 +\&{end}\par +\U169.\fi + +\M171. Here we delete node \|p from the ring, and let \\{rover} rove around. + +\Y\P$\4\X171:Allocate entire node \|p and \&{goto} \\{found}\X\S$\6 +\&{begin} \37$\\{rover}\K\\{rlink}(\|p)$;\5 +$\|t\K\\{llink}(\|p)$;\5 +$\\{llink}(\\{rover})\K\|t$;\5 +$\\{rlink}(\|t)\K\\{rover}$;\5 +\&{goto} \37\\{found};\6 +\&{end}\par +\U169.\fi + +\M172. Conversely, when some variable-size node \|p of size \|s is no longer +needed, +the operation $\\{free\_node}(\|p,\|s)$ will make its words available, by +inserting +\|p as a new empty node just before where \\{rover} now points. + +\Y\P\4\&{procedure}\1\ \37$\\{free\_node}(\|p:\\{pointer};\,\35\|s:% +\\{halfword})$;\C{variable-size node liberation}\6 +\4\&{var} \37\|q: \37\\{pointer};\C{$\\{llink}(\\{rover})$}\2\6 +\&{begin} \37$\\{node\_size}(\|p)\K\|s$;\5 +$\\{link}(\|p)\K\\{empty\_flag}$;\5 +$\|q\K\\{llink}(\\{rover})$;\5 +$\\{llink}(\|p)\K\|q$;\5 +$\\{rlink}(\|p)\K\\{rover}$;\C{set both links}\6 +$\\{llink}(\\{rover})\K\|p$;\5 +$\\{rlink}(\|q)\K\|p$;\C{insert \|p into the ring}\6 +\&{stat} \37$\\{var\_used}\K\\{var\_used}-\|s$;\ \&{tats}\C{maintain +statistics}\6 +\&{end};\par +\fi + +\M173. Just before \.{INIMF} writes out the memory, it sorts the doubly linked +available space list. The list is probably very short at such times, so a +simple insertion sort is used. The smallest available location will be +pointed to by \\{rover}, the next-smallest by $\\{rlink}(\\{rover})$, etc. + +\Y\P\&{init} \37\&{procedure}\1\ \37\\{sort\_avail};\C{sorts the available +variable-size nodes by location}\6 +\4\&{var} \37$\|p,\39\|q,\39\|r$: \37\\{pointer};\C{indices into \\{mem}}\6 +\\{old\_rover}: \37\\{pointer};\C{initial \\{rover} setting}\2\6 +\&{begin} \37$\|p\K\\{get\_node}(\O{10000000000})$;\C{merge adjacent free +areas}\6 +$\|p\K\\{rlink}(\\{rover})$;\5 +$\\{rlink}(\\{rover})\K\\{max\_halfword}$;\5 +$\\{old\_rover}\K\\{rover}$;\6 +\&{while} $\|p\I\\{old\_rover}$ \1\&{do}\5 +\X174:Sort \|p into the list starting at \\{rover} and advance \|p to $% +\\{rlink}(\|p)$\X;\2\6 +$\|p\K\\{rover}$;\6 +\&{while} $\\{rlink}(\|p)\I\\{max\_halfword}$ \1\&{do}\6 +\&{begin} \37$\\{llink}(\\{rlink}(\|p))\K\|p$;\5 +$\|p\K\\{rlink}(\|p)$;\6 +\&{end};\2\6 +$\\{rlink}(\|p)\K\\{rover}$;\5 +$\\{llink}(\\{rover})\K\|p$;\6 +\&{end};\6 +\&{tini}\par +\fi + +\M174. The following \&{while} loop is guaranteed to +terminate, since the list that starts at +\\{rover} ends with \\{max\_halfword} during the sorting procedure. + +\Y\P$\4\X174:Sort \|p into the list starting at \\{rover} and advance \|p to $% +\\{rlink}(\|p)$\X\S$\6 +\&{if} $\|p<\\{rover}$ \1\&{then}\6 +\&{begin} \37$\|q\K\|p$;\5 +$\|p\K\\{rlink}(\|q)$;\5 +$\\{rlink}(\|q)\K\\{rover}$;\5 +$\\{rover}\K\|q$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|q\K\\{rover}$;\6 +\&{while} $\\{rlink}(\|q)<\|p$ \1\&{do}\5 +$\|q\K\\{rlink}(\|q)$;\2\6 +$\|r\K\\{rlink}(\|p)$;\5 +$\\{rlink}(\|p)\K\\{rlink}(\|q)$;\5 +$\\{rlink}(\|q)\K\|p$;\5 +$\|p\K\|r$;\6 +\&{end}\2\par +\U173.\fi + +\N175. \[11] Memory layout. +Some areas of \\{mem} are dedicated to fixed usage, since static allocation is +more efficient than dynamic allocation when we can get away with it. For +example, locations \\{mem\_min} to $\\{mem\_min}+2$ are always used to store +the +specification for null pen coordinates that are `$(0,0)$'. The +following macro definitions accomplish the static allocation by giving +symbolic names to the fixed positions. Static variable-size nodes appear +in locations \\{mem\_min} through \\{lo\_mem\_stat\_max}, and static +single-word nodes +appear in locations \\{hi\_mem\_stat\_min} through \\{mem\_top}, inclusive. + +\Y\P\D \37$\\{null\_coords}\S\\{mem\_min}$\C{specification for pen offsets of +$(0,0)$}\par +\P\D \37$\\{null\_pen}\S\\{null\_coords}+3$\C{we will define $\\{coord\_node% +\_size}=3$}\par +\P\D \37$\\{dep\_head}\S\\{null\_pen}+10$\C{and $\\{pen\_node\_size}=10$}\par +\P\D \37$\\{zero\_val}\S\\{dep\_head}+2$\C{two words for a permanently zero +value}\par +\P\D \37$\\{temp\_val}\S\\{zero\_val}+2$\C{two words for a temporary value +node}\par +\P\D \37$\\{end\_attr}\S\\{temp\_val}$\C{we use $\\{end\_attr}+2$ only}\par +\P\D \37$\\{inf\_val}\S\\{end\_attr}+2$\C{and $\\{inf\_val}+1$ only}\par +\P\D \37$\\{bad\_vardef}\S\\{inf\_val}+2$\C{two words for \&{vardef} error +recovery}\par +\P\D \37$\\{lo\_mem\_stat\_max}\S\\{bad\_vardef}+1$\C{largest statically +allocated word in the variable-size \\{mem}}\Y\par +\P\D \37$\\{sentinel}\S\\{mem\_top}$\C{end of sorted lists}\par +\P\D \37$\\{temp\_head}\S\\{mem\_top}-1$\C{head of a temporary list of some +kind}\par +\P\D \37$\\{hold\_head}\S\\{mem\_top}-2$\C{head of a temporary list of another +kind}\par +\P\D \37$\\{hi\_mem\_stat\_min}\S\\{mem\_top}-2$\C{smallest statically +allocated word in the one-word \\{mem}}\par +\fi + +\M176. The following code gets the dynamic part of \\{mem} off to a good start, +when \MF\ is initializing itself the slow way. + +\Y\P$\4\X176:Initialize table entries (done by \.{INIMF} only)\X\S$\6 +$\\{rover}\K\\{lo\_mem\_stat\_max}+1$;\C{initialize the dynamic memory}\6 +$\\{link}(\\{rover})\K\\{empty\_flag}$;\5 +$\\{node\_size}(\\{rover})\K1000$;\C{which is a 1000-word available node}\6 +$\\{llink}(\\{rover})\K\\{rover}$;\5 +$\\{rlink}(\\{rover})\K\\{rover}$;\6 +$\\{lo\_mem\_max}\K\\{rover}+1000$;\5 +$\\{link}(\\{lo\_mem\_max})\K\\{null}$;\5 +$\\{info}(\\{lo\_mem\_max})\K\\{null}$;\6 +\&{for} $\|k\K\\{hi\_mem\_stat\_min}\mathrel{\&{to}}\\{mem\_top}$ \1\&{do}\5 +$\\{mem}[\|k]\K\\{mem}[\\{lo\_mem\_max}]$;\C{clear list heads}\2\6 +$\\{avail}\K\\{null}$;\5 +$\\{mem\_end}\K\\{mem\_top}$;\5 +$\\{hi\_mem\_min}\K\\{hi\_mem\_stat\_min}$;\C{initialize the one-word memory}\6 +$\\{var\_used}\K\\{lo\_mem\_stat\_max}+1-\\{mem\_min}$;\5 +$\\{dyn\_used}\K\\{mem\_top}+1-\\{hi\_mem\_min}$;\C{initialize statistics}\par +\As193, 203, 229, 324, 475, 587, 702, 759, 911, 1116, 1127\ETs1185. +\U1210.\fi + +\M177. The procedure $\\{flush\_list}(\|p)$ frees an entire linked list of +one-word +nodes that starts at a given position, until coming to \\{sentinel} or a +pointer that is not in the one-word region. Another procedure, +\\{flush\_node\_list}, frees an entire linked list of one-word and two-word +nodes, until coming to a \\{null} pointer. + +\Y\P\4\&{procedure}\1\ \37$\\{flush\_list}(\|p:\\{pointer})$;\C{makes list of +single-word nodes available}\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37$\|q,\39\|r$: \37\\{pointer};\C{list traversers}\2\6 +\&{begin} \37\&{if} $\|p\G\\{hi\_mem\_min}$ \1\&{then}\6 +\&{if} $\|p\I\\{sentinel}$ \1\&{then}\6 +\&{begin} \37$\|r\K\|p$;\6 +\1\&{repeat} \37$\|q\K\|r$;\5 +$\|r\K\\{link}(\|r)$;\6 +\&{stat} \37$\\{decr}(\\{dyn\_used})$;\ \&{tats}\6 +\&{if} $\|r<\\{hi\_mem\_min}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +\4\&{until}\5 +$\|r=\\{sentinel}$;\2\6 +\4\\{done}: \37\C{now \|q is the last node on the list}\6 +$\\{link}(\|q)\K\\{avail}$;\5 +$\\{avail}\K\|p$;\6 +\&{end};\2\2\6 +\&{end};\7 +\4\&{procedure}\1\ \37$\\{flush\_node\_list}(\|p:\\{pointer})$;\6 +\4\&{var} \37\|q: \37\\{pointer};\C{the node being recycled}\2\6 +\&{begin} \37\&{while} $\|p\I\\{null}$ \1\&{do}\6 +\&{begin} \37$\|q\K\|p$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{if} $\|q<\\{hi\_mem\_min}$ \1\&{then}\5 +$\\{free\_node}(\|q,\392)$\ \&{else} $\\{free\_avail}(\|q)$;\2\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M178. If \MF\ is extended improperly, the \\{mem} array might get screwed up. +For example, some pointers might be wrong, or some ``dead'' nodes might not +have been freed when the last reference to them disappeared. Procedures +\\{check\_mem} and \\{search\_mem} are available to help diagnose such +problems. These procedures make use of two arrays called \\{free} and +\\{was\_free} that are present only if \MF's debugging routines have +been included. (You may want to decrease the size of \\{mem} while you +are debugging.) + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\&{debug} \37\\{free}: \37\&{packed} \37\&{array} $[\\{mem\_min}\to\\{mem% +\_max}]$ \1\&{of}\5 +\\{boolean};\C{free cells}\2\6 +\4\hbox{\hskip1em}\\{was\_free}: \37\&{packed} \37\&{array} $[\\{mem\_min}\to% +\\{mem\_max}]$ \1\&{of}\5 +\\{boolean};\C{previously free cells}\2\6 +\4$\hbox{\hskip1em}\\{was\_mem\_end},\39\\{was\_lo\_max},\39\\{was\_hi\_min}$: % +\37\\{pointer};\C{previous \\{mem\_end}, \\{lo\_mem\_max}, and \\{hi\_mem% +\_min}}\6 +\4\hbox{\hskip1em}\\{panicking}: \37\\{boolean};\C{do we want to check memory +constantly?}\6 +\&{gubed}\par +\fi + +\M179. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +\&{debug} \37$\\{was\_mem\_end}\K\\{mem\_min}$;\C{indicate that everything was +previously free}\6 +$\\{was\_lo\_max}\K\\{mem\_min}$;\5 +$\\{was\_hi\_min}\K\\{mem\_max}$;\5 +$\\{panicking}\K\\{false}$;\6 +\&{gubed}\par +\fi + +\M180. Procedure \\{check\_mem} makes sure that the available space lists of +\\{mem} are well formed, and it optionally prints out all locations +that are reserved now but were free the last time this procedure was called. + +\Y\P\&{debug} \37\&{procedure}\1\ \37$\\{check\_mem}(\\{print\_locs}:% +\\{boolean})$;\6 +\4\&{label} \37$\\{done1},\39\\{done2}$;\C{loop exits}\6 +\4\&{var} \37$\|p,\39\|q,\39\|r$: \37\\{pointer};\C{current locations of +interest in \\{mem}}\6 +\\{clobbered}: \37\\{boolean};\C{is something amiss?}\2\6 +\&{begin} \37\&{for} $\|p\K\\{mem\_min}\mathrel{\&{to}}\\{lo\_mem\_max}$ \1% +\&{do}\5 +$\\{free}[\|p]\K\\{false}$;\C{you can probably do this faster}\2\6 +\&{for} $\|p\K\\{hi\_mem\_min}\mathrel{\&{to}}\\{mem\_end}$ \1\&{do}\5 +$\\{free}[\|p]\K\\{false}$;\C{ditto}\2\6 +\X181:Check single-word \\{avail} list\X;\6 +\X182:Check variable-size \\{avail} list\X;\6 +\X183:Check flags of unavailable nodes\X;\6 +\X617:Check the list of linear dependencies\X;\6 +\&{if} $\\{print\_locs}$ \1\&{then}\5 +\X184:Print newly busy locations\X;\2\6 +\&{for} $\|p\K\\{mem\_min}\mathrel{\&{to}}\\{lo\_mem\_max}$ \1\&{do}\5 +$\\{was\_free}[\|p]\K\\{free}[\|p]$;\2\6 +\&{for} $\|p\K\\{hi\_mem\_min}\mathrel{\&{to}}\\{mem\_end}$ \1\&{do}\5 +$\\{was\_free}[\|p]\K\\{free}[\|p]$;\C{$\\{was\_free}\K\\{free}$ might be +faster}\2\6 +$\\{was\_mem\_end}\K\\{mem\_end}$;\5 +$\\{was\_lo\_max}\K\\{lo\_mem\_max}$;\5 +$\\{was\_hi\_min}\K\\{hi\_mem\_min}$;\6 +\&{end};\6 +\&{gubed}\par +\fi + +\M181. \P$\X181:Check single-word \\{avail} list\X\S$\6 +$\|p\K\\{avail}$;\5 +$\|q\K\\{null}$;\5 +$\\{clobbered}\K\\{false}$;\6 +\&{while} $\|p\I\\{null}$ \1\&{do}\6 +\&{begin} \37\&{if} $(\|p>\\{mem\_end})\V(\|p<\\{hi\_mem\_min})$ \1\&{then}\5 +$\\{clobbered}\K\\{true}$\6 +\4\&{else} \&{if} $\\{free}[\|p]$ \1\&{then}\5 +$\\{clobbered}\K\\{true}$;\2\2\6 +\&{if} $\\{clobbered}$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"AVAIL\ list\ clobbered\ at\ "})$;\5 +$\\{print\_int}(\|q)$;\5 +\&{goto} \37\\{done1};\6 +\&{end};\2\6 +$\\{free}[\|p]\K\\{true}$;\5 +$\|q\K\|p$;\5 +$\|p\K\\{link}(\|q)$;\6 +\&{end};\2\6 +\4\\{done1}: \37\par +\U180.\fi + +\M182. \P$\X182:Check variable-size \\{avail} list\X\S$\6 +$\|p\K\\{rover}$;\5 +$\|q\K\\{null}$;\5 +$\\{clobbered}\K\\{false}$;\6 +\1\&{repeat} \37\&{if} $(\|p\G\\{lo\_mem\_max})\V(\|p<\\{mem\_min})$ \1\&{then}% +\5 +$\\{clobbered}\K\\{true}$\6 +\4\&{else} \&{if} $(\\{rlink}(\|p)\G\\{lo\_mem\_max})\V(\\{rlink}(\|p)<\\{mem% +\_min})$ \1\&{then}\5 +$\\{clobbered}\K\\{true}$\6 +\4\&{else} \&{if} $\R(\\{is\_empty}(\|p))\V(\\{node\_size}(\|p)<2)\V\30(\|p+% +\\{node\_size}(\|p)>\\{lo\_mem\_max})\V\30(\\{llink}(\\{rlink}(\|p))\I\|p)$ \1% +\&{then}\5 +$\\{clobbered}\K\\{true}$;\2\2\2\6 +\&{if} $\\{clobbered}$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"Double-AVAIL\ list\ clobbered\ at\ "})$;\5 +$\\{print\_int}(\|q)$;\5 +\&{goto} \37\\{done2};\6 +\&{end};\2\6 +\&{for} $\|q\K\|p\mathrel{\&{to}}\|p+\\{node\_size}(\|p)-1$ \1\&{do}\C{mark all +locations free}\6 +\&{begin} \37\&{if} $\\{free}[\|q]$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"Doubly\ free\ location\ at\ "})$;\5 +$\\{print\_int}(\|q)$;\5 +\&{goto} \37\\{done2};\6 +\&{end};\2\6 +$\\{free}[\|q]\K\\{true}$;\6 +\&{end};\2\6 +$\|q\K\|p$;\5 +$\|p\K\\{rlink}(\|p)$;\6 +\4\&{until}\5 +$\|p=\\{rover}$;\2\6 +\4\\{done2}: \37\par +\U180.\fi + +\M183. \P$\X183:Check flags of unavailable nodes\X\S$\6 +$\|p\K\\{mem\_min}$;\6 +\&{while} $\|p\L\\{lo\_mem\_max}$ \1\&{do}\C{node \|p should not be empty}\6 +\&{begin} \37\&{if} $\\{is\_empty}(\|p)$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"Bad\ flag\ at\ "})$;\5 +$\\{print\_int}(\|p)$;\6 +\&{end};\2\6 +\&{while} $(\|p\L\\{lo\_mem\_max})\W\R\\{free}[\|p]$ \1\&{do}\5 +$\\{incr}(\|p)$;\2\6 +\&{while} $(\|p\L\\{lo\_mem\_max})\W\\{free}[\|p]$ \1\&{do}\5 +$\\{incr}(\|p)$;\2\6 +\&{end}\2\par +\U180.\fi + +\M184. \P$\X184:Print newly busy locations\X\S$\6 +\&{begin} \37$\\{print\_nl}(\.{"New\ busy\ locs:"})$;\6 +\&{for} $\|p\K\\{mem\_min}\mathrel{\&{to}}\\{lo\_mem\_max}$ \1\&{do}\6 +\&{if} $\R\\{free}[\|p]\W((\|p>\\{was\_lo\_max})\V\\{was\_free}[\|p])$ \1% +\&{then}\6 +\&{begin} \37$\\{print\_char}(\.{"\ "})$;\5 +$\\{print\_int}(\|p)$;\6 +\&{end};\2\2\6 +\&{for} $\|p\K\\{hi\_mem\_min}\mathrel{\&{to}}\\{mem\_end}$ \1\&{do}\6 +\&{if} $\R\\{free}[\|p]\W((\|p<\\{was\_hi\_min})\V(\|p>\\{was\_mem\_end})\V% +\\{was\_free}[\|p])$ \1\&{then}\6 +\&{begin} \37$\\{print\_char}(\.{"\ "})$;\5 +$\\{print\_int}(\|p)$;\6 +\&{end};\2\2\6 +\&{end}\par +\U180.\fi + +\M185. The \\{search\_mem} procedure attempts to answer the question ``Who +points +to node~\|p?'' In doing so, it fetches \\{link} and \\{info} fields of \\{mem} +that might not be of type \\{two\_halves}. Strictly speaking, this is +undefined in \PASCAL, and it can lead to ``false drops'' (words that seem to +point to \|p purely by coincidence). But for debugging purposes, we want +to rule out the places that do {\sl not\/} point to \|p, so a few false +drops are tolerable. + +\Y\P\&{debug} \37\&{procedure}\1\ \37$\\{search\_mem}(\|p:\\{pointer})$;% +\C{look for pointers to \|p}\6 +\4\&{var} \37\|q: \37\\{integer};\C{current position being searched}\2\6 +\&{begin} \37\&{for} $\|q\K\\{mem\_min}\mathrel{\&{to}}\\{lo\_mem\_max}$ \1% +\&{do}\6 +\&{begin} \37\&{if} $\\{link}(\|q)=\|p$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"LINK("})$;\5 +$\\{print\_int}(\|q)$;\5 +$\\{print\_char}(\.{")"})$;\6 +\&{end};\2\6 +\&{if} $\\{info}(\|q)=\|p$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"INFO("})$;\5 +$\\{print\_int}(\|q)$;\5 +$\\{print\_char}(\.{")"})$;\6 +\&{end};\2\6 +\&{end};\2\6 +\&{for} $\|q\K\\{hi\_mem\_min}\mathrel{\&{to}}\\{mem\_end}$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{link}(\|q)=\|p$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"LINK("})$;\5 +$\\{print\_int}(\|q)$;\5 +$\\{print\_char}(\.{")"})$;\6 +\&{end};\2\6 +\&{if} $\\{info}(\|q)=\|p$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"INFO("})$;\5 +$\\{print\_int}(\|q)$;\5 +$\\{print\_char}(\.{")"})$;\6 +\&{end};\2\6 +\&{end};\2\6 +\X209:Search \\{eqtb} for equivalents equal to \|p\X;\6 +\&{end};\6 +\&{gubed}\par +\fi + +\N186. \[12] The command codes. +Before we can go much further, we need to define symbolic names for the +internal +code numbers that represent the various commands obeyed by \MF. These codes +are somewhat arbitrary, but not completely so. For example, +some 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. A command can begin an +expression if and only if its code lies between \\{min\_primary\_command} and +\\{max\_primary\_command}, inclusive. The first token of a statement that +doesn't +begin with an expression has a command code between \\{min\_command} and +\\{max\_statement\_command}, inclusive. The ordering of the highest-numbered +commands ($\\{comma}<\\{semicolon}<\\{end\_group}<\\{stop}$) is crucial for the +parsing +and error-recovery methods of this program. + +At any rate, here is the list, for future reference. + +\Y\P\D \37$\\{if\_test}=1$\C{conditional text (\&{if})}\par +\P\D \37$\\{fi\_or\_else}=2$\C{delimiters for conditionals (\&{elseif}, % +\&{else}, \&{fi}}\par +\P\D \37$\\{input}=3$\C{input a source file (\&{input}, \&{endinput})}\par +\P\D \37$\\{iteration}=4$\C{iterate (\&{for}, \&{forsuffixes}, \&{forever}, % +\&{endfor})}\par +\P\D \37$\\{repeat\_loop}=5$\C{special command substituted for \&{endfor}}\par +\P\D \37$\\{exit\_test}=6$\C{premature exit from a loop (\&{exitif})}\par +\P\D \37$\\{relax}=7$\C{do nothing (\.{\char`\\})}\par +\P\D \37$\\{scan\_tokens}=8$\C{put a string into the input buffer}\par +\P\D \37$\\{expand\_after}=9$\C{look ahead one token}\par +\P\D \37$\\{defined\_macro}=10$\C{a macro defined by the user}\par +\P\D \37$\\{min\_command}=\\{defined\_macro}+1$\par +\P\D \37$\\{display\_command}=11$\C{online graphic output (\&{display})}\par +\P\D \37$\\{save\_command}=12$\C{save a list of tokens (\&{save})}\par +\P\D \37$\\{interim\_command}=13$\C{save an internal quantity (\&{interim})}\par +\P\D \37$\\{let\_command}=14$\C{redefine a symbolic token (\&{let})}\par +\P\D \37$\\{new\_internal}=15$\C{define a new internal quantity (% +\&{newinternal})}\par +\P\D \37$\\{macro\_def}=16$\C{define a macro (\&{def}, \&{vardef}, etc.)}\par +\P\D \37$\\{ship\_out\_command}=17$\C{output a character (\&{shipout})}\par +\P\D \37$\\{add\_to\_command}=18$\C{add to edges (\&{addto})}\par +\P\D \37$\\{cull\_command}=19$\C{cull and normalize edges (\&{cull})}\par +\P\D \37$\\{tfm\_command}=20$\C{command for font metric info (\&{ligtable}, +etc.)}\par +\P\D \37$\\{protection\_command}=21$\C{set protection flag (\&{outer}, % +\&{inner})}\par +\P\D \37$\\{show\_command}=22$\C{diagnostic output (\&{show}, \&{showvariable}, +etc.)}\par +\P\D \37$\\{mode\_command}=23$\C{set interaction level (\&{batchmode}, etc.)}% +\par +\P\D \37$\\{random\_seed}=24$\C{initialize random number generator (% +\&{randomseed})}\par +\P\D \37$\\{message\_command}=25$\C{communicate to user (\&{message}, % +\&{errmessage})}\par +\P\D \37$\\{every\_job\_command}=26$\C{designate a starting token (% +\&{everyjob})}\par +\P\D \37$\\{delimiters}=27$\C{define a pair of delimiters (\&{delimiters})}\par +\P\D \37$\\{open\_window}=28$\C{define a window on the screen (\&{openwindow})}% +\par +\P\D \37$\\{special\_command}=29$\C{output special info (\&{special}, % +\&{numspecial})}\par +\P\D \37$\\{type\_name}=30$\C{declare a type (\&{numeric}, \&{pair}, etc.}\par +\P\D \37$\\{max\_statement\_command}=\\{type\_name}$\par +\P\D \37$\\{min\_primary\_command}=\\{type\_name}$\par +\P\D \37$\\{left\_delimiter}=31$\C{the left delimiter of a matching pair}\par +\P\D \37$\\{begin\_group}=32$\C{beginning of a group (\&{begingroup})}\par +\P\D \37$\\{nullary}=33$\C{an operator without arguments (e.g., % +\&{normaldeviate})}\par +\P\D \37$\\{unary}=34$\C{an operator with one argument (e.g., \&{sqrt})}\par +\P\D \37$\\{str\_op}=35$\C{convert a suffix to a string (\&{str})}\par +\P\D \37$\\{cycle}=36$\C{close a cyclic path (\&{cycle})}\par +\P\D \37$\\{primary\_binary}=37$\C{binary operation taking `\&{of}' (e.g., % +\&{point})}\par +\P\D \37$\\{capsule\_token}=38$\C{a value that has been put into a token list}% +\par +\P\D \37$\\{string\_token}=39$\C{a string constant (e.g., \.{"hello"})}\par +\P\D \37$\\{internal\_quantity}=40$\C{internal numeric parameter (e.g., % +\&{pausing})}\par +\P\D \37$\\{min\_suffix\_token}=\\{internal\_quantity}$\par +\P\D \37$\\{tag\_token}=41$\C{a symbolic token without a primitive meaning}\par +\P\D \37$\\{numeric\_token}=42$\C{a numeric constant (e.g., \.{3.14159})}\par +\P\D \37$\\{max\_suffix\_token}=\\{numeric\_token}$\par +\P\D \37$\\{plus\_or\_minus}=43$\C{either `\.+' or `\.-'}\par +\P\D \37$\\{max\_primary\_command}=\\{plus\_or\_minus}$\C{should also be $% +\\{numeric\_token}+1$}\par +\P\D \37$\\{min\_tertiary\_command}=\\{plus\_or\_minus}$\par +\P\D \37$\\{tertiary\_secondary\_macro}=44$\C{a macro defined by % +\&{secondarydef}}\par +\P\D \37$\\{tertiary\_binary}=45$\C{an operator at the tertiary level (e.g., `% +\.{++}')}\par +\P\D \37$\\{max\_tertiary\_command}=\\{tertiary\_binary}$\par +\P\D \37$\\{left\_brace}=46$\C{the operator `\.{\char`\{}'}\par +\P\D \37$\\{min\_expression\_command}=\\{left\_brace}$\par +\P\D \37$\\{path\_join}=47$\C{the operator `\.{..}'}\par +\P\D \37$\\{ampersand}=48$\C{the operator `\.\&'}\par +\P\D \37$\\{expression\_tertiary\_macro}=49$\C{a macro defined by % +\&{tertiarydef}}\par +\P\D \37$\\{expression\_binary}=50$\C{an operator at the expression level +(e.g., `\.<')}\par +\P\D \37$\\{equals}=51$\C{the operator `\.='}\par +\P\D \37$\\{max\_expression\_command}=\\{equals}$\par +\P\D \37$\\{and\_command}=52$\C{the operator `\&{and}'}\par +\P\D \37$\\{min\_secondary\_command}=\\{and\_command}$\par +\P\D \37$\\{secondary\_primary\_macro}=53$\C{a macro defined by \&{primarydef}}% +\par +\P\D \37$\\{slash}=54$\C{the operator `\./'}\par +\P\D \37$\\{secondary\_binary}=55$\C{an operator at the binary level (e.g., % +\&{shifted})}\par +\P\D \37$\\{max\_secondary\_command}=\\{secondary\_binary}$\par +\P\D \37$\\{param\_type}=56$\C{type of parameter (\&{primary}, \&{expr}, % +\&{suffix}, etc.)}\par +\P\D \37$\\{controls}=57$\C{specify control points explicitly (\&{controls})}% +\par +\P\D \37$\\{tension}=58$\C{specify tension between knots (\&{tension})}\par +\P\D \37$\\{at\_least}=59$\C{bounded tension value (\&{atleast})}\par +\P\D \37$\\{curl\_command}=60$\C{specify curl at an end knot (\&{curl})}\par +\P\D \37$\\{macro\_special}=61$\C{special macro operators (\&{quote}, \.{\#% +\AT!}, etc.)}\par +\P\D \37$\\{right\_delimiter}=62$\C{the right delimiter of a matching pair}\par +\P\D \37$\\{left\_bracket}=63$\C{the operator `\.['}\par +\P\D \37$\\{right\_bracket}=64$\C{the operator `\.]'}\par +\P\D \37$\\{right\_brace}=65$\C{the operator `\.{\char`\}}'}\par +\P\D \37$\\{with\_option}=66$\C{option for filling (\&{withpen}, % +\&{withweight})}\par +\P\D \37$\\{cull\_op}=67$\C{the operator `\&{keeping}' or `\&{dropping}'}\par +\P\D \37$\\{thing\_to\_add}=68$\C{variant of \&{addto} (\&{contour}, % +\&{doublepath}, \&{also})}\par +\P\D \37$\\{of\_token}=69$\C{the operator `\&{of}'}\par +\P\D \37$\\{from\_token}=70$\C{the operator `\&{from}'}\par +\P\D \37$\\{to\_token}=71$\C{the operator `\&{to}'}\par +\P\D \37$\\{at\_token}=72$\C{the operator `\&{at}'}\par +\P\D \37$\\{in\_window}=73$\C{the operator `\&{inwindow}'}\par +\P\D \37$\\{step\_token}=74$\C{the operator `\&{step}'}\par +\P\D \37$\\{until\_token}=75$\C{the operator `\&{until}'}\par +\P\D \37$\\{lig\_kern\_token}=76$\C{the operators `\&{kern}' and `\.{=:}' and `% +\.{=:\char'174}, etc.}\par +\P\D \37$\\{assignment}=77$\C{the operator `\.{:=}'}\par +\P\D \37$\\{skip\_to}=78$\C{the operation `\&{skipto}'}\par +\P\D \37$\\{bchar\_label}=79$\C{the operator `\.{\char'174\char'174:}'}\par +\P\D \37$\\{double\_colon}=80$\C{the operator `\.{::}'}\par +\P\D \37$\\{colon}=81$\C{the operator `\.:'}\Y\par +\P\D \37$\\{comma}=82$\C{the operator `\.,', must be $\\{colon}+1$}\par +\P\D \37$\\{end\_of\_statement}\S\\{cur\_cmd}>\\{comma}$\par +\P\D \37$\\{semicolon}=83$\C{the operator `\.;', must be $\\{comma}+1$}\par +\P\D \37$\\{end\_group}=84$\C{end a group (\&{endgroup}), must be $% +\\{semicolon}+1$}\par +\P\D \37$\\{stop}=85$\C{end a job (\&{end}, \&{dump}), must be $\\{end% +\_group}+1$}\par +\P\D \37$\\{max\_command\_code}=\\{stop}$\par +\P\D \37$\\{outer\_tag}=\\{max\_command\_code}+1$\C{protection code added to +command code}\par +\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6 +$\\{command\_code}=1\to\\{max\_command\_code}$;\par +\fi + +\M187. Variables and capsules in \MF\ have a variety of ``types,'' +distinguished by the following code numbers: + +\Y\P\D \37$\\{undefined}=0$\C{no type has been declared}\par +\P\D \37$\\{unknown\_tag}=1$\C{this constant is added to certain type codes +below}\par +\P\D \37$\\{vacuous}=1$\C{no expression was present}\par +\P\D \37$\\{boolean\_type}=2$\C{\&{boolean} with a known value}\par +\P\D \37$\\{unknown\_boolean}=\\{boolean\_type}+\\{unknown\_tag}$\par +\P\D \37$\\{string\_type}=4$\C{\&{string} with a known value}\par +\P\D \37$\\{unknown\_string}=\\{string\_type}+\\{unknown\_tag}$\par +\P\D \37$\\{pen\_type}=6$\C{\&{pen} with a known value}\par +\P\D \37$\\{unknown\_pen}=\\{pen\_type}+\\{unknown\_tag}$\par +\P\D \37$\\{future\_pen}=8$\C{subexpression that will become a \&{pen} at a +higher level}\par +\P\D \37$\\{path\_type}=9$\C{\&{path} with a known value}\par +\P\D \37$\\{unknown\_path}=\\{path\_type}+\\{unknown\_tag}$\par +\P\D \37$\\{picture\_type}=11$\C{\&{picture} with a known value}\par +\P\D \37$\\{unknown\_picture}=\\{picture\_type}+\\{unknown\_tag}$\par +\P\D \37$\\{transform\_type}=13$\C{\&{transform} variable or capsule}\par +\P\D \37$\\{pair\_type}=14$\C{\&{pair} variable or capsule}\par +\P\D \37$\\{numeric\_type}=15$\C{variable that has been declared \&{numeric} +but not used}\par +\P\D \37$\\{known}=16$\C{\&{numeric} with a known value}\par +\P\D \37$\\{dependent}=17$\C{a linear combination with \\{fraction} +coefficients}\par +\P\D \37$\\{proto\_dependent}=18$\C{a linear combination with \\{scaled} +coefficients}\par +\P\D \37$\\{independent}=19$\C{\&{numeric} with unknown value}\par +\P\D \37$\\{token\_list}=20$\C{variable name or suffix argument or text +argument}\par +\P\D \37$\\{structured}=21$\C{variable with subscripts and attributes}\par +\P\D \37$\\{unsuffixed\_macro}=22$\C{variable defined with \&{vardef} but no % +\.{\AT!\#}}\par +\P\D \37$\\{suffixed\_macro}=23$\C{variable defined with \&{vardef} and \.{\AT!% +\#}}\Y\par +\P\D \37$\\{unknown\_types}\S\\{unknown\_boolean},\39\\{unknown\_string},\39% +\\{unknown\_pen},\39\\{unknown\_picture},\39\\{unknown\_path}$\par +\Y\P$\4\X57:Basic printing procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{print\_type}(\|t:\\{small\_number})$;\2\6 +\&{begin} \37\&{case} $\|t$ \1\&{of}\6 +\4\\{vacuous}: \37$\\{print}(\.{"vacuous"})$;\6 +\4\\{boolean\_type}: \37$\\{print}(\.{"boolean"})$;\6 +\4\\{unknown\_boolean}: \37$\\{print}(\.{"unknown\ boolean"})$;\6 +\4\\{string\_type}: \37$\\{print}(\.{"string"})$;\6 +\4\\{unknown\_string}: \37$\\{print}(\.{"unknown\ string"})$;\6 +\4\\{pen\_type}: \37$\\{print}(\.{"pen"})$;\6 +\4\\{unknown\_pen}: \37$\\{print}(\.{"unknown\ pen"})$;\6 +\4\\{future\_pen}: \37$\\{print}(\.{"future\ pen"})$;\6 +\4\\{path\_type}: \37$\\{print}(\.{"path"})$;\6 +\4\\{unknown\_path}: \37$\\{print}(\.{"unknown\ path"})$;\6 +\4\\{picture\_type}: \37$\\{print}(\.{"picture"})$;\6 +\4\\{unknown\_picture}: \37$\\{print}(\.{"unknown\ picture"})$;\6 +\4\\{transform\_type}: \37$\\{print}(\.{"transform"})$;\6 +\4\\{pair\_type}: \37$\\{print}(\.{"pair"})$;\6 +\4\\{known}: \37$\\{print}(\.{"known\ numeric"})$;\6 +\4\\{dependent}: \37$\\{print}(\.{"dependent"})$;\6 +\4\\{proto\_dependent}: \37$\\{print}(\.{"proto-dependent"})$;\6 +\4\\{numeric\_type}: \37$\\{print}(\.{"numeric"})$;\6 +\4\\{independent}: \37$\\{print}(\.{"independent"})$;\6 +\4\\{token\_list}: \37$\\{print}(\.{"token\ list"})$;\6 +\4\\{structured}: \37$\\{print}(\.{"structured"})$;\6 +\4\\{unsuffixed\_macro}: \37$\\{print}(\.{"unsuffixed\ macro"})$;\6 +\4\\{suffixed\_macro}: \37$\\{print}(\.{"suffixed\ macro"})$;\6 +\4\&{othercases} \37$\\{print}(\.{"undefined"})$\2\6 +\&{endcases};\6 +\&{end};\par +\fi + +\M188. Values inside \MF\ are stored in two-word nodes that have a \\{name% +\_type} +as well as a \\{type}. The possibilities for \\{name\_type} are defined +here; they will be explained in more detail later. + +\Y\P\D \37$\\{root}=0$\C{\\{name\_type} at the top level of a variable}\par +\P\D \37$\\{saved\_root}=1$\C{same, when the variable has been saved}\par +\P\D \37$\\{structured\_root}=2$\C{\\{name\_type} where a \\{structured} branch +occurs}\par +\P\D \37$\\{subscr}=3$\C{\\{name\_type} in a subscript node}\par +\P\D \37$\\{attr}=4$\C{\\{name\_type} in an attribute node}\par +\P\D \37$\\{x\_part\_sector}=5$\C{\\{name\_type} in the \&{xpart} of a node}\par +\P\D \37$\\{y\_part\_sector}=6$\C{\\{name\_type} in the \&{ypart} of a node}\par +\P\D \37$\\{xx\_part\_sector}=7$\C{\\{name\_type} in the \&{xxpart} of a node}% +\par +\P\D \37$\\{xy\_part\_sector}=8$\C{\\{name\_type} in the \&{xypart} of a node}% +\par +\P\D \37$\\{yx\_part\_sector}=9$\C{\\{name\_type} in the \&{yxpart} of a node}% +\par +\P\D \37$\\{yy\_part\_sector}=10$\C{\\{name\_type} in the \&{yypart} of a node}% +\par +\P\D \37$\\{capsule}=11$\C{\\{name\_type} in stashed-away subexpressions}\par +\P\D \37$\\{token}=12$\C{\\{name\_type} in a numeric token or string token}\par +\fi + +\M189. Primitive operations that produce values have a secondary identification +code in addition to their command code; it's something like genera and species. +For example, `\.*' has the command code \\{primary\_binary}, and its +secondary identification is \\{times}. The secondary codes start at 30 so that +they don't overlap with the type codes; some type codes (e.g., \\{string% +\_type}) +are used as operators as well as type identifications. + +\Y\P\D \37$\\{true\_code}=30$\C{operation code for \.{true}}\par +\P\D \37$\\{false\_code}=31$\C{operation code for \.{false}}\par +\P\D \37$\\{null\_picture\_code}=32$\C{operation code for \.{nullpicture}}\par +\P\D \37$\\{null\_pen\_code}=33$\C{operation code for \.{nullpen}}\par +\P\D \37$\\{job\_name\_op}=34$\C{operation code for \.{jobname}}\par +\P\D \37$\\{read\_string\_op}=35$\C{operation code for \.{readstring}}\par +\P\D \37$\\{pen\_circle}=36$\C{operation code for \.{pencircle}}\par +\P\D \37$\\{normal\_deviate}=37$\C{operation code for \.{normaldeviate}}\par +\P\D \37$\\{odd\_op}=38$\C{operation code for \.{odd}}\par +\P\D \37$\\{known\_op}=39$\C{operation code for \.{known}}\par +\P\D \37$\\{unknown\_op}=40$\C{operation code for \.{unknown}}\par +\P\D \37$\\{not\_op}=41$\C{operation code for \.{not}}\par +\P\D \37$\\{decimal}=42$\C{operation code for \.{decimal}}\par +\P\D \37$\\{reverse}=43$\C{operation code for \.{reverse}}\par +\P\D \37$\\{make\_path\_op}=44$\C{operation code for \.{makepath}}\par +\P\D \37$\\{make\_pen\_op}=45$\C{operation code for \.{makepen}}\par +\P\D \37$\\{total\_weight\_op}=46$\C{operation code for \.{totalweight}}\par +\P\D \37$\\{oct\_op}=47$\C{operation code for \.{oct}}\par +\P\D \37$\\{hex\_op}=48$\C{operation code for \.{hex}}\par +\P\D \37$\\{ASCII\_op}=49$\C{operation code for \.{ASCII}}\par +\P\D \37$\\{char\_op}=50$\C{operation code for \.{char}}\par +\P\D \37$\\{length\_op}=51$\C{operation code for \.{length}}\par +\P\D \37$\\{turning\_op}=52$\C{operation code for \.{turningnumber}}\par +\P\D \37$\\{x\_part}=53$\C{operation code for \.{xpart}}\par +\P\D \37$\\{y\_part}=54$\C{operation code for \.{ypart}}\par +\P\D \37$\\{xx\_part}=55$\C{operation code for \.{xxpart}}\par +\P\D \37$\\{xy\_part}=56$\C{operation code for \.{xypart}}\par +\P\D \37$\\{yx\_part}=57$\C{operation code for \.{yxpart}}\par +\P\D \37$\\{yy\_part}=58$\C{operation code for \.{yypart}}\par +\P\D \37$\\{sqrt\_op}=59$\C{operation code for \.{sqrt}}\par +\P\D \37$\\{m\_exp\_op}=60$\C{operation code for \.{mexp}}\par +\P\D \37$\\{m\_log\_op}=61$\C{operation code for \.{mlog}}\par +\P\D \37$\\{sin\_d\_op}=62$\C{operation code for \.{sind}}\par +\P\D \37$\\{cos\_d\_op}=63$\C{operation code for \.{cosd}}\par +\P\D \37$\\{floor\_op}=64$\C{operation code for \.{floor}}\par +\P\D \37$\\{uniform\_deviate}=65$\C{operation code for \.{uniformdeviate}}\par +\P\D \37$\\{char\_exists\_op}=66$\C{operation code for \.{charexists}}\par +\P\D \37$\\{angle\_op}=67$\C{operation code for \.{angle}}\par +\P\D \37$\\{cycle\_op}=68$\C{operation code for \.{cycle}}\par +\P\D \37$\\{plus}=69$\C{operation code for \.+}\par +\P\D \37$\\{minus}=70$\C{operation code for \.-}\par +\P\D \37$\\{times}=71$\C{operation code for \.*}\par +\P\D \37$\\{over}=72$\C{operation code for \./}\par +\P\D \37$\\{pythag\_add}=73$\C{operation code for \.{++}}\par +\P\D \37$\\{pythag\_sub}=74$\C{operation code for \.{+-+}}\par +\P\D \37$\\{or\_op}=75$\C{operation code for \.{or}}\par +\P\D \37$\\{and\_op}=76$\C{operation code for \.{and}}\par +\P\D \37$\\{less\_than}=77$\C{operation code for \.<}\par +\P\D \37$\\{less\_or\_equal}=78$\C{operation code for \.{<=}}\par +\P\D \37$\\{greater\_than}=79$\C{operation code for \.>}\par +\P\D \37$\\{greater\_or\_equal}=80$\C{operation code for \.{>=}}\par +\P\D \37$\\{equal\_to}=81$\C{operation code for \.=}\par +\P\D \37$\\{unequal\_to}=82$\C{operation code for \.{<>}}\par +\P\D \37$\\{concatenate}=83$\C{operation code for \.\&}\par +\P\D \37$\\{rotated\_by}=84$\C{operation code for \.{rotated}}\par +\P\D \37$\\{slanted\_by}=85$\C{operation code for \.{slanted}}\par +\P\D \37$\\{scaled\_by}=86$\C{operation code for \.{scaled}}\par +\P\D \37$\\{shifted\_by}=87$\C{operation code for \.{shifted}}\par +\P\D \37$\\{transformed\_by}=88$\C{operation code for \.{transformed}}\par +\P\D \37$\\{x\_scaled}=89$\C{operation code for \.{xscaled}}\par +\P\D \37$\\{y\_scaled}=90$\C{operation code for \.{yscaled}}\par +\P\D \37$\\{z\_scaled}=91$\C{operation code for \.{zscaled}}\par +\P\D \37$\\{intersect}=92$\C{operation code for \.{intersectiontimes}}\par +\P\D \37$\\{double\_dot}=93$\C{operation code for improper \.{..}}\par +\P\D \37$\\{substring\_of}=94$\C{operation code for \.{substring}}\par +\P\D \37$\\{min\_of}=\\{substring\_of}$\par +\P\D \37$\\{subpath\_of}=95$\C{operation code for \.{subpath}}\par +\P\D \37$\\{direction\_time\_of}=96$\C{operation code for \.{directiontime}}\par +\P\D \37$\\{point\_of}=97$\C{operation code for \.{point}}\par +\P\D \37$\\{precontrol\_of}=98$\C{operation code for \.{precontrol}}\par +\P\D \37$\\{postcontrol\_of}=99$\C{operation code for \.{postcontrol}}\par +\P\D \37$\\{pen\_offset\_of}=100$\C{operation code for \.{penoffset}}\par +\Y\P\4\&{procedure}\1\ \37$\\{print\_op}(\|c:\\{quarterword})$;\2\6 +\&{begin} \37\&{if} $\|c\L\\{numeric\_type}$ \1\&{then}\5 +$\\{print\_type}(\|c)$\6 +\4\&{else} \&{case} $\|c$ \1\&{of}\6 +\4\\{true\_code}: \37$\\{print}(\.{"true"})$;\6 +\4\\{false\_code}: \37$\\{print}(\.{"false"})$;\6 +\4\\{null\_picture\_code}: \37$\\{print}(\.{"nullpicture"})$;\6 +\4\\{null\_pen\_code}: \37$\\{print}(\.{"nullpen"})$;\6 +\4\\{job\_name\_op}: \37$\\{print}(\.{"jobname"})$;\6 +\4\\{read\_string\_op}: \37$\\{print}(\.{"readstring"})$;\6 +\4\\{pen\_circle}: \37$\\{print}(\.{"pencircle"})$;\6 +\4\\{normal\_deviate}: \37$\\{print}(\.{"normaldeviate"})$;\6 +\4\\{odd\_op}: \37$\\{print}(\.{"odd"})$;\6 +\4\\{known\_op}: \37$\\{print}(\.{"known"})$;\6 +\4\\{unknown\_op}: \37$\\{print}(\.{"unknown"})$;\6 +\4\\{not\_op}: \37$\\{print}(\.{"not"})$;\6 +\4\\{decimal}: \37$\\{print}(\.{"decimal"})$;\6 +\4\\{reverse}: \37$\\{print}(\.{"reverse"})$;\6 +\4\\{make\_path\_op}: \37$\\{print}(\.{"makepath"})$;\6 +\4\\{make\_pen\_op}: \37$\\{print}(\.{"makepen"})$;\6 +\4\\{total\_weight\_op}: \37$\\{print}(\.{"totalweight"})$;\6 +\4\\{oct\_op}: \37$\\{print}(\.{"oct"})$;\6 +\4\\{hex\_op}: \37$\\{print}(\.{"hex"})$;\6 +\4\\{ASCII\_op}: \37$\\{print}(\.{"ASCII"})$;\6 +\4\\{char\_op}: \37$\\{print}(\.{"char"})$;\6 +\4\\{length\_op}: \37$\\{print}(\.{"length"})$;\6 +\4\\{turning\_op}: \37$\\{print}(\.{"turningnumber"})$;\6 +\4\\{x\_part}: \37$\\{print}(\.{"xpart"})$;\6 +\4\\{y\_part}: \37$\\{print}(\.{"ypart"})$;\6 +\4\\{xx\_part}: \37$\\{print}(\.{"xxpart"})$;\6 +\4\\{xy\_part}: \37$\\{print}(\.{"xypart"})$;\6 +\4\\{yx\_part}: \37$\\{print}(\.{"yxpart"})$;\6 +\4\\{yy\_part}: \37$\\{print}(\.{"yypart"})$;\6 +\4\\{sqrt\_op}: \37$\\{print}(\.{"sqrt"})$;\6 +\4\\{m\_exp\_op}: \37$\\{print}(\.{"mexp"})$;\6 +\4\\{m\_log\_op}: \37$\\{print}(\.{"mlog"})$;\6 +\4\\{sin\_d\_op}: \37$\\{print}(\.{"sind"})$;\6 +\4\\{cos\_d\_op}: \37$\\{print}(\.{"cosd"})$;\6 +\4\\{floor\_op}: \37$\\{print}(\.{"floor"})$;\6 +\4\\{uniform\_deviate}: \37$\\{print}(\.{"uniformdeviate"})$;\6 +\4\\{char\_exists\_op}: \37$\\{print}(\.{"charexists"})$;\6 +\4\\{angle\_op}: \37$\\{print}(\.{"angle"})$;\6 +\4\\{cycle\_op}: \37$\\{print}(\.{"cycle"})$;\6 +\4\\{plus}: \37$\\{print\_char}(\.{"+"})$;\6 +\4\\{minus}: \37$\\{print\_char}(\.{"-"})$;\6 +\4\\{times}: \37$\\{print\_char}(\.{"*"})$;\6 +\4\\{over}: \37$\\{print\_char}(\.{"/"})$;\6 +\4\\{pythag\_add}: \37$\\{print}(\.{"++"})$;\6 +\4\\{pythag\_sub}: \37$\\{print}(\.{"+-+"})$;\6 +\4\\{or\_op}: \37$\\{print}(\.{"or"})$;\6 +\4\\{and\_op}: \37$\\{print}(\.{"and"})$;\6 +\4\\{less\_than}: \37$\\{print\_char}(\.{"<"})$;\6 +\4\\{less\_or\_equal}: \37$\\{print}(\.{"<="})$;\6 +\4\\{greater\_than}: \37$\\{print\_char}(\.{">"})$;\6 +\4\\{greater\_or\_equal}: \37$\\{print}(\.{">="})$;\6 +\4\\{equal\_to}: \37$\\{print\_char}(\.{"="})$;\6 +\4\\{unequal\_to}: \37$\\{print}(\.{"<>"})$;\6 +\4\\{concatenate}: \37$\\{print}(\.{"\&"})$;\6 +\4\\{rotated\_by}: \37$\\{print}(\.{"rotated"})$;\6 +\4\\{slanted\_by}: \37$\\{print}(\.{"slanted"})$;\6 +\4\\{scaled\_by}: \37$\\{print}(\.{"scaled"})$;\6 +\4\\{shifted\_by}: \37$\\{print}(\.{"shifted"})$;\6 +\4\\{transformed\_by}: \37$\\{print}(\.{"transformed"})$;\6 +\4\\{x\_scaled}: \37$\\{print}(\.{"xscaled"})$;\6 +\4\\{y\_scaled}: \37$\\{print}(\.{"yscaled"})$;\6 +\4\\{z\_scaled}: \37$\\{print}(\.{"zscaled"})$;\6 +\4\\{intersect}: \37$\\{print}(\.{"intersectiontimes"})$;\6 +\4\\{substring\_of}: \37$\\{print}(\.{"substring"})$;\6 +\4\\{subpath\_of}: \37$\\{print}(\.{"subpath"})$;\6 +\4\\{direction\_time\_of}: \37$\\{print}(\.{"directiontime"})$;\6 +\4\\{point\_of}: \37$\\{print}(\.{"point"})$;\6 +\4\\{precontrol\_of}: \37$\\{print}(\.{"precontrol"})$;\6 +\4\\{postcontrol\_of}: \37$\\{print}(\.{"postcontrol"})$;\6 +\4\\{pen\_offset\_of}: \37$\\{print}(\.{"penoffset"})$;\6 +\4\&{othercases} \37$\\{print}(\.{".."})$\2\6 +\&{endcases};\2\6 +\&{end};\par +\fi + +\M190. \MF\ also has a bunch of internal parameters that a user might want to +fuss with. Every such parameter has an identifying code number, defined here. + +\Y\P\D \37$\\{tracing\_titles}=1$\C{show titles online when they appear}\par +\P\D \37$\\{tracing\_equations}=2$\C{show each variable when it becomes known}% +\par +\P\D \37$\\{tracing\_capsules}=3$\C{show capsules too}\par +\P\D \37$\\{tracing\_choices}=4$\C{show the control points chosen for paths}\par +\P\D \37$\\{tracing\_specs}=5$\C{show subdivision of paths into octants before +digitizing}\par +\P\D \37$\\{tracing\_pens}=6$\C{show details of pens that are made}\par +\P\D \37$\\{tracing\_commands}=7$\C{show commands and operations before they +are performed}\par +\P\D \37$\\{tracing\_restores}=8$\C{show when a variable or internal is +restored}\par +\P\D \37$\\{tracing\_macros}=9$\C{show macros before they are expanded}\par +\P\D \37$\\{tracing\_edges}=10$\C{show digitized edges as they are computed}\par +\P\D \37$\\{tracing\_output}=11$\C{show digitized edges as they are output}\par +\P\D \37$\\{tracing\_stats}=12$\C{show memory usage at end of job}\par +\P\D \37$\\{tracing\_online}=13$\C{show long diagnostics on terminal and in the +log file}\par +\P\D \37$\\{year}=14$\C{the current year (e.g., 1984)}\par +\P\D \37$\\{month}=15$\C{the current month (e.g, 3 $\equiv$ March)}\par +\P\D \37$\\{day}=16$\C{the current day of the month}\par +\P\D \37$\\{time}=17$\C{the number of minutes past midnight when this job +started}\par +\P\D \37$\\{char\_code}=18$\C{the number of the next character to be output}\par +\P\D \37$\\{char\_ext}=19$\C{the extension code of the next character to be +output}\par +\P\D \37$\\{char\_wd}=20$\C{the width of the next character to be output}\par +\P\D \37$\\{char\_ht}=21$\C{the height of the next character to be output}\par +\P\D \37$\\{char\_dp}=22$\C{the depth of the next character to be output}\par +\P\D \37$\\{char\_ic}=23$\C{the italic correction of the next character to be +output}\par +\P\D \37$\\{char\_dx}=24$\C{the device's $x$ movement for the next character, +in pixels}\par +\P\D \37$\\{char\_dy}=25$\C{the device's $y$ movement for the next character, +in pixels}\par +\P\D \37$\\{design\_size}=26$\C{the unit of measure used for $\\{char\_wd}\to% +\\{char\_ic}$, in points}\par +\P\D \37$\\{hppp}=27$\C{the number of horizontal pixels per point}\par +\P\D \37$\\{vppp}=28$\C{the number of vertical pixels per point}\par +\P\D \37$\\{x\_offset}=29$\C{horizontal displacement of shipped-out characters}% +\par +\P\D \37$\\{y\_offset}=30$\C{vertical displacement of shipped-out characters}% +\par +\P\D \37$\\{pausing}=31$\C{positive to display lines on the terminal before +they are read}\par +\P\D \37$\\{showstopping}=32$\C{positive to stop after each \&{show} command}% +\par +\P\D \37$\\{fontmaking}=33$\C{positive if font metric output is to be produced}% +\par +\P\D \37$\\{proofing}=34$\C{positive for proof mode, negative to suppress +output}\par +\P\D \37$\\{smoothing}=35$\C{positive if moves are to be ``smoothed''}\par +\P\D \37$\\{autorounding}=36$\C{controls path modification to ``good'' points}% +\par +\P\D \37$\\{granularity}=37$\C{autorounding uses this pixel size}\par +\P\D \37$\\{fillin}=38$\C{extra darkness of diagonal lines}\par +\P\D \37$\\{turning\_check}=39$\C{controls reorientation of clockwise paths}\par +\P\D \37$\\{warning\_check}=40$\C{controls error message when variable value is +large}\par +\P\D \37$\\{boundary\_char}=41$\C{the right boundary character for ligatures}% +\par +\P\D \37$\\{max\_given\_internal}=41$\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{internal}: \37\&{array} $[1\to\\{max\_internal}]$ \1\&{of}\5 +\\{scaled};\C{the values of internal quantities}\2\6 +\4\\{int\_name}: \37\&{array} $[1\to\\{max\_internal}]$ \1\&{of}\5 +\\{str\_number};\C{their names}\2\6 +\4\\{int\_ptr}: \37$\\{max\_given\_internal}\to\\{max\_internal}$;\C{the +maximum internal quantity defined so far}\par +\fi + +\M191. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +\&{for} $\|k\K1\mathrel{\&{to}}\\{max\_given\_internal}$ \1\&{do}\5 +$\\{internal}[\|k]\K0$;\2\6 +$\\{int\_ptr}\K\\{max\_given\_internal}$;\par +\fi + +\M192. The symbolic names for internal quantities are put into \MF's hash table +by using a routine called \\{primitive}, which will be defined later. Let us +enter them now, so that we don't have to list all those names again +anywhere else. + +\Y\P$\4\X192:Put each of \MF's primitives into the hash table\X\S$\6 +$\\{primitive}(\.{"tracingtitles"},\39\\{internal\_quantity},\39\\{tracing% +\_titles})$;\6 +$\\{primitive}(\.{"tracingequations"},\39\\{internal\_quantity},\39\\{tracing% +\_equations})$;\6 +$\\{primitive}(\.{"tracingcapsules"},\39\\{internal\_quantity},\39\\{tracing% +\_capsules})$;\6 +$\\{primitive}(\.{"tracingchoices"},\39\\{internal\_quantity},\39\\{tracing% +\_choices})$;\6 +$\\{primitive}(\.{"tracingspecs"},\39\\{internal\_quantity},\39\\{tracing% +\_specs})$;\6 +$\\{primitive}(\.{"tracingpens"},\39\\{internal\_quantity},\39\\{tracing% +\_pens})$;\6 +$\\{primitive}(\.{"tracingcommands"},\39\\{internal\_quantity},\39\\{tracing% +\_commands})$;\6 +$\\{primitive}(\.{"tracingrestores"},\39\\{internal\_quantity},\39\\{tracing% +\_restores})$;\6 +$\\{primitive}(\.{"tracingmacros"},\39\\{internal\_quantity},\39\\{tracing% +\_macros})$;\6 +$\\{primitive}(\.{"tracingedges"},\39\\{internal\_quantity},\39\\{tracing% +\_edges})$;\6 +$\\{primitive}(\.{"tracingoutput"},\39\\{internal\_quantity},\39\\{tracing% +\_output})$;\6 +$\\{primitive}(\.{"tracingstats"},\39\\{internal\_quantity},\39\\{tracing% +\_stats})$;\6 +$\\{primitive}(\.{"tracingonline"},\39\\{internal\_quantity},\39\\{tracing% +\_online})$;\6 +$\\{primitive}(\.{"year"},\39\\{internal\_quantity},\39\\{year})$;\6 +$\\{primitive}(\.{"month"},\39\\{internal\_quantity},\39\\{month})$;\6 +$\\{primitive}(\.{"day"},\39\\{internal\_quantity},\39\\{day})$;\6 +$\\{primitive}(\.{"time"},\39\\{internal\_quantity},\39\\{time})$;\6 +$\\{primitive}(\.{"charcode"},\39\\{internal\_quantity},\39\\{char\_code})$;\6 +$\\{primitive}(\.{"charext"},\39\\{internal\_quantity},\39\\{char\_ext})$;\6 +$\\{primitive}(\.{"charwd"},\39\\{internal\_quantity},\39\\{char\_wd})$;\6 +$\\{primitive}(\.{"charht"},\39\\{internal\_quantity},\39\\{char\_ht})$;\6 +$\\{primitive}(\.{"chardp"},\39\\{internal\_quantity},\39\\{char\_dp})$;\6 +$\\{primitive}(\.{"charic"},\39\\{internal\_quantity},\39\\{char\_ic})$;\6 +$\\{primitive}(\.{"chardx"},\39\\{internal\_quantity},\39\\{char\_dx})$;\6 +$\\{primitive}(\.{"chardy"},\39\\{internal\_quantity},\39\\{char\_dy})$;\6 +$\\{primitive}(\.{"designsize"},\39\\{internal\_quantity},\39\\{design% +\_size})$;\6 +$\\{primitive}(\.{"hppp"},\39\\{internal\_quantity},\39\\{hppp})$;\6 +$\\{primitive}(\.{"vppp"},\39\\{internal\_quantity},\39\\{vppp})$;\6 +$\\{primitive}(\.{"xoffset"},\39\\{internal\_quantity},\39\\{x\_offset})$;\6 +$\\{primitive}(\.{"yoffset"},\39\\{internal\_quantity},\39\\{y\_offset})$;\6 +$\\{primitive}(\.{"pausing"},\39\\{internal\_quantity},\39\\{pausing})$;\6 +$\\{primitive}(\.{"showstopping"},\39\\{internal\_quantity},\39% +\\{showstopping})$;\6 +$\\{primitive}(\.{"fontmaking"},\39\\{internal\_quantity},\39\\{fontmaking})$;\6 +$\\{primitive}(\.{"proofing"},\39\\{internal\_quantity},\39\\{proofing})$;\6 +$\\{primitive}(\.{"smoothing"},\39\\{internal\_quantity},\39\\{smoothing})$;\6 +$\\{primitive}(\.{"autorounding"},\39\\{internal\_quantity},\39% +\\{autorounding})$;\6 +$\\{primitive}(\.{"granularity"},\39\\{internal\_quantity},\39% +\\{granularity})$;\6 +$\\{primitive}(\.{"fillin"},\39\\{internal\_quantity},\39\\{fillin})$;\6 +$\\{primitive}(\.{"turningcheck"},\39\\{internal\_quantity},\39\\{turning% +\_check})$;\6 +$\\{primitive}(\.{"warningcheck"},\39\\{internal\_quantity},\39\\{warning% +\_check})$;\6 +$\\{primitive}(\.{"boundarychar"},\39\\{internal\_quantity},\39\\{boundary% +\_char})$;\par +\As211, 683, 688, 695, 709, 740, 893, 1013, 1018, 1024, 1027, 1037, 1052, 1079, +1101, 1108\ETs1176. +\U1210.\fi + +\M193. Well, we do have to list the names one more time, for use in symbolic +printouts. + +\Y\P$\4\X176:Initialize table entries (done by \.{INIMF} only)\X\mathrel{+}\S$\6 +$\\{int\_name}[\\{tracing\_titles}]\K\.{"tracingtitles"}$;\5 +$\\{int\_name}[\\{tracing\_equations}]\K\.{"tracingequations"}$;\5 +$\\{int\_name}[\\{tracing\_capsules}]\K\.{"tracingcapsules"}$;\5 +$\\{int\_name}[\\{tracing\_choices}]\K\.{"tracingchoices"}$;\5 +$\\{int\_name}[\\{tracing\_specs}]\K\.{"tracingspecs"}$;\5 +$\\{int\_name}[\\{tracing\_pens}]\K\.{"tracingpens"}$;\5 +$\\{int\_name}[\\{tracing\_commands}]\K\.{"tracingcommands"}$;\5 +$\\{int\_name}[\\{tracing\_restores}]\K\.{"tracingrestores"}$;\5 +$\\{int\_name}[\\{tracing\_macros}]\K\.{"tracingmacros"}$;\5 +$\\{int\_name}[\\{tracing\_edges}]\K\.{"tracingedges"}$;\5 +$\\{int\_name}[\\{tracing\_output}]\K\.{"tracingoutput"}$;\5 +$\\{int\_name}[\\{tracing\_stats}]\K\.{"tracingstats"}$;\5 +$\\{int\_name}[\\{tracing\_online}]\K\.{"tracingonline"}$;\5 +$\\{int\_name}[\\{year}]\K\.{"year"}$;\5 +$\\{int\_name}[\\{month}]\K\.{"month"}$;\5 +$\\{int\_name}[\\{day}]\K\.{"day"}$;\5 +$\\{int\_name}[\\{time}]\K\.{"time"}$;\5 +$\\{int\_name}[\\{char\_code}]\K\.{"charcode"}$;\5 +$\\{int\_name}[\\{char\_ext}]\K\.{"charext"}$;\5 +$\\{int\_name}[\\{char\_wd}]\K\.{"charwd"}$;\5 +$\\{int\_name}[\\{char\_ht}]\K\.{"charht"}$;\5 +$\\{int\_name}[\\{char\_dp}]\K\.{"chardp"}$;\5 +$\\{int\_name}[\\{char\_ic}]\K\.{"charic"}$;\5 +$\\{int\_name}[\\{char\_dx}]\K\.{"chardx"}$;\5 +$\\{int\_name}[\\{char\_dy}]\K\.{"chardy"}$;\5 +$\\{int\_name}[\\{design\_size}]\K\.{"designsize"}$;\5 +$\\{int\_name}[\\{hppp}]\K\.{"hppp"}$;\5 +$\\{int\_name}[\\{vppp}]\K\.{"vppp"}$;\5 +$\\{int\_name}[\\{x\_offset}]\K\.{"xoffset"}$;\5 +$\\{int\_name}[\\{y\_offset}]\K\.{"yoffset"}$;\5 +$\\{int\_name}[\\{pausing}]\K\.{"pausing"}$;\5 +$\\{int\_name}[\\{showstopping}]\K\.{"showstopping"}$;\5 +$\\{int\_name}[\\{fontmaking}]\K\.{"fontmaking"}$;\5 +$\\{int\_name}[\\{proofing}]\K\.{"proofing"}$;\5 +$\\{int\_name}[\\{smoothing}]\K\.{"smoothing"}$;\5 +$\\{int\_name}[\\{autorounding}]\K\.{"autorounding"}$;\5 +$\\{int\_name}[\\{granularity}]\K\.{"granularity"}$;\5 +$\\{int\_name}[\\{fillin}]\K\.{"fillin"}$;\5 +$\\{int\_name}[\\{turning\_check}]\K\.{"turningcheck"}$;\5 +$\\{int\_name}[\\{warning\_check}]\K\.{"warningcheck"}$;\5 +$\\{int\_name}[\\{boundary\_char}]\K\.{"boundarychar"}$;\par +\fi + +\M194. The following procedure, which is called just before \MF\ 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. + +Note that the values are \\{scaled} integers. Hence \MF\ can no longer +be used after the year 32767. + +\Y\P\4\&{procedure}\1\ \37\\{fix\_date\_and\_time};\2\6 +\&{begin} \37$\\{internal}[\\{time}]\K12\ast60\ast\\{unity}$;\C{minutes since +midnight}\6 +$\\{internal}[\\{day}]\K4\ast\\{unity}$;\C{fourth day of the month}\6 +$\\{internal}[\\{month}]\K7\ast\\{unity}$;\C{seventh month of the year}\6 +$\\{internal}[\\{year}]\K1776\ast\\{unity}$;\C{Anno Domini}\6 +\&{end};\par +\fi + +\M195. \MF\ is occasionally supposed to print diagnostic information that +goes only into the transcript file, unless \\{tracing\_online} is positive. +Now that we have defined \\{tracing\_online} we can define +two routines that adjust the destination of print commands: + +\Y\P$\4\X57:Basic printing procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{begin\_diagnostic};\C{prepare to do some tracing}\2\6 +\&{begin} \37$\\{old\_setting}\K\\{selector}$;\6 +\&{if} $(\\{internal}[\\{tracing\_online}]\L0)\W(\\{selector}=\\{term\_and% +\_log})$ \1\&{then}\6 +\&{begin} \37$\\{decr}(\\{selector})$;\6 +\&{if} $\\{history}=\\{spotless}$ \1\&{then}\5 +$\\{history}\K\\{warning\_issued}$;\2\6 +\&{end};\2\6 +\&{end};\7 +\4\&{procedure}\1\ \37$\\{end\_diagnostic}(\\{blank\_line}:\\{boolean})$;% +\C{restore proper conditions after tracing}\2\6 +\&{begin} \37$\\{print\_nl}(\.{""})$;\6 +\&{if} $\\{blank\_line}$ \1\&{then}\5 +\\{print\_ln};\2\6 +$\\{selector}\K\\{old\_setting}$;\6 +\&{end};\par +\fi + +\M196. Of course we had better declare another global variable, if the previous +routines are going to work. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{old\_setting}: \37$0\to\\{max\_selector}$;\par +\fi + +\M197. We will occasionally use \\{begin\_diagnostic} in connection with +line-number +printing, as follows. (The parameter \|s is typically \.{"Path"} or +\.{"Cycle\ spec"}, etc.) + +\Y\P$\4\X57:Basic printing procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{print\_diagnostic}(\|s,\39\|t:\\{str\_number};\,\35% +\\{nuline}:\\{boolean})$;\2\6 +\&{begin} \37\\{begin\_diagnostic};\6 +\&{if} $\\{nuline}$ \1\&{then}\5 +$\\{print\_nl}(\|s)$\ \&{else} $\\{print}(\|s)$;\2\6 +$\\{print}(\.{"\ at\ line\ "})$;\5 +$\\{print\_int}(\\{line})$;\5 +$\\{print}(\|t)$;\5 +$\\{print\_char}(\.{":"})$;\6 +\&{end};\par +\fi + +\M198. The 256 \\{ASCII\_code} characters are grouped into classes by means of +the \\{char\_class} table. Individual class numbers have no semantic +or syntactic significance, except in a few instances defined here. +There's also \\{max\_class}, which can be used as a basis for additional +class numbers in nonstandard extensions of \MF. + +\Y\P\D \37$\\{digit\_class}=0$\C{the class number of \.{0123456789}}\par +\P\D \37$\\{period\_class}=1$\C{the class number of `\..'}\par +\P\D \37$\\{space\_class}=2$\C{the class number of spaces and nonstandard +characters}\par +\P\D \37$\\{percent\_class}=3$\C{the class number of `\.\%'}\par +\P\D \37$\\{string\_class}=4$\C{the class number of `\."'}\par +\P\D \37$\\{right\_paren\_class}=8$\C{the class number of `\.)'}\par +\P\D \37$\\{isolated\_classes}\S5,\396,\397,\398$\C{characters that make +length-one tokens only}\par +\P\D \37$\\{letter\_class}=9$\C{letters and the underline character}\par +\P\D \37$\\{left\_bracket\_class}=17$\C{`\.['}\par +\P\D \37$\\{right\_bracket\_class}=18$\C{`\.]'}\par +\P\D \37$\\{invalid\_class}=20$\C{bad character in the input}\par +\P\D \37$\\{max\_class}=20$\C{the largest class number}\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{char\_class}: \37\&{array} $[\\{ASCII\_code}]$ \1\&{of}\5 +$0\to\\{max\_class}$;\C{the class numbers}\2\par +\fi + +\M199. If changes are made to accommodate non-ASCII character sets, they should +follow the guidelines in Appendix~C of {\sl The {\logos METAFONT\/}book}. + +\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +\&{for} $\|k\K\.{"0"}\mathrel{\&{to}}\.{"9"}$ \1\&{do}\5 +$\\{char\_class}[\|k]\K\\{digit\_class}$;\2\6 +$\\{char\_class}[\.{"."}]\K\\{period\_class}$;\5 +$\\{char\_class}[\.{"\ "}]\K\\{space\_class}$;\5 +$\\{char\_class}[\.{"\%"}]\K\\{percent\_class}$;\5 +$\\{char\_class}[\.{""}\.{""}]\K\\{string\_class}$;\6 +$\\{char\_class}[\.{","}]\K5$;\5 +$\\{char\_class}[\.{";"}]\K6$;\5 +$\\{char\_class}[\.{"("}]\K7$;\5 +$\\{char\_class}[\.{")"}]\K\\{right\_paren\_class}$;\6 +\&{for} $\|k\K\.{"A"}\mathrel{\&{to}}\.{"Z"}$ \1\&{do}\5 +$\\{char\_class}[\|k]\K\\{letter\_class}$;\2\6 +\&{for} $\|k\K\.{"a"}\mathrel{\&{to}}\.{"z"}$ \1\&{do}\5 +$\\{char\_class}[\|k]\K\\{letter\_class}$;\2\6 +$\\{char\_class}[\.{"\_"}]\K\\{letter\_class}$;\6 +$\\{char\_class}[\.{"<"}]\K10$;\5 +$\\{char\_class}[\.{"="}]\K10$;\5 +$\\{char\_class}[\.{">"}]\K10$;\5 +$\\{char\_class}[\.{":"}]\K10$;\5 +$\\{char\_class}[\.{"|"}]\K10$;\6 +$\\{char\_class}[\.{"\`"}]\K11$;\5 +$\\{char\_class}[\.{"\'"}]\K11$;\6 +$\\{char\_class}[\.{"+"}]\K12$;\5 +$\\{char\_class}[\.{"-"}]\K12$;\6 +$\\{char\_class}[\.{"/"}]\K13$;\5 +$\\{char\_class}[\.{"*"}]\K13$;\5 +$\\{char\_class}[\.{"\\"}]\K13$;\6 +$\\{char\_class}[\.{"!"}]\K14$;\5 +$\\{char\_class}[\.{"?"}]\K14$;\6 +$\\{char\_class}[\.{"\#"}]\K15$;\5 +$\\{char\_class}[\.{"\&"}]\K15$;\5 +$\\{char\_class}[\.{"@"}]\K15$;\5 +$\\{char\_class}[\.{"\$"}]\K15$;\6 +$\\{char\_class}[\.{"\^"}]\K16$;\5 +$\\{char\_class}[\.{"\~"}]\K16$;\6 +$\\{char\_class}[\.{"["}]\K\\{left\_bracket\_class}$;\5 +$\\{char\_class}[\.{"]"}]\K\\{right\_bracket\_class}$;\6 +$\\{char\_class}[\.{"\{"}]\K19$;\5 +$\\{char\_class}[\.{"\}"}]\K19$;\6 +\&{for} $\|k\K0\mathrel{\&{to}}\.{"\ "}-1$ \1\&{do}\5 +$\\{char\_class}[\|k]\K\\{invalid\_class}$;\2\6 +\&{for} $\|k\K127\mathrel{\&{to}}255$ \1\&{do}\5 +$\\{char\_class}[\|k]\K\\{invalid\_class}$;\2\par +\fi + +\N200. \[13] The hash table. +Symbolic tokens 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 symbolic token enters the +table, it is never removed. + +The actual sequence of characters forming a symbolic token is +stored in the \\{str\_pool} array together with all the other strings. An +auxiliary array \\{hash} consists of items with two halfword fields per +word. The first of these, called $\\{next}(\|p)$, points to the next identifier +belonging to the same coalesced list as the identifier corresponding to~\|p; +and the other, called $\\{text}(\|p)$, points to the \\{str\_start} entry for +\|p's identifier. If position~\|p of the hash table is empty, we have +$\\{text}(\|p)=0$; if position \|p is either empty or the end of a coalesced +hash list, we have $\\{next}(\|p)=0$. + +An auxiliary pointer variable called \\{hash\_used} is maintained in such a +way that all locations $\|p\G\\{hash\_used}$ are nonempty. The global variable +\\{st\_count} tells how many symbolic tokens have been defined, if statistics +are being kept. + +The first 256 locations of \\{hash} are reserved for symbols of length one. + +There's a parallel array called \\{eqtb} that contains the current equivalent +values of each symbolic token. The entries of this array consist of +two halfwords called \\{eq\_type} (a command code) and \\{equiv} (a secondary +piece of information that qualifies the \\{eq\_type}). + +\Y\P\D \37$\\{next}(\#)\S\\{hash}[\#].\\{lh}$\C{link for coalesced lists}\par +\P\D \37$\\{text}(\#)\S\\{hash}[\#].\\{rh}$\C{string number for symbolic token +name}\par +\P\D \37$\\{eq\_type}(\#)\S\\{eqtb}[\#].\\{lh}$\C{the current ``meaning'' of a +symbolic token}\par +\P\D \37$\\{equiv}(\#)\S\\{eqtb}[\#].\\{rh}$\C{parametric part of a token's +meaning}\par +\P\D \37$\\{hash\_base}=257$\C{hashing actually starts here}\par +\P\D \37$\\{hash\_is\_full}\S(\\{hash\_used}=\\{hash\_base})$\C{are all +positions occupied?}\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{hash\_used}: \37\\{pointer};\C{allocation pointer for \\{hash}}\6 +\4\\{st\_count}: \37\\{integer};\C{total number of known identifiers}\par +\fi + +\M201. Certain entries in the hash table are ``frozen'' and not redefinable, +since they are used in error recovery. + +\Y\P\D \37$\\{hash\_top}\S\\{hash\_base}+\\{hash\_size}$\C{the first location +of the frozen area}\par +\P\D \37$\\{frozen\_inaccessible}\S\\{hash\_top}$\C{\\{hash} location to +protect the frozen area}\par +\P\D \37$\\{frozen\_repeat\_loop}\S\\{hash\_top}+1$\C{\\{hash} location of a +loop-repeat token}\par +\P\D \37$\\{frozen\_right\_delimiter}\S\\{hash\_top}+2$\C{\\{hash} location of +a permanent `\.)'}\par +\P\D \37$\\{frozen\_left\_bracket}\S\\{hash\_top}+3$\C{\\{hash} location of a +permanent `\.['}\par +\P\D \37$\\{frozen\_slash}\S\\{hash\_top}+4$\C{\\{hash} location of a permanent +`\./'}\par +\P\D \37$\\{frozen\_colon}\S\\{hash\_top}+5$\C{\\{hash} location of a permanent +`\.:'}\par +\P\D \37$\\{frozen\_semicolon}\S\\{hash\_top}+6$\C{\\{hash} location of a +permanent `\.;'}\par +\P\D \37$\\{frozen\_end\_for}\S\\{hash\_top}+7$\C{\\{hash} location of a +permanent \&{endfor}}\par +\P\D \37$\\{frozen\_end\_def}\S\\{hash\_top}+8$\C{\\{hash} location of a +permanent \&{enddef}}\par +\P\D \37$\\{frozen\_fi}\S\\{hash\_top}+9$\C{\\{hash} location of a permanent % +\&{fi}}\par +\P\D \37$\\{frozen\_end\_group}\S\\{hash\_top}+10$\C{\\{hash} location of a +permanent `\.{endgroup}'}\par +\P\D \37$\\{frozen\_bad\_vardef}\S\\{hash\_top}+11$\C{\\{hash} location of `% +\.{a bad variable}'}\par +\P\D \37$\\{frozen\_undefined}\S\\{hash\_top}+12$\C{\\{hash} location that +never gets defined}\par +\P\D \37$\\{hash\_end}\S\\{hash\_top}+12$\C{the actual size of the \\{hash} and +\\{eqtb} arrays}\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{hash}: \37\&{array} $[1\to\\{hash\_end}]$ \1\&{of}\5 +\\{two\_halves};\C{the hash table}\2\6 +\4\\{eqtb}: \37\&{array} $[1\to\\{hash\_end}]$ \1\&{of}\5 +\\{two\_halves};\C{the equivalents}\2\par +\fi + +\M202. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{next}(1)\K0$;\5 +$\\{text}(1)\K0$;\5 +$\\{eq\_type}(1)\K\\{tag\_token}$;\5 +$\\{equiv}(1)\K\\{null}$;\6 +\&{for} $\|k\K2\mathrel{\&{to}}\\{hash\_end}$ \1\&{do}\6 +\&{begin} \37$\\{hash}[\|k]\K\\{hash}[1]$;\5 +$\\{eqtb}[\|k]\K\\{eqtb}[1]$;\6 +\&{end};\2\par +\fi + +\M203. \P$\X176:Initialize table entries (done by \.{INIMF} only)\X\mathrel{+}% +\S$\6 +$\\{hash\_used}\K\\{frozen\_inaccessible}$;\C{nothing is used}\6 +$\\{st\_count}\K0$;\6 +$\\{text}(\\{frozen\_bad\_vardef})\K\.{"a\ bad\ variable"}$;\5 +$\\{text}(\\{frozen\_fi})\K\.{"fi"}$;\5 +$\\{text}(\\{frozen\_end\_group})\K\.{"endgroup"}$;\5 +$\\{text}(\\{frozen\_end\_def})\K\.{"enddef"}$;\5 +$\\{text}(\\{frozen\_end\_for})\K\.{"endfor"}$;\6 +$\\{text}(\\{frozen\_semicolon})\K\.{";"}$;\5 +$\\{text}(\\{frozen\_colon})\K\.{":"}$;\5 +$\\{text}(\\{frozen\_slash})\K\.{"/"}$;\5 +$\\{text}(\\{frozen\_left\_bracket})\K\.{"["}$;\5 +$\\{text}(\\{frozen\_right\_delimiter})\K\.{")"}$;\6 +$\\{text}(\\{frozen\_inaccessible})\K\.{"\ INACCESSIBLE"}$;\6 +$\\{eq\_type}(\\{frozen\_right\_delimiter})\K\\{right\_delimiter}$;\par +\fi + +\M204. \P$\X14:Check the ``constant'' values for consistency\X\mathrel{+}\S$\6 +\&{if} $\\{hash\_end}+\\{max\_internal}>\\{max\_halfword}$ \1\&{then}\5 +$\\{bad}\K21$;\2\par +\fi + +\M205. Here is the subroutine that searches the hash table for an identifier +that matches a given string of length~\|l appearing in $\\{buffer}[\|j\to(\|j+% +\|l-1)]$. If the identifier is not found, it is inserted; hence it +will always be found, and the corresponding hash table address +will be returned. + +\Y\P\4\&{function}\1\ \37$\\{id\_lookup}(\|j,\39\|l:\\{integer})$: \37% +\\{pointer};\C{search the hash table}\6 +\4\&{label} \37\\{found};\C{go here when you've found it}\6 +\4\&{var} \37\|h: \37\\{integer};\C{hash code}\6 +\|p: \37\\{pointer};\C{index in \\{hash} array}\6 +\|k: \37\\{pointer};\C{index in \\{buffer} array}\2\6 +\&{begin} \37\&{if} $\|l=1$ \1\&{then}\5 +\X206:Treat special case of length 1 and \&{goto} \\{found}\X;\2\6 +\X208:Compute the hash code \|h\X;\6 +$\|p\K\|h+\\{hash\_base}$;\C{we start searching here; note that $0\L\|h<\\{hash% +\_prime}$}\6 +\~ \1\&{loop}\ \&{begin} \37\&{if} $\\{text}(\|p)>0$ \1\&{then}\6 +\&{if} $\\{length}(\\{text}(\|p))=\|l$ \1\&{then}\6 +\&{if} $\\{str\_eq\_buf}(\\{text}(\|p),\39\|j)$ \1\&{then}\5 +\&{goto} \37\\{found};\2\2\2\6 +\&{if} $\\{next}(\|p)=0$ \1\&{then}\5 +\X207:Insert a new symbolic token after \|p, then make \|p point to it and % +\&{goto} \\{found}\X;\2\6 +$\|p\K\\{next}(\|p)$;\6 +\&{end};\2\6 +\4\\{found}: \37$\\{id\_lookup}\K\|p$;\6 +\&{end};\par +\fi + +\M206. \P$\X206:Treat special case of length 1 and \&{goto} \\{found}\X\S$\6 +\&{begin} \37$\|p\K\\{buffer}[\|j]+1$;\5 +$\\{text}(\|p)\K\|p-1$;\5 +\&{goto} \37\\{found};\6 +\&{end}\par +\U205.\fi + +\M207. \P$\X207:Insert a new symbolic token after \|p, then make \|p point to +it and \&{goto} \\{found}\X\S$\6 +\&{begin} \37\&{if} $\\{text}(\|p)>0$ \1\&{then}\6 +\&{begin} \37\1\&{repeat} \37\&{if} $\\{hash\_is\_full}$ \1\&{then}\5 +$\\{overflow}(\.{"hash\ size"},\39\\{hash\_size})$;\2\6 +$\\{decr}(\\{hash\_used})$;\6 +\4\&{until}\5 +$\\{text}(\\{hash\_used})=0$;\C{search for an empty location in \\{hash}}\2\6 +$\\{next}(\|p)\K\\{hash\_used}$;\5 +$\|p\K\\{hash\_used}$;\6 +\&{end};\2\6 +$\\{str\_room}(\|l)$;\6 +\&{for} $\|k\K\|j\mathrel{\&{to}}\|j+\|l-1$ \1\&{do}\5 +$\\{append\_char}(\\{buffer}[\|k])$;\2\6 +$\\{text}(\|p)\K\\{make\_string}$;\5 +$\\{str\_ref}[\\{text}(\|p)]\K\\{max\_str\_ref}$;\6 +\&{stat} \37$\\{incr}(\\{st\_count})$;\ \&{tats}\6 +\&{goto} \37\\{found};\6 +\&{end}\par +\U205.\fi + +\M208. The value of \\{hash\_prime} should be roughly 85\pct! of \\{hash% +\_size}, and it +should be a prime number. The theory of hashing tells us to expect fewer +than two table probes, on the average, when the search is successful. +[See J.~S. Vitter, {\sl Journal of the ACM\/ \bf30} (1983), 231--258.] + +\Y\P$\4\X208:Compute the hash code \|h\X\S$\6 +$\|h\K\\{buffer}[\|j]$;\6 +\&{for} $\|k\K\|j+1\mathrel{\&{to}}\|j+\|l-1$ \1\&{do}\6 +\&{begin} \37$\|h\K\|h+\|h+\\{buffer}[\|k]$;\6 +\&{while} $\|h\G\\{hash\_prime}$ \1\&{do}\5 +$\|h\K\|h-\\{hash\_prime}$;\2\6 +\&{end}\2\par +\U205.\fi + +\M209. \P$\X209:Search \\{eqtb} for equivalents equal to \|p\X\S$\6 +\&{for} $\|q\K1\mathrel{\&{to}}\\{hash\_end}$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{equiv}(\|q)=\|p$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"EQUIV("})$;\5 +$\\{print\_int}(\|q)$;\5 +$\\{print\_char}(\.{")"})$;\6 +\&{end};\2\6 +\&{end}\2\par +\U185.\fi + +\M210. We need to put \MF's ``primitive'' symbolic tokens 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 \MF\ user can. The global value \\{cur\_sym} +contains the new \\{eqtb} pointer after \\{primitive} has acted. + +\Y\P\&{init} \37\&{procedure}\1\ \37$\\{primitive}(\|s:\\{str\_number};\,\35% +\|c:\\{halfword};\,\35\|o:\\{halfword})$;\6 +\4\&{var} \37\|k: \37\\{pool\_pointer};\C{index into \\{str\_pool}}\6 +\|j: \37\\{small\_number};\C{index into \\{buffer}}\6 +\|l: \37\\{small\_number};\C{length of the string}\2\6 +\&{begin} \37$\|k\K\\{str\_start}[\|s]$;\5 +$\|l\K\\{str\_start}[\|s+1]-\|k$;\C{we will move \|s into the (empty) % +\\{buffer}}\6 +\&{for} $\|j\K0\mathrel{\&{to}}\|l-1$ \1\&{do}\5 +$\\{buffer}[\|j]\K\\{so}(\\{str\_pool}[\|k+\|j])$;\2\6 +$\\{cur\_sym}\K\\{id\_lookup}(0,\39\|l)$;\6 +\&{if} $\|s\G256$ \1\&{then}\C{we don't want to have the string twice}\6 +\&{begin} \37$\\{flush\_string}(\\{str\_ptr}-1)$;\5 +$\\{text}(\\{cur\_sym})\K\|s$;\6 +\&{end};\2\6 +$\\{eq\_type}(\\{cur\_sym})\K\|c$;\5 +$\\{equiv}(\\{cur\_sym})\K\|o$;\6 +\&{end};\6 +\&{tini}\par +\fi + +\M211. Many of \MF's primitives need no \\{equiv}, since they are identifiable +by their \\{eq\_type} alone. These primitives are loaded into the hash table +as follows: + +\Y\P$\4\X192:Put each of \MF's primitives into the hash table\X\mathrel{+}\S$\6 +$\\{primitive}(\.{".."},\39\\{path\_join},\390)$;\6 +$\\{primitive}(\.{"["},\39\\{left\_bracket},\390)$;\5 +$\\{eqtb}[\\{frozen\_left\_bracket}]\K\\{eqtb}[\\{cur\_sym}]$;\6 +$\\{primitive}(\.{"]"},\39\\{right\_bracket},\390)$;\6 +$\\{primitive}(\.{"\}"},\39\\{right\_brace},\390)$;\6 +$\\{primitive}(\.{"\{"},\39\\{left\_brace},\390)$;\6 +$\\{primitive}(\.{":"},\39\\{colon},\390)$;\5 +$\\{eqtb}[\\{frozen\_colon}]\K\\{eqtb}[\\{cur\_sym}]$;\6 +$\\{primitive}(\.{"::"},\39\\{double\_colon},\390)$;\6 +$\\{primitive}(\.{"||:"},\39\\{bchar\_label},\390)$;\6 +$\\{primitive}(\.{":="},\39\\{assignment},\390)$;\6 +$\\{primitive}(\.{","},\39\\{comma},\390)$;\6 +$\\{primitive}(\.{";"},\39\\{semicolon},\390)$;\5 +$\\{eqtb}[\\{frozen\_semicolon}]\K\\{eqtb}[\\{cur\_sym}]$;\6 +$\\{primitive}(\.{"\\"},\39\\{relax},\390)$;\7 +$\\{primitive}(\.{"addto"},\39\\{add\_to\_command},\390)$;\6 +$\\{primitive}(\.{"at"},\39\\{at\_token},\390)$;\6 +$\\{primitive}(\.{"atleast"},\39\\{at\_least},\390)$;\6 +$\\{primitive}(\.{"begingroup"},\39\\{begin\_group},\390)$;\5 +$\\{bg\_loc}\K\\{cur\_sym}$;\6 +$\\{primitive}(\.{"controls"},\39\\{controls},\390)$;\6 +$\\{primitive}(\.{"cull"},\39\\{cull\_command},\390)$;\6 +$\\{primitive}(\.{"curl"},\39\\{curl\_command},\390)$;\6 +$\\{primitive}(\.{"delimiters"},\39\\{delimiters},\390)$;\6 +$\\{primitive}(\.{"display"},\39\\{display\_command},\390)$;\6 +$\\{primitive}(\.{"endgroup"},\39\\{end\_group},\390)$;\5 +$\\{eqtb}[\\{frozen\_end\_group}]\K\\{eqtb}[\\{cur\_sym}]$;\5 +$\\{eg\_loc}\K\\{cur\_sym}$;\6 +$\\{primitive}(\.{"everyjob"},\39\\{every\_job\_command},\390)$;\6 +$\\{primitive}(\.{"exitif"},\39\\{exit\_test},\390)$;\6 +$\\{primitive}(\.{"expandafter"},\39\\{expand\_after},\390)$;\6 +$\\{primitive}(\.{"from"},\39\\{from\_token},\390)$;\6 +$\\{primitive}(\.{"inwindow"},\39\\{in\_window},\390)$;\6 +$\\{primitive}(\.{"interim"},\39\\{interim\_command},\390)$;\6 +$\\{primitive}(\.{"let"},\39\\{let\_command},\390)$;\6 +$\\{primitive}(\.{"newinternal"},\39\\{new\_internal},\390)$;\6 +$\\{primitive}(\.{"of"},\39\\{of\_token},\390)$;\6 +$\\{primitive}(\.{"openwindow"},\39\\{open\_window},\390)$;\6 +$\\{primitive}(\.{"randomseed"},\39\\{random\_seed},\390)$;\6 +$\\{primitive}(\.{"save"},\39\\{save\_command},\390)$;\6 +$\\{primitive}(\.{"scantokens"},\39\\{scan\_tokens},\390)$;\6 +$\\{primitive}(\.{"shipout"},\39\\{ship\_out\_command},\390)$;\6 +$\\{primitive}(\.{"skipto"},\39\\{skip\_to},\390)$;\6 +$\\{primitive}(\.{"step"},\39\\{step\_token},\390)$;\6 +$\\{primitive}(\.{"str"},\39\\{str\_op},\390)$;\6 +$\\{primitive}(\.{"tension"},\39\\{tension},\390)$;\6 +$\\{primitive}(\.{"to"},\39\\{to\_token},\390)$;\6 +$\\{primitive}(\.{"until"},\39\\{until\_token},\390)$;\par +\fi + +\M212. 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\_mod} routine +explained below. + +\Y\P$\4\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of primitives\X% +\S$\6 +\4\\{add\_to\_command}: \37$\\{print}(\.{"addto"})$;\6 +\4\\{assignment}: \37$\\{print}(\.{":="})$;\6 +\4\\{at\_least}: \37$\\{print}(\.{"atleast"})$;\6 +\4\\{at\_token}: \37$\\{print}(\.{"at"})$;\6 +\4\\{bchar\_label}: \37$\\{print}(\.{"||:"})$;\6 +\4\\{begin\_group}: \37$\\{print}(\.{"begingroup"})$;\6 +\4\\{colon}: \37$\\{print}(\.{":"})$;\6 +\4\\{comma}: \37$\\{print}(\.{","})$;\6 +\4\\{controls}: \37$\\{print}(\.{"controls"})$;\6 +\4\\{cull\_command}: \37$\\{print}(\.{"cull"})$;\6 +\4\\{curl\_command}: \37$\\{print}(\.{"curl"})$;\6 +\4\\{delimiters}: \37$\\{print}(\.{"delimiters"})$;\6 +\4\\{display\_command}: \37$\\{print}(\.{"display"})$;\6 +\4\\{double\_colon}: \37$\\{print}(\.{"::"})$;\6 +\4\\{end\_group}: \37$\\{print}(\.{"endgroup"})$;\6 +\4\\{every\_job\_command}: \37$\\{print}(\.{"everyjob"})$;\6 +\4\\{exit\_test}: \37$\\{print}(\.{"exitif"})$;\6 +\4\\{expand\_after}: \37$\\{print}(\.{"expandafter"})$;\6 +\4\\{from\_token}: \37$\\{print}(\.{"from"})$;\6 +\4\\{in\_window}: \37$\\{print}(\.{"inwindow"})$;\6 +\4\\{interim\_command}: \37$\\{print}(\.{"interim"})$;\6 +\4\\{left\_brace}: \37$\\{print}(\.{"\{"})$;\6 +\4\\{left\_bracket}: \37$\\{print}(\.{"["})$;\6 +\4\\{let\_command}: \37$\\{print}(\.{"let"})$;\6 +\4\\{new\_internal}: \37$\\{print}(\.{"newinternal"})$;\6 +\4\\{of\_token}: \37$\\{print}(\.{"of"})$;\6 +\4\\{open\_window}: \37$\\{print}(\.{"openwindow"})$;\6 +\4\\{path\_join}: \37$\\{print}(\.{".."})$;\6 +\4\\{random\_seed}: \37$\\{print}(\.{"randomseed"})$;\6 +\4\\{relax}: \37$\\{print\_char}(\.{"\\"})$;\6 +\4\\{right\_brace}: \37$\\{print}(\.{"\}"})$;\6 +\4\\{right\_bracket}: \37$\\{print}(\.{"]"})$;\6 +\4\\{save\_command}: \37$\\{print}(\.{"save"})$;\6 +\4\\{scan\_tokens}: \37$\\{print}(\.{"scantokens"})$;\6 +\4\\{semicolon}: \37$\\{print}(\.{";"})$;\6 +\4\\{ship\_out\_command}: \37$\\{print}(\.{"shipout"})$;\6 +\4\\{skip\_to}: \37$\\{print}(\.{"skipto"})$;\6 +\4\\{step\_token}: \37$\\{print}(\.{"step"})$;\6 +\4\\{str\_op}: \37$\\{print}(\.{"str"})$;\6 +\4\\{tension}: \37$\\{print}(\.{"tension"})$;\6 +\4\\{to\_token}: \37$\\{print}(\.{"to"})$;\6 +\4\\{until\_token}: \37$\\{print}(\.{"until"})$;\par +\As684, 689, 696, 710, 741, 894, 1014, 1019, 1025, 1028, 1038, 1043, 1053, +1080, 1102, 1109\ETs1180. +\U625.\fi + +\M213. 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 macro definitions will be loaded when we consider the +routines that define macros. +It is easy to find where each particular +primitive was treated by looking in the index at the end; for example, the +section where \.{"def"} entered \\{eqtb} is listed under `\&{def} primitive'. + +\fi + +\N214. \[14] Token lists. +A \MF\ token is either symbolic or numeric or a string, or it denotes +a macro parameter or capsule; so there are five corresponding ways to encode it +internally: (1)~A symbolic token whose hash code is~\|p +is represented by the number \|p, in the \\{info} field of a single-word +node in~\\{mem}. (2)~A numeric token whose \\{scaled} value is~\|v is +represented in a two-word node of~\\{mem}; the \\{type} field is \\{known}, +the \\{name\_type} field is \\{token}, and the \\{value} field holds~\|v. +The fact that this token appears in a two-word node rather than a +one-word node is, of course, clear from the node address. +(3)~A string token is also represented in a two-word node; the \\{type} +field is \\{string\_type}, the \\{name\_type} field is \\{token}, and the +\\{value} field holds the corresponding \\{str\_number}. (4)~Capsules have +$\\{name\_type}=\\{capsule}$, and their \\{type} and \\{value} fields represent +arbitrary values (in ways to be explained later). (5)~Macro parameters +are like symbolic tokens in that they appear in \\{info} fields of +one-word nodes. The $k$th parameter is represented by $\\{expr\_base}+\|k$ if +it +is of type \&{expr}, or by $\\{suffix\_base}+\|k$ if it is of type \&{suffix}, +or +by $\\{text\_base}+\|k$ if it is of type \&{text}. (Here $0\L\|k<\\{param% +\_size}$.) +Actual values of these parameters are kept in a separate stack, as we will +see later. The constants \\{expr\_base}, \\{suffix\_base}, and \\{text\_base} +are, +of course, chosen so that there will be no confusion between symbolic +tokens and parameters of various types. + +It turns out that $\\{value}(\\{null})=0$, because $\\{null}=\\{null\_coords}$; +we will make use of this coincidence later. + +Incidentally, while we're speaking of coincidences, we might note that +the `\\{type}' field of a node has nothing to do with ``type'' in a +printer's sense. It's curious that the same word is used in such different +ways. + +\Y\P\D \37$\\{type}(\#)\S\\{mem}[\#].\\{hh}.\\{b0}$\C{identifies what kind of +value this is}\par +\P\D \37$\\{name\_type}(\#)\S\\{mem}[\#].\\{hh}.\\{b1}$\C{a clue to the name of +this value}\par +\P\D \37$\\{token\_node\_size}=2$\C{the number of words in a large token node}% +\par +\P\D \37$\\{value\_loc}(\#)\S\#+1$\C{the word that contains the \\{value} +field}\par +\P\D \37$\\{value}(\#)\S\\{mem}[\\{value\_loc}(\#)].\\{int}$\C{the value stored +in a large token node}\par +\P\D \37$\\{expr\_base}\S\\{hash\_end}+1$\C{code for the zeroth \&{expr} +parameter}\par +\P\D \37$\\{suffix\_base}\S\\{expr\_base}+\\{param\_size}$\C{code for the +zeroth \&{suffix} parameter}\par +\P\D \37$\\{text\_base}\S\\{suffix\_base}+\\{param\_size}$\C{code for the +zeroth \&{text} parameter}\par +\Y\P$\4\X14:Check the ``constant'' values for consistency\X\mathrel{+}\S$\6 +\&{if} $\\{text\_base}+\\{param\_size}>\\{max\_halfword}$ \1\&{then}\5 +$\\{bad}\K22$;\2\par +\fi + +\M215. A numeric token is created by the following trivial routine. + +\Y\P\4\&{function}\1\ \37$\\{new\_num\_tok}(\|v:\\{scaled})$: \37\\{pointer};\6 +\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\2\6 +\&{begin} \37$\|p\K\\{get\_node}(\\{token\_node\_size})$;\5 +$\\{value}(\|p)\K\|v$;\5 +$\\{type}(\|p)\K\\{known}$;\5 +$\\{name\_type}(\|p)\K\\{token}$;\5 +$\\{new\_num\_tok}\K\|p$;\6 +\&{end};\par +\fi + +\M216. A token list is a singly linked list of nodes in \\{mem}, where +each node contains a token and a link. Here's a subroutine that gets rid +of a token list when it is no longer needed. + +\Y\P\4\&{procedure}\1\ \37\\{token\_recycle};\5 +\\{forward};\5 +\hbox{\2}\6 +\4\&{procedure}\1\ \37$\\{flush\_token\_list}(\|p:\\{pointer})$;\6 +\4\&{var} \37\|q: \37\\{pointer};\C{the node being recycled}\2\6 +\&{begin} \37\&{while} $\|p\I\\{null}$ \1\&{do}\6 +\&{begin} \37$\|q\K\|p$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{if} $\|q\G\\{hi\_mem\_min}$ \1\&{then}\5 +$\\{free\_avail}(\|q)$\6 +\4\&{else} \&{begin} \37\&{case} $\\{type}(\|q)$ \1\&{of}\6 +\4$\\{vacuous},\39\\{boolean\_type},\39\\{known}$: \37\\{do\_nothing};\6 +\4\\{string\_type}: \37$\\{delete\_str\_ref}(\\{value}(\|q))$;\6 +\4$\\{unknown\_types},\39\\{pen\_type},\39\\{path\_type},\39\\{future\_pen},\39% +\\{picture\_type},\39\\{pair\_type},\39\\{transform\_type},\39\\{dependent},\39% +\\{proto\_dependent},\39\\{independent}$: \37\&{begin} \37$\\{g\_pointer}\K% +\|q$;\5 +\\{token\_recycle};\6 +\&{end};\6 +\4\&{othercases} \37$\\{confusion}(\.{"token"})$\2\6 +\&{endcases};\6 +$\\{free\_node}(\|q,\39\\{token\_node\_size})$;\6 +\&{end};\2\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M217. 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 fairly robust, so that if the +memory links are awry or if \|p is not really a pointer to a token list, +almost nothing catastrophic can 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.) + +The generation will stop, and `\.{\char`\ ETC.}' will be printed, if the length +of printing exceeds a given limit~\|l; the length of printing upon entry is +assumed to be a given amount called \\{null\_tally}. (Note that +\\{show\_token\_list} sometimes uses itself recursively to print +variable names within a capsule.) + +Unusual entries are printed in the form of all-caps tokens +preceded by a space, e.g., `\.{\char`\ BAD}'. + +\Y\P$\4\X217:Declare the procedure called \\{show\_token\_list}\X\S$\6 +\4\&{procedure}\1\ \37\\{print\_capsule};\5 +\\{forward};\5 +\hbox{\2}\6 +\4\&{procedure}\1\ \37$\\{show\_token\_list}(\|p,\39\|q:\\{integer};\,\35\|l,% +\39\\{null\_tally}:\\{integer})$;\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37$\\{class},\39\|c$: \37\\{small\_number};\C{the \\{char\_class} of +previous and new tokens}\6 +$\|r,\39\|v$: \37\\{integer};\C{temporary registers}\2\6 +\&{begin} \37$\\{class}\K\\{percent\_class}$;\5 +$\\{tally}\K\\{null\_tally}$;\6 +\&{while} $(\|p\I\\{null})\W(\\{tally}<\|l)$ \1\&{do}\6 +\&{begin} \37\&{if} $\|p=\|q$ \1\&{then}\5 +\X646:Do magic computation\X;\2\6 +\X218:Display token \|p and set \|c to its class; but \&{return} if there are +problems\X;\6 +$\\{class}\K\|c$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +\&{if} $\|p\I\\{null}$ \1\&{then}\5 +$\\{print}(\.{"\ ETC."})$;\2\6 +\4\\{exit}: \37\&{end};\par +\U162.\fi + +\M218. \P$\X218:Display token \|p and set \|c to its class; but \&{return} if +there are problems\X\S$\6 +$\|c\K\\{letter\_class}$;\C{the default}\6 +\&{if} $(\|p<\\{mem\_min})\V(\|p>\\{mem\_end})$ \1\&{then}\6 +\&{begin} \37$\\{print}(\.{"\ CLOBBERED"})$;\5 +\&{return};\6 +\&{end};\2\6 +\&{if} $\|p<\\{hi\_mem\_min}$ \1\&{then}\5 +\X219:Display two-word token\X\6 +\4\&{else} \&{begin} \37$\|r\K\\{info}(\|p)$;\6 +\&{if} $\|r\G\\{expr\_base}$ \1\&{then}\5 +\X222:Display a parameter token\X\6 +\4\&{else} \&{if} $\|r<1$ \1\&{then}\6 +\&{if} $\|r=0$ \1\&{then}\5 +\X221:Display a collective subscript\X\6 +\4\&{else} $\\{print}(\.{"\ IMPOSSIBLE"})$\2\6 +\4\&{else} \&{begin} \37$\|r\K\\{text}(\|r)$;\6 +\&{if} $(\|r<0)\V(\|r\G\\{str\_ptr})$ \1\&{then}\5 +$\\{print}(\.{"\ NONEXISTENT"})$\6 +\4\&{else} \X223:Print string \|r as a symbolic token and set \|c to its class% +\X;\2\6 +\&{end};\2\2\6 +\&{end}\2\par +\U217.\fi + +\M219. \P$\X219:Display two-word token\X\S$\6 +\&{if} $\\{name\_type}(\|p)=\\{token}$ \1\&{then}\6 +\&{if} $\\{type}(\|p)=\\{known}$ \1\&{then}\5 +\X220:Display a numeric token\X\6 +\4\&{else} \&{if} $\\{type}(\|p)\I\\{string\_type}$ \1\&{then}\5 +$\\{print}(\.{"\ BAD"})$\6 +\4\&{else} \&{begin} \37$\\{print\_char}(\.{""}\.{""})$;\5 +$\\{slow\_print}(\\{value}(\|p))$;\5 +$\\{print\_char}(\.{""}\.{""})$;\5 +$\|c\K\\{string\_class}$;\6 +\&{end}\2\2\6 +\4\&{else} \&{if} $(\\{name\_type}(\|p)\I\\{capsule})\V(\\{type}(\|p)<% +\\{vacuous})\V(\\{type}(\|p)>\\{independent})$ \1\&{then}\5 +$\\{print}(\.{"\ BAD"})$\6 +\4\&{else} \&{begin} \37$\\{g\_pointer}\K\|p$;\5 +\\{print\_capsule};\5 +$\|c\K\\{right\_paren\_class}$;\6 +\&{end}\2\2\par +\U218.\fi + +\M220. \P$\X220:Display a numeric token\X\S$\6 +\&{begin} \37\&{if} $\\{class}=\\{digit\_class}$ \1\&{then}\5 +$\\{print\_char}(\.{"\ "})$;\2\6 +$\|v\K\\{value}(\|p)$;\6 +\&{if} $\|v<0$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{class}=\\{left\_bracket\_class}$ \1\&{then}\5 +$\\{print\_char}(\.{"\ "})$;\2\6 +$\\{print\_char}(\.{"["})$;\5 +$\\{print\_scaled}(\|v)$;\5 +$\\{print\_char}(\.{"]"})$;\5 +$\|c\K\\{right\_bracket\_class}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{print\_scaled}(\|v)$;\5 +$\|c\K\\{digit\_class}$;\6 +\&{end};\2\6 +\&{end}\par +\U219.\fi + +\M221. Strictly speaking, a genuine token will never have $\\{info}(\|p)=0$. +But we will see later (in the \\{print\_variable\_name} routine) that +it is convenient to let $\\{info}(\|p)=0$ stand for `\.{[]}'. + +\Y\P$\4\X221:Display a collective subscript\X\S$\6 +\&{begin} \37\&{if} $\\{class}=\\{left\_bracket\_class}$ \1\&{then}\5 +$\\{print\_char}(\.{"\ "})$;\2\6 +$\\{print}(\.{"[]"})$;\5 +$\|c\K\\{right\_bracket\_class}$;\6 +\&{end}\par +\U218.\fi + +\M222. \P$\X222:Display a parameter token\X\S$\6 +\&{begin} \37\&{if} $\|r<\\{suffix\_base}$ \1\&{then}\6 +\&{begin} \37$\\{print}(\.{"(EXPR"})$;\5 +$\|r\K\|r-(\\{expr\_base})$;\6 +\&{end}\6 +\4\&{else} \&{if} $\|r<\\{text\_base}$ \1\&{then}\6 +\&{begin} \37$\\{print}(\.{"(SUFFIX"})$;\5 +$\|r\K\|r-(\\{suffix\_base})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{print}(\.{"(TEXT"})$;\5 +$\|r\K\|r-(\\{text\_base})$;\6 +\&{end};\2\2\6 +$\\{print\_int}(\|r)$;\5 +$\\{print\_char}(\.{")"})$;\5 +$\|c\K\\{right\_paren\_class}$;\6 +\&{end}\par +\U218.\fi + +\M223. \P$\X223:Print string \|r as a symbolic token and set \|c to its class\X% +\S$\6 +\&{begin} \37$\|c\K\\{char\_class}[\\{so}(\\{str\_pool}[\\{str\_start}[% +\|r]])]$;\6 +\&{if} $\|c=\\{class}$ \1\&{then}\6 +\&{case} $\|c$ \1\&{of}\6 +\4\\{letter\_class}: \37$\\{print\_char}(\.{"."})$;\6 +\4\\{isolated\_classes}: \37\\{do\_nothing};\6 +\4\&{othercases} \37$\\{print\_char}(\.{"\ "})$\2\6 +\&{endcases};\2\6 +$\\{slow\_print}(\|r)$;\6 +\&{end}\par +\U218.\fi + +\M224. The following procedures have been declared \\{forward} with no +parameters, +because the author dislikes \PASCAL's convention about \\{forward} procedures +with parameters. It was necessary to do something, because \\{show\_token% +\_list} +is recursive (although the recursion is limited to one level), and because +\\{flush\_token\_list} is syntactically (but not semantically) recursive. + +\Y\P$\4\X224:Declare miscellaneous procedures that were declared \\{forward}\X% +\S$\6 +\4\&{procedure}\1\ \37\\{print\_capsule};\2\6 +\&{begin} \37$\\{print\_char}(\.{"("})$;\5 +$\\{print\_exp}(\\{g\_pointer},\390)$;\5 +$\\{print\_char}(\.{")"})$;\6 +\&{end};\7 +\4\&{procedure}\1\ \37\\{token\_recycle};\2\6 +\&{begin} \37$\\{recycle\_value}(\\{g\_pointer})$;\6 +\&{end};\par +\U1202.\fi + +\M225. \P$\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{g\_pointer}: \37\\{pointer};\C{(global) parameter to the \\{forward} +procedures}\par +\fi + +\M226. Macro definitions are kept in \MF's memory in the form of token lists +that have a few extra one-word nodes at the beginning. + +The first node contains a reference count that is used to tell when the +list is no longer needed. To emphasize the fact that a reference count is +present, we shall refer to the \\{info} field of this special node as the +\\{ref\_count} field. + +The next node or nodes after the reference count serve to describe the +formal parameters. They either contain a code word that specifies all +of the parameters, or they contain zero or more parameter tokens followed +by the code `\\{general\_macro}'. + +\Y\P\D \37$\\{ref\_count}\S\\{info}$\C{reference count preceding a macro +definition or pen header}\par +\P\D \37$\\{add\_mac\_ref}(\#)\S\\{incr}(\\{ref\_count}(\#))$\C{make a new +reference to a macro list}\par +\P\D \37$\\{general\_macro}=0$\C{preface to a macro defined with a parameter +list}\par +\P\D \37$\\{primary\_macro}=1$\C{preface to a macro with a \&{primary} +parameter}\par +\P\D \37$\\{secondary\_macro}=2$\C{preface to a macro with a \&{secondary} +parameter}\par +\P\D \37$\\{tertiary\_macro}=3$\C{preface to a macro with a \&{tertiary} +parameter}\par +\P\D \37$\\{expr\_macro}=4$\C{preface to a macro with an undelimited \&{expr} +parameter}\par +\P\D \37$\\{of\_macro}=5$\C{preface to a macro with undelimited `\&{expr} \|x +\&{of}~\|y' parameters}\par +\P\D \37$\\{suffix\_macro}=6$\C{preface to a macro with an undelimited % +\&{suffix} parameter}\par +\P\D \37$\\{text\_macro}=7$\C{preface to a macro with an undelimited \&{text} +parameter}\par +\Y\P\4\&{procedure}\1\ \37$\\{delete\_mac\_ref}(\|p:\\{pointer})$;\C{\|p +points to the reference count of a macro list that is losing one reference}% +\2\6 +\&{begin} \37\&{if} $\\{ref\_count}(\|p)=\\{null}$ \1\&{then}\5 +$\\{flush\_token\_list}(\|p)$\6 +\4\&{else} $\\{decr}(\\{ref\_count}(\|p))$;\2\6 +\&{end};\par +\fi + +\M227. The following subroutine displays a macro, given a pointer to its +reference count. + +\Y\P\hbox{\4}\X625:Declare the procedure called \\{print\_cmd\_mod}\X\6 +\4\&{procedure}\1\ \37$\\{show\_macro}(\|p:\\{pointer};\,\35\|q,\39\|l:% +\\{integer})$;\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37\|r: \37\\{pointer};\C{temporary storage}\2\6 +\&{begin} \37$\|p\K\\{link}(\|p)$;\C{bypass the reference count}\6 +\&{while} $\\{info}(\|p)>\\{text\_macro}$ \1\&{do}\6 +\&{begin} \37$\|r\K\\{link}(\|p)$;\5 +$\\{link}(\|p)\K\\{null}$;\5 +$\\{show\_token\_list}(\|p,\39\\{null},\39\|l,\390)$;\5 +$\\{link}(\|p)\K\|r$;\5 +$\|p\K\|r$;\6 +\&{if} $\|l>0$ \1\&{then}\5 +$\|l\K\|l-\\{tally}$\ \&{else} \&{return};\2\6 +\&{end};\C{control printing of `\.{ETC.}'}\2\6 +$\\{tally}\K0$;\6 +\&{case} $\\{info}(\|p)$ \1\&{of}\6 +\4\\{general\_macro}: \37$\\{print}(\.{"->"})$;\6 +\4$\\{primary\_macro},\39\\{secondary\_macro},\39\\{tertiary\_macro}$: \37% +\&{begin} \37$\\{print\_char}(\.{"<"})$;\5 +$\\{print\_cmd\_mod}(\\{param\_type},\39\\{info}(\|p))$;\5 +$\\{print}(\.{">->"})$;\6 +\&{end};\6 +\4\\{expr\_macro}: \37$\\{print}(\.{"<expr>->"})$;\6 +\4\\{of\_macro}: \37$\\{print}(\.{"<expr>of<primary>->"})$;\6 +\4\\{suffix\_macro}: \37$\\{print}(\.{"<suffix>->"})$;\6 +\4\\{text\_macro}: \37$\\{print}(\.{"<text>->"})$;\2\6 +\&{end};\C{there are no other cases}\6 +$\\{show\_token\_list}(\\{link}(\|p),\39\|q,\39\|l-\\{tally},\390)$;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\N228. \[15] Data structures for variables. +The variables of \MF\ programs can be simple, like `\.x', or they can +combine the structural properties of arrays and records, like `\.{x20a.b}'. +A \MF\ user assigns a type to a variable like \.{x20a.b} by saying, for +example, `\.{boolean} \.{x20a.b}'. It's time for us to study how such +things are represented inside of the computer. + +Each variable value occupies two consecutive words, either in a two-word +node called a value node, or as a two-word subfield of a larger node. One +of those two words is called the \\{value} field; it is an integer, +containing either a \\{scaled} numeric value or the representation of some +other type of quantity. (It might also be subdivided into halfwords, in +which case it is referred to by other names instead of \\{value}.) The other +word is broken into subfields called \\{type}, \\{name\_type}, and \\{link}. +The +\\{type} field is a quarterword that specifies the variable's type, and +\\{name\_type} is a quarterword from which \MF\ can reconstruct the +variable's name (sometimes by using the \\{link} field as well). Thus, only +1.25 words are actually devoted to the value itself; the other +three-quarters of a word are overhead, but they aren't wasted because they +allow \MF\ to deal with sparse arrays and to provide meaningful diagnostics. + +In this section we shall be concerned only with the structural aspects of +variables, not their values. Later parts of the program will change the +\\{type} and \\{value} fields, but we shall treat those fields as black boxes +whose contents should not be touched. + +However, if the \\{type} field is \\{structured}, there is no \\{value} field, +and the second word is broken into two pointer fields called \\{attr\_head} +and \\{subscr\_head}. Those fields point to additional nodes that +contain structural information, as we shall see. + +\Y\P\D \37$\\{subscr\_head\_loc}(\#)\S\#+1$\C{where \\{value}, \\{subscr% +\_head}, and \\{attr\_head} are}\par +\P\D \37$\\{attr\_head}(\#)\S\\{info}(\\{subscr\_head\_loc}(\#))$\C{pointer to +attribute info}\par +\P\D \37$\\{subscr\_head}(\#)\S\\{link}(\\{subscr\_head\_loc}(\#))$\C{pointer +to subscript info}\par +\P\D \37$\\{value\_node\_size}=2$\C{the number of words in a value node}\par +\fi + +\M229. An attribute node is three words long. Two of these words contain % +\\{type} +and \\{value} fields as described above, and the third word contains +additional information: There is an \\{attr\_loc} field, which contains the +hash address of the token that names this attribute; and there's also a +\\{parent} field, which points to the value node of \\{structured} type at the +next higher level (i.e., at the level to which this attribute is +subsidiary). The \\{name\_type} in an attribute node is `\\{attr}'. The +\\{link} field points to the next attribute with the same parent; these are +arranged in increasing order, so that $\\{attr\_loc}(\\{link}(\|p))>\\{attr% +\_loc}(\|p)$. The +final attribute node links to the constant \\{end\_attr}, whose \\{attr\_loc} +field is greater than any legal hash address. The \\{attr\_head} in the +parent points to a node whose \\{name\_type} is \\{structured\_root}; this +node represents the null attribute, i.e., the variable that is relevant +when no attributes are attached to the parent. The \\{attr\_head} node is +either +a value node, a subscript node, or an attribute node, depending on what +the parent would be if it were not structured; but the subscript and +attribute fields are ignored, so it effectively contains only the data of +a value node. The \\{link} field in this special node points to an attribute +node whose \\{attr\_loc} field is zero; the latter node represents a collective +subscript `\.{[]}' attached to the parent, and its \\{link} field points to +the first non-special attribute node (or to \\{end\_attr} if there are none). + +A subscript node likewise occupies three words, with \\{type} and \\{value} +fields +plus extra information; its \\{name\_type} is \\{subscr}. In this case the +third word is called the \\{subscript} field, which is a \\{scaled} integer. +The \\{link} field points to the subscript node with the next larger +subscript, if any; otherwise the \\{link} points to the attribute node +for collective subscripts at this level. We have seen that the latter node +contains an upward pointer, so that the parent can be deduced. + +The \\{name\_type} in a parent-less value node is \\{root}, and the \\{link} +is the hash address of the token that names this value. + +In other words, variables have a hierarchical structure that includes +enough threads running around so that the program is able to move easily +between siblings, parents, and children. An example should be helpful: +(The reader is advised to draw a picture while reading the following +description, since that will help to firm up the ideas.) +Suppose that `\.x' and `\.{x.a}' and `\.{x[]b}' and `\.{x5}' +and `\.{x20b}' have been mentioned in a user's program, where +\.{x[]b} has been declared to be of \&{boolean} type. Let $\|h(\|x)$, $\|h(% +\|a)$, +and $\|h(\|b)$ be the hash addresses of \.x, \.a, and~\.b. Then +$\\{eq\_type}(\|h(\|x))=\\{tag\_token}$ and $\\{equiv}(\|h(\|x))=\|p$, where % +\|p~is a two-word value +node with $\\{name\_type}(\|p)=\\{root}$ and $\\{link}(\|p)=\|h(\|x)$. We have +$\\{type}(\|p)=\\{structured}$, +$\\{attr\_head}(\|p)=\|q$, and $\\{subscr\_head}(\|p)=\|r$, where \|q points to +a value +node and \|r to a subscript node. (Are you still following this? Use +a pencil to draw a diagram.) The lone variable `\.x' is represented by +$\\{type}(\|q)$ and $\\{value}(\|q)$; furthermore +$\\{name\_type}(\|q)=\\{structured\_root}$ and $\\{link}(\|q)=\\{q1}$, where % +\\{q1} points +to an attribute node representing `\.{x[]}'. Thus $\\{name\_type}(\\{q1})=% +\\{attr}$, +$\\{attr\_loc}(\\{q1})=\\{collective\_subscript}=0$, $\\{parent}(\\{q1})=\|p$, +$\\{type}(\\{q1})=\\{structured}$, $\\{attr\_head}(\\{q1})=\\{qq}$, and $% +\\{subscr\_head}(\\{q1})=\\{qq1}$; +\\{qq} is a value node with $\\{type}(\\{qq})=\\{numeric\_type}$ (assuming that +\.{x5} is +numeric, because \\{qq} represents `\.{x[]}' with no further attributes), +$\\{name\_type}(\\{qq})=\\{structured\_root}$, and +$\\{link}(\\{qq})=\\{qq1}$. (Now pay attention to the next part.) Node \\{qq1} +is +an attribute node representing `\.{x[][]}', which has never yet +occurred; its \\{type} field is \\{undefined}, and its \\{value} field is +undefined. We have $\\{name\_type}(\\{qq1})=\\{attr}$, $\\{attr\_loc}(\\{qq1})=% +\\{collective\_subscript}$, +$\\{parent}(\\{qq1})=\\{q1}$, and $\\{link}(\\{qq1})=\\{qq2}$. Since \\{qq2} +represents +`\.{x[]b}', $\\{type}(\\{qq2})=\\{unknown\_boolean}$; also $\\{attr\_loc}(% +\\{qq2})=\|h(\|b)$, +$\\{parent}(\\{qq2})=\\{q1}$, $\\{name\_type}(\\{qq2})=\\{attr}$, $\\{link}(% +\\{qq2})=\\{end\_attr}$. +(Maybe colored lines will help untangle your picture.) +Node \|r is a subscript node with \\{type} and \\{value} +representing `\.{x5}'; $\\{name\_type}(\|r)=\\{subscr}$, $\\{subscript}(% +\|r)=5.0$, +and $\\{link}(\|r)=\\{r1}$ is another subscript node. To complete the picture, +see if you can guess what $\\{link}(\\{r1})$ is; give up? It's~\\{q1}. +Furthermore $\\{subscript}(\\{r1})=20.0$, $\\{name\_type}(\\{r1})=\\{subscr}$, +$\\{type}(\\{r1})=\\{structured}$, $\\{attr\_head}(\\{r1})=\\{qqq}$, $\\{subscr% +\_head}(\\{r1})=\\{qqq1}$, +and we finish things off with three more nodes +\\{qqq}, \\{qqq1}, and \\{qqq2} hung onto~\\{r1}. (Perhaps you should start +again +with a larger sheet of paper.) The value of variable \.{x20b} +appears in node~\\{qqq2}, as you can well imagine. + +If the example in the previous paragraph doesn't make things crystal +clear, a glance at some of the simpler subroutines below will reveal how +things work out in practice. + +The only really unusual thing about these conventions is the use of +collective subscript attributes. The idea is to avoid repeating a lot of +type information when many elements of an array are identical macros +(for which distinct values need not be stored) or when they don't have +all of the possible attributes. Branches of the structure below collective +subscript attributes do not carry actual values except for macro identifiers; +branches of the structure below subscript nodes do not carry significant +information in their collective subscript attributes. + +\Y\P\D \37$\\{attr\_loc\_loc}(\#)\S\#+2$\C{where the \\{attr\_loc} and % +\\{parent} fields are}\par +\P\D \37$\\{attr\_loc}(\#)\S\\{info}(\\{attr\_loc\_loc}(\#))$\C{hash address of +this attribute}\par +\P\D \37$\\{parent}(\#)\S\\{link}(\\{attr\_loc\_loc}(\#))$\C{pointer to % +\\{structured} variable}\par +\P\D \37$\\{subscript\_loc}(\#)\S\#+2$\C{where the \\{subscript} field lives}% +\par +\P\D \37$\\{subscript}(\#)\S\\{mem}[\\{subscript\_loc}(\#)].\\{sc}$\C{subscript +of this variable}\par +\P\D \37$\\{attr\_node\_size}=3$\C{the number of words in an attribute node}\par +\P\D \37$\\{subscr\_node\_size}=3$\C{the number of words in a subscript node}% +\par +\P\D \37$\\{collective\_subscript}=0$\C{code for the attribute `\.{[]}'}\par +\Y\P$\4\X176:Initialize table entries (done by \.{INIMF} only)\X\mathrel{+}\S$\6 +$\\{attr\_loc}(\\{end\_attr})\K\\{hash\_end}+1$;\5 +$\\{parent}(\\{end\_attr})\K\\{null}$;\par +\fi + +\M230. Variables of type \&{pair} will have values that point to four-word +nodes containing two numeric values. The first of these values has +$\\{name\_type}=\\{x\_part\_sector}$ and the second has $\\{name\_type}=\\{y% +\_part\_sector}$; +the \\{link} in the first points back to the node whose \\{value} points +to this four-word node. + +Variables of type \&{transform} are similar, but in this case their +\\{value} points to a 12-word node containing six values, identified by +\\{x\_part\_sector}, \\{y\_part\_sector}, \\{xx\_part\_sector}, \\{xy\_part% +\_sector}, +\\{yx\_part\_sector}, and \\{yy\_part\_sector}. + +When an entire structured variable is saved, the \\{root} indication +is temporarily replaced by \\{saved\_root}. + +Some variables have no name; they just are used for temporary storage +while expressions are being evaluated. We call them {\sl capsules}. + +\Y\P\D \37$\\{x\_part\_loc}(\#)\S\#$\C{where the \&{xpart} is found in a pair +or transform node}\par +\P\D \37$\\{y\_part\_loc}(\#)\S\#+2$\C{where the \&{ypart} is found in a pair +or transform node}\par +\P\D \37$\\{xx\_part\_loc}(\#)\S\#+4$\C{where the \&{xxpart} is found in a +transform node}\par +\P\D \37$\\{xy\_part\_loc}(\#)\S\#+6$\C{where the \&{xypart} is found in a +transform node}\par +\P\D \37$\\{yx\_part\_loc}(\#)\S\#+8$\C{where the \&{yxpart} is found in a +transform node}\par +\P\D \37$\\{yy\_part\_loc}(\#)\S\#+10$\C{where the \&{yypart} is found in a +transform node}\Y\par +\P\D \37$\\{pair\_node\_size}=4$\C{the number of words in a pair node}\par +\P\D \37$\\{transform\_node\_size}=12$\C{the number of words in a transform +node}\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{big\_node\_size}: \37\&{array} $[\\{transform\_type}\to\\{pair\_type}]$ \1% +\&{of}\5 +\\{small\_number};\2\par +\fi + +\M231. The \\{big\_node\_size} array simply contains two constants that \MF\ +occasionally needs to know. + +\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{big\_node\_size}[\\{transform\_type}]\K\\{transform\_node\_size}$;\5 +$\\{big\_node\_size}[\\{pair\_type}]\K\\{pair\_node\_size}$;\par +\fi + +\M232. If $\\{type}(\|p)=\\{pair\_type}$ or \\{transform\_type} and if $% +\\{value}(\|p)=\\{null}$, the +procedure call $\\{init\_big\_node}(\|p)$ will allocate a pair or transform +node +for~\|p. The individual parts of such nodes are initially of type +\\{independent}. + +\Y\P\4\&{procedure}\1\ \37$\\{init\_big\_node}(\|p:\\{pointer})$;\6 +\4\&{var} \37\|q: \37\\{pointer};\C{the new node}\6 +\|s: \37\\{small\_number};\C{its size}\2\6 +\&{begin} \37$\|s\K\\{big\_node\_size}[\\{type}(\|p)]$;\5 +$\|q\K\\{get\_node}(\|s)$;\6 +\1\&{repeat} \37$\|s\K\|s-2$;\5 +\X586:Make variable $\|q+\|s$ newly independent\X;\6 +$\\{name\_type}(\|q+\|s)\K\\{half}(\|s)+\\{x\_part\_sector}$;\5 +$\\{link}(\|q+\|s)\K\\{null}$;\6 +\4\&{until}\5 +$\|s=0$;\2\6 +$\\{link}(\|q)\K\|p$;\5 +$\\{value}(\|p)\K\|q$;\6 +\&{end};\par +\fi + +\M233. The \\{id\_transform} function creates a capsule for the +identity transformation. + +\Y\P\4\&{function}\1\ \37\\{id\_transform}: \37\\{pointer};\6 +\4\&{var} \37$\|p,\39\|q,\39\|r$: \37\\{pointer};\C{list manipulation +registers}\2\6 +\&{begin} \37$\|p\K\\{get\_node}(\\{value\_node\_size})$;\5 +$\\{type}(\|p)\K\\{transform\_type}$;\5 +$\\{name\_type}(\|p)\K\\{capsule}$;\5 +$\\{value}(\|p)\K\\{null}$;\5 +$\\{init\_big\_node}(\|p)$;\5 +$\|q\K\\{value}(\|p)$;\5 +$\|r\K\|q+\\{transform\_node\_size}$;\6 +\1\&{repeat} \37$\|r\K\|r-2$;\5 +$\\{type}(\|r)\K\\{known}$;\5 +$\\{value}(\|r)\K0$;\6 +\4\&{until}\5 +$\|r=\|q$;\2\6 +$\\{value}(\\{xx\_part\_loc}(\|q))\K\\{unity}$;\5 +$\\{value}(\\{yy\_part\_loc}(\|q))\K\\{unity}$;\5 +$\\{id\_transform}\K\|p$;\6 +\&{end};\par +\fi + +\M234. Tokens are of type \\{tag\_token} when they first appear, but they point +to \\{null} until they are first used as the root of a variable. +The following subroutine establishes the root node on such grand occasions. + +\Y\P\4\&{procedure}\1\ \37$\\{new\_root}(\|x:\\{pointer})$;\6 +\4\&{var} \37\|p: \37\\{pointer};\C{the new node}\2\6 +\&{begin} \37$\|p\K\\{get\_node}(\\{value\_node\_size})$;\5 +$\\{type}(\|p)\K\\{undefined}$;\5 +$\\{name\_type}(\|p)\K\\{root}$;\5 +$\\{link}(\|p)\K\|x$;\5 +$\\{equiv}(\|x)\K\|p$;\6 +\&{end};\par +\fi + +\M235. These conventions for variable representation are illustrated by the +\\{print\_variable\_name} routine, which displays the full name of a +variable given only a pointer to its two-word value packet. + +\Y\P\4\&{procedure}\1\ \37$\\{print\_variable\_name}(\|p:\\{pointer})$;\6 +\4\&{label} \37$\\{found},\39\\{exit}$;\6 +\4\&{var} \37\|q: \37\\{pointer};\C{a token list that will name the variable's +suffix}\6 +\|r: \37\\{pointer};\C{temporary for token list creation}\2\6 +\&{begin} \37\&{while} $\\{name\_type}(\|p)\G\\{x\_part\_sector}$ \1\&{do}\5 +\X237:Preface the output with a part specifier; \&{return} in the case of a +capsule\X;\2\6 +$\|q\K\\{null}$;\6 +\&{while} $\\{name\_type}(\|p)>\\{saved\_root}$ \1\&{do}\5 +\X236:Ascend one level, pushing a token onto list \|q and replacing \|p by its +parent\X;\2\6 +$\|r\K\\{get\_avail}$;\5 +$\\{info}(\|r)\K\\{link}(\|p)$;\5 +$\\{link}(\|r)\K\|q$;\6 +\&{if} $\\{name\_type}(\|p)=\\{saved\_root}$ \1\&{then}\5 +$\\{print}(\.{"(SAVED)"})$;\2\6 +$\\{show\_token\_list}(\|r,\39\\{null},\39\\{el\_gordo},\39\\{tally})$;\5 +$\\{flush\_token\_list}(\|r)$;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M236. \P$\X236:Ascend one level, pushing a token onto list \|q and replacing % +\|p by its parent\X\S$\6 +\&{begin} \37\&{if} $\\{name\_type}(\|p)=\\{subscr}$ \1\&{then}\6 +\&{begin} \37$\|r\K\\{new\_num\_tok}(\\{subscript}(\|p))$;\6 +\1\&{repeat} \37$\|p\K\\{link}(\|p)$;\6 +\4\&{until}\5 +$\\{name\_type}(\|p)=\\{attr}$;\2\6 +\&{end}\6 +\4\&{else} \&{if} $\\{name\_type}(\|p)=\\{structured\_root}$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{link}(\|p)$;\5 +\&{goto} \37\\{found};\6 +\&{end}\6 +\4\&{else} \&{begin} \37\&{if} $\\{name\_type}(\|p)\I\\{attr}$ \1\&{then}\5 +$\\{confusion}(\.{"var"})$;\2\6 +$\|r\K\\{get\_avail}$;\5 +$\\{info}(\|r)\K\\{attr\_loc}(\|p)$;\6 +\&{end};\2\2\6 +$\\{link}(\|r)\K\|q$;\5 +$\|q\K\|r$;\6 +\4\\{found}: \37$\|p\K\\{parent}(\|p)$;\6 +\&{end}\par +\U235.\fi + +\M237. \P$\X237:Preface the output with a part specifier; \&{return} in the +case of a capsule\X\S$\6 +\&{begin} \37\&{case} $\\{name\_type}(\|p)$ \1\&{of}\6 +\4\\{x\_part\_sector}: \37$\\{print\_char}(\.{"x"})$;\6 +\4\\{y\_part\_sector}: \37$\\{print\_char}(\.{"y"})$;\6 +\4\\{xx\_part\_sector}: \37$\\{print}(\.{"xx"})$;\6 +\4\\{xy\_part\_sector}: \37$\\{print}(\.{"xy"})$;\6 +\4\\{yx\_part\_sector}: \37$\\{print}(\.{"yx"})$;\6 +\4\\{yy\_part\_sector}: \37$\\{print}(\.{"yy"})$;\6 +\4\\{capsule}: \37\&{begin} \37$\\{print}(\.{"\%CAPSULE"})$;\5 +$\\{print\_int}(\|p-\\{null})$;\5 +\&{return};\6 +\&{end};\2\6 +\&{end};\C{there are no other cases}\6 +$\\{print}(\.{"part\ "})$;\5 +$\|p\K\\{link}(\|p-2\ast(\\{name\_type}(\|p)-\\{x\_part\_sector}))$;\6 +\&{end}\par +\U235.\fi + +\M238. The \\{interesting} function returns \\{true} if a given variable is not +in a capsule, or if the user wants to trace capsules. + +\Y\P\4\&{function}\1\ \37$\\{interesting}(\|p:\\{pointer})$: \37\\{boolean};\6 +\4\&{var} \37\|t: \37\\{small\_number};\C{a \\{name\_type}}\2\6 +\&{begin} \37\&{if} $\\{internal}[\\{tracing\_capsules}]>0$ \1\&{then}\5 +$\\{interesting}\K\\{true}$\6 +\4\&{else} \&{begin} \37$\|t\K\\{name\_type}(\|p)$;\6 +\&{if} $\|t\G\\{x\_part\_sector}$ \1\&{then}\6 +\&{if} $\|t\I\\{capsule}$ \1\&{then}\5 +$\|t\K\\{name\_type}(\\{link}(\|p-2\ast(\|t-\\{x\_part\_sector})))$;\2\2\6 +$\\{interesting}\K(\|t\I\\{capsule})$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M239. Now here is a subroutine that converts an unstructured type into an +equivalent structured type, by inserting a \\{structured} node that is +capable of growing. This operation is done only when $\\{name\_type}(\|p)=% +\\{root}$, +\\{subscr}, or \\{attr}. + +The procedure returns a pointer to the new node that has taken node~\|p's +place in the structure. Node~\|p itself does not move, nor are its +\\{value} or \\{type} fields changed in any way. + +\Y\P\4\&{function}\1\ \37$\\{new\_structure}(\|p:\\{pointer})$: \37% +\\{pointer};\6 +\4\&{var} \37$\|q,\39\|r$: \37\\{pointer};\C{list manipulation registers}\2\6 +\&{begin} \37\&{case} $\\{name\_type}(\|p)$ \1\&{of}\6 +\4\\{root}: \37\&{begin} \37$\|q\K\\{link}(\|p)$;\5 +$\|r\K\\{get\_node}(\\{value\_node\_size})$;\5 +$\\{equiv}(\|q)\K\|r$;\6 +\&{end};\6 +\4\\{subscr}: \37\X240:Link a new subscript node \|r in place of node \|p\X;\6 +\4\\{attr}: \37\X241:Link a new attribute node \|r in place of node \|p\X;\6 +\4\&{othercases} \37$\\{confusion}(\.{"struct"})$\2\6 +\&{endcases};\6 +$\\{link}(\|r)\K\\{link}(\|p)$;\5 +$\\{type}(\|r)\K\\{structured}$;\5 +$\\{name\_type}(\|r)\K\\{name\_type}(\|p)$;\5 +$\\{attr\_head}(\|r)\K\|p$;\5 +$\\{name\_type}(\|p)\K\\{structured\_root}$;\6 +$\|q\K\\{get\_node}(\\{attr\_node\_size})$;\5 +$\\{link}(\|p)\K\|q$;\5 +$\\{subscr\_head}(\|r)\K\|q$;\5 +$\\{parent}(\|q)\K\|r$;\5 +$\\{type}(\|q)\K\\{undefined}$;\5 +$\\{name\_type}(\|q)\K\\{attr}$;\5 +$\\{link}(\|q)\K\\{end\_attr}$;\5 +$\\{attr\_loc}(\|q)\K\\{collective\_subscript}$;\5 +$\\{new\_structure}\K\|r$;\6 +\&{end};\par +\fi + +\M240. \P$\X240:Link a new subscript node \|r in place of node \|p\X\S$\6 +\&{begin} \37$\|q\K\|p$;\6 +\1\&{repeat} \37$\|q\K\\{link}(\|q)$;\6 +\4\&{until}\5 +$\\{name\_type}(\|q)=\\{attr}$;\2\6 +$\|q\K\\{parent}(\|q)$;\5 +$\|r\K\\{subscr\_head\_loc}(\|q)$;\C{$\\{link}(\|r)=\\{subscr\_head}(\|q)$}\6 +\1\&{repeat} \37$\|q\K\|r$;\5 +$\|r\K\\{link}(\|r)$;\6 +\4\&{until}\5 +$\|r=\|p$;\2\6 +$\|r\K\\{get\_node}(\\{subscr\_node\_size})$;\5 +$\\{link}(\|q)\K\|r$;\5 +$\\{subscript}(\|r)\K\\{subscript}(\|p)$;\6 +\&{end}\par +\U239.\fi + +\M241. If the attribute is \\{collective\_subscript}, there are two pointers to +node~\|p, so we must change both of them. + +\Y\P$\4\X241:Link a new attribute node \|r in place of node \|p\X\S$\6 +\&{begin} \37$\|q\K\\{parent}(\|p)$;\5 +$\|r\K\\{attr\_head}(\|q)$;\6 +\1\&{repeat} \37$\|q\K\|r$;\5 +$\|r\K\\{link}(\|r)$;\6 +\4\&{until}\5 +$\|r=\|p$;\2\6 +$\|r\K\\{get\_node}(\\{attr\_node\_size})$;\5 +$\\{link}(\|q)\K\|r$;\6 +$\\{mem}[\\{attr\_loc\_loc}(\|r)]\K\\{mem}[\\{attr\_loc\_loc}(\|p)]$;\C{copy % +\\{attr\_loc} and \\{parent}}\6 +\&{if} $\\{attr\_loc}(\|p)=\\{collective\_subscript}$ \1\&{then}\6 +\&{begin} \37$\|q\K\\{subscr\_head\_loc}(\\{parent}(\|p))$;\6 +\&{while} $\\{link}(\|q)\I\|p$ \1\&{do}\5 +$\|q\K\\{link}(\|q)$;\2\6 +$\\{link}(\|q)\K\|r$;\6 +\&{end};\2\6 +\&{end}\par +\U239.\fi + +\M242. The \\{find\_variable} routine is given a pointer~\|t to a nonempty +token +list of suffixes; it returns a pointer to the corresponding two-word +value. For example, if \|t points to token \.x followed by a numeric +token containing the value~7, \\{find\_variable} finds where the value of +\.{x7} is stored in memory. This may seem a simple task, and it +usually is, except when \.{x7} has never been referenced before. +Indeed, \.x may never have even been subscripted before; complexities +arise with respect to updating the collective subscript information. + +If a macro type is detected anywhere along path~\|t, or if the first +item on \|t isn't a \\{tag\_token}, the value \\{null} is returned. +Otherwise \|p will be a non-null pointer to a node such that +$\\{undefined}<\\{type}(\|p)<\\{structured}$. + +\Y\P\D \37$\\{abort\_find}\S$\1\6 +\&{begin} \37$\\{find\_variable}\K\\{null}$;\5 +\&{return};\ \&{end}\2\par +\Y\P\4\&{function}\1\ \37$\\{find\_variable}(\|t:\\{pointer})$: \37% +\\{pointer};\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37$\|p,\39\|q,\39\|r,\39\|s$: \37\\{pointer};\C{nodes in the +``value'' line}\6 +$\\{pp},\39\\{qq},\39\\{rr},\39\\{ss}$: \37\\{pointer};\C{nodes in the +``collective'' line}\6 +\|n: \37\\{integer};\C{subscript or attribute}\6 +\\{save\_word}: \37\\{memory\_word};\C{temporary storage for a word of \\{mem}}% +\2\6 +\&{begin} \37$\|p\K\\{info}(\|t)$;\5 +$\|t\K\\{link}(\|t)$;\6 +\&{if} $\\{eq\_type}(\|p)\mathbin{\&{mod}}\\{outer\_tag}\I\\{tag\_token}$ \1% +\&{then}\5 +\\{abort\_find};\2\6 +\&{if} $\\{equiv}(\|p)=\\{null}$ \1\&{then}\5 +$\\{new\_root}(\|p)$;\2\6 +$\|p\K\\{equiv}(\|p)$;\5 +$\\{pp}\K\|p$;\6 +\&{while} $\|t\I\\{null}$ \1\&{do}\6 +\&{begin} \37\X243:Make sure that both nodes \|p and \\{pp} are of % +\\{structured} type\X;\6 +\&{if} $\|t<\\{hi\_mem\_min}$ \1\&{then}\5 +\X244:Descend one level for the subscript $\\{value}(\|t)$\X\6 +\4\&{else} \X245:Descend one level for the attribute $\\{info}(\|t)$\X;\2\6 +$\|t\K\\{link}(\|t)$;\6 +\&{end};\2\6 +\&{if} $\\{type}(\\{pp})\G\\{structured}$ \1\&{then}\6 +\&{if} $\\{type}(\\{pp})=\\{structured}$ \1\&{then}\5 +$\\{pp}\K\\{attr\_head}(\\{pp})$\ \&{else} \\{abort\_find};\2\2\6 +\&{if} $\\{type}(\|p)=\\{structured}$ \1\&{then}\5 +$\|p\K\\{attr\_head}(\|p)$;\2\6 +\&{if} $\\{type}(\|p)=\\{undefined}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{type}(\\{pp})=\\{undefined}$ \1\&{then}\6 +\&{begin} \37$\\{type}(\\{pp})\K\\{numeric\_type}$;\5 +$\\{value}(\\{pp})\K\\{null}$;\6 +\&{end};\2\6 +$\\{type}(\|p)\K\\{type}(\\{pp})$;\5 +$\\{value}(\|p)\K\\{null}$;\6 +\&{end};\2\6 +$\\{find\_variable}\K\|p$;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M243. Although \\{pp} and \|p begin together, they diverge when a subscript +occurs; +\\{pp}~stays in the collective line while \|p~goes through actual subscript +values. + +\Y\P$\4\X243:Make sure that both nodes \|p and \\{pp} are of \\{structured} +type\X\S$\6 +\&{if} $\\{type}(\\{pp})\I\\{structured}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{type}(\\{pp})>\\{structured}$ \1\&{then}\5 +\\{abort\_find};\2\6 +$\\{ss}\K\\{new\_structure}(\\{pp})$;\6 +\&{if} $\|p=\\{pp}$ \1\&{then}\5 +$\|p\K\\{ss}$;\2\6 +$\\{pp}\K\\{ss}$;\6 +\&{end};\C{now $\\{type}(\\{pp})=\\{structured}$}\2\6 +\&{if} $\\{type}(\|p)\I\\{structured}$ \1\&{then}\C{it cannot be $>% +\\{structured}$}\6 +$\|p\K\\{new\_structure}(\|p)$\C{now $\\{type}(\|p)=\\{structured}$}\2\par +\U242.\fi + +\M244. We want this part of the program to be reasonably fast, in case there +are +lots of subscripts at the same level of the data structure. Therefore +we store an ``infinite'' value in the word that appears at the end of the +subscript list, even though that word isn't part of a subscript node. + +\Y\P$\4\X244:Descend one level for the subscript $\\{value}(\|t)$\X\S$\6 +\&{begin} \37$\|n\K\\{value}(\|t)$;\5 +$\\{pp}\K\\{link}(\\{attr\_head}(\\{pp}))$;\C{now $\\{attr\_loc}(\\{pp})=% +\\{collective\_subscript}$}\6 +$\|q\K\\{link}(\\{attr\_head}(\|p))$;\5 +$\\{save\_word}\K\\{mem}[\\{subscript\_loc}(\|q)]$;\5 +$\\{subscript}(\|q)\K\\{el\_gordo}$;\5 +$\|s\K\\{subscr\_head\_loc}(\|p)$;\C{$\\{link}(\|s)=\\{subscr\_head}(\|p)$}\6 +\1\&{repeat} \37$\|r\K\|s$;\5 +$\|s\K\\{link}(\|s)$;\6 +\4\&{until}\5 +$\|n\L\\{subscript}(\|s)$;\2\6 +\&{if} $\|n=\\{subscript}(\|s)$ \1\&{then}\5 +$\|p\K\|s$\6 +\4\&{else} \&{begin} \37$\|p\K\\{get\_node}(\\{subscr\_node\_size})$;\5 +$\\{link}(\|r)\K\|p$;\5 +$\\{link}(\|p)\K\|s$;\5 +$\\{subscript}(\|p)\K\|n$;\5 +$\\{name\_type}(\|p)\K\\{subscr}$;\5 +$\\{type}(\|p)\K\\{undefined}$;\6 +\&{end};\2\6 +$\\{mem}[\\{subscript\_loc}(\|q)]\K\\{save\_word}$;\6 +\&{end}\par +\U242.\fi + +\M245. \P$\X245:Descend one level for the attribute $\\{info}(\|t)$\X\S$\6 +\&{begin} \37$\|n\K\\{info}(\|t)$;\5 +$\\{ss}\K\\{attr\_head}(\\{pp})$;\6 +\1\&{repeat} \37$\\{rr}\K\\{ss}$;\5 +$\\{ss}\K\\{link}(\\{ss})$;\6 +\4\&{until}\5 +$\|n\L\\{attr\_loc}(\\{ss})$;\2\6 +\&{if} $\|n<\\{attr\_loc}(\\{ss})$ \1\&{then}\6 +\&{begin} \37$\\{qq}\K\\{get\_node}(\\{attr\_node\_size})$;\5 +$\\{link}(\\{rr})\K\\{qq}$;\5 +$\\{link}(\\{qq})\K\\{ss}$;\5 +$\\{attr\_loc}(\\{qq})\K\|n$;\5 +$\\{name\_type}(\\{qq})\K\\{attr}$;\5 +$\\{type}(\\{qq})\K\\{undefined}$;\5 +$\\{parent}(\\{qq})\K\\{pp}$;\5 +$\\{ss}\K\\{qq}$;\6 +\&{end};\2\6 +\&{if} $\|p=\\{pp}$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{ss}$;\5 +$\\{pp}\K\\{ss}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{pp}\K\\{ss}$;\5 +$\|s\K\\{attr\_head}(\|p)$;\6 +\1\&{repeat} \37$\|r\K\|s$;\5 +$\|s\K\\{link}(\|s)$;\6 +\4\&{until}\5 +$\|n\L\\{attr\_loc}(\|s)$;\2\6 +\&{if} $\|n=\\{attr\_loc}(\|s)$ \1\&{then}\5 +$\|p\K\|s$\6 +\4\&{else} \&{begin} \37$\|q\K\\{get\_node}(\\{attr\_node\_size})$;\5 +$\\{link}(\|r)\K\|q$;\5 +$\\{link}(\|q)\K\|s$;\5 +$\\{attr\_loc}(\|q)\K\|n$;\5 +$\\{name\_type}(\|q)\K\\{attr}$;\5 +$\\{type}(\|q)\K\\{undefined}$;\5 +$\\{parent}(\|q)\K\|p$;\5 +$\|p\K\|q$;\6 +\&{end};\2\6 +\&{end};\2\6 +\&{end}\par +\U242.\fi + +\M246. Variables lose their former values when they appear in a type +declaration, +or when they are defined to be macros or \&{let} equal to something else. +A subroutine will be defined later that recycles the storage associated +with any particular \\{type} or \\{value}; our goal now is to study a higher +level process called \\{flush\_variable}, which selectively frees parts of a +variable structure. + +This routine has some complexity because of examples such as +`\hbox{\tt numeric x[]a[]b}', +which recycles all variables of the form \.{x[i]a[j]b} (and no others), while +`\hbox{\tt vardef x[]a[]=...}' +discards all variables of the form \.{x[i]a[j]} followed by an arbitrary +suffix, except for the collective node \.{x[]a[]} itself. The obvious way +to handle such examples is to use recursion; so that's what we~do. + +Parameter \|p points to the root information of the variable; +parameter \|t points to a list of one-word nodes that represent +suffixes, with $\\{info}=\\{collective\_subscript}$ for subscripts. + +\Y\P\hbox{\4}\X257:Declare subroutines for printing expressions\X\6 +\hbox{\4}\X594:Declare basic dependency-list subroutines\X\6 +\hbox{\4}\X268:Declare the recycling subroutines\X\6 +\hbox{\4}\X808:Declare the procedure called \\{flush\_cur\_exp}\X\6 +\hbox{\4}\X247:Declare the procedure called \\{flush\_below\_variable}\X\6 +\4\&{procedure}\1\ \37$\\{flush\_variable}(\|p,\39\|t:\\{pointer};\,\35% +\\{discard\_suffixes}:\\{boolean})$;\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37$\|q,\39\|r$: \37\\{pointer};\C{list manipulation}\6 +\|n: \37\\{halfword};\C{attribute to match}\2\6 +\&{begin} \37\&{while} $\|t\I\\{null}$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{type}(\|p)\I\\{structured}$ \1\&{then}\5 +\&{return};\2\6 +$\|n\K\\{info}(\|t)$;\5 +$\|t\K\\{link}(\|t)$;\6 +\&{if} $\|n=\\{collective\_subscript}$ \1\&{then}\6 +\&{begin} \37$\|r\K\\{subscr\_head\_loc}(\|p)$;\5 +$\|q\K\\{link}(\|r)$;\C{$\|q=\\{subscr\_head}(\|p)$}\6 +\&{while} $\\{name\_type}(\|q)=\\{subscr}$ \1\&{do}\6 +\&{begin} \37$\\{flush\_variable}(\|q,\39\|t,\39\\{discard\_suffixes})$;\6 +\&{if} $\|t=\\{null}$ \1\&{then}\6 +\&{if} $\\{type}(\|q)=\\{structured}$ \1\&{then}\5 +$\|r\K\|q$\6 +\4\&{else} \&{begin} \37$\\{link}(\|r)\K\\{link}(\|q)$;\5 +$\\{free\_node}(\|q,\39\\{subscr\_node\_size})$;\6 +\&{end}\2\6 +\4\&{else} $\|r\K\|q$;\2\6 +$\|q\K\\{link}(\|r)$;\6 +\&{end};\2\6 +\&{end};\2\6 +$\|p\K\\{attr\_head}(\|p)$;\6 +\1\&{repeat} \37$\|r\K\|p$;\5 +$\|p\K\\{link}(\|p)$;\6 +\4\&{until}\5 +$\\{attr\_loc}(\|p)\G\|n$;\2\6 +\&{if} $\\{attr\_loc}(\|p)\I\|n$ \1\&{then}\5 +\&{return};\2\6 +\&{end};\2\6 +\&{if} $\\{discard\_suffixes}$ \1\&{then}\5 +$\\{flush\_below\_variable}(\|p)$\6 +\4\&{else} \&{begin} \37\&{if} $\\{type}(\|p)=\\{structured}$ \1\&{then}\5 +$\|p\K\\{attr\_head}(\|p)$;\2\6 +$\\{recycle\_value}(\|p)$;\6 +\&{end};\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M247. The next procedure is simpler; it wipes out everything but \|p itself, +which becomes undefined. + +\Y\P$\4\X247:Declare the procedure called \\{flush\_below\_variable}\X\S$\6 +\4\&{procedure}\1\ \37$\\{flush\_below\_variable}(\|p:\\{pointer})$;\6 +\4\&{var} \37$\|q,\39\|r$: \37\\{pointer};\C{list manipulation registers}\2\6 +\&{begin} \37\&{if} $\\{type}(\|p)\I\\{structured}$ \1\&{then}\5 +$\\{recycle\_value}(\|p)$\C{this sets $\\{type}(\|p)=\\{undefined}$}\6 +\4\&{else} \&{begin} \37$\|q\K\\{subscr\_head}(\|p)$;\6 +\&{while} $\\{name\_type}(\|q)=\\{subscr}$ \1\&{do}\6 +\&{begin} \37$\\{flush\_below\_variable}(\|q)$;\5 +$\|r\K\|q$;\5 +$\|q\K\\{link}(\|q)$;\5 +$\\{free\_node}(\|r,\39\\{subscr\_node\_size})$;\6 +\&{end};\2\6 +$\|r\K\\{attr\_head}(\|p)$;\5 +$\|q\K\\{link}(\|r)$;\5 +$\\{recycle\_value}(\|r)$;\6 +\&{if} $\\{name\_type}(\|p)\L\\{saved\_root}$ \1\&{then}\5 +$\\{free\_node}(\|r,\39\\{value\_node\_size})$\6 +\4\&{else} $\\{free\_node}(\|r,\39\\{subscr\_node\_size})$;\C{we assume that $% +\\{subscr\_node\_size}=\\{attr\_node\_size}$}\2\6 +\1\&{repeat} \37$\\{flush\_below\_variable}(\|q)$;\5 +$\|r\K\|q$;\5 +$\|q\K\\{link}(\|q)$;\5 +$\\{free\_node}(\|r,\39\\{attr\_node\_size})$;\6 +\4\&{until}\5 +$\|q=\\{end\_attr}$;\2\6 +$\\{type}(\|p)\K\\{undefined}$;\6 +\&{end};\2\6 +\&{end};\par +\U246.\fi + +\M248. Just before assigning a new value to a variable, we will recycle the +old value and make the old value undefined. The \\{und\_type} routine +determines what type of undefined value should be given, based on +the current type before recycling. + +\Y\P\4\&{function}\1\ \37$\\{und\_type}(\|p:\\{pointer})$: \37\\{small% +\_number};\2\6 +\&{begin} \37\&{case} $\\{type}(\|p)$ \1\&{of}\6 +\4$\\{undefined},\39\\{vacuous}$: \37$\\{und\_type}\K\\{undefined}$;\6 +\4$\\{boolean\_type},\39\\{unknown\_boolean}$: \37$\\{und\_type}\K\\{unknown% +\_boolean}$;\6 +\4$\\{string\_type},\39\\{unknown\_string}$: \37$\\{und\_type}\K\\{unknown% +\_string}$;\6 +\4$\\{pen\_type},\39\\{unknown\_pen},\39\\{future\_pen}$: \37$\\{und\_type}\K% +\\{unknown\_pen}$;\6 +\4$\\{path\_type},\39\\{unknown\_path}$: \37$\\{und\_type}\K\\{unknown\_path}$;% +\6 +\4$\\{picture\_type},\39\\{unknown\_picture}$: \37$\\{und\_type}\K\\{unknown% +\_picture}$;\6 +\4$\\{transform\_type},\39\\{pair\_type},\39\\{numeric\_type}$: \37$\\{und% +\_type}\K\\{type}(\|p)$;\6 +\4$\\{known},\39\\{dependent},\39\\{proto\_dependent},\39\\{independent}$: \37$% +\\{und\_type}\K\\{numeric\_type}$;\2\6 +\&{end};\C{there are no other cases}\6 +\&{end};\par +\fi + +\M249. The \\{clear\_symbol} routine is used when we want to redefine the +equivalent +of a symbolic token. It must remove any variable structure or macro +definition that is currently attached to that symbol. If the \\{saving} +parameter is true, a subsidiary structure is saved instead of destroyed. + +\Y\P\4\&{procedure}\1\ \37$\\{clear\_symbol}(\|p:\\{pointer};\,\35\\{saving}:% +\\{boolean})$;\6 +\4\&{var} \37\|q: \37\\{pointer};\C{$\\{equiv}(\|p)$}\2\6 +\&{begin} \37$\|q\K\\{equiv}(\|p)$;\6 +\&{case} $\\{eq\_type}(\|p)\mathbin{\&{mod}}\\{outer\_tag}$ \1\&{of}\6 +\4$\\{defined\_macro},\39\\{secondary\_primary\_macro},\39\\{tertiary% +\_secondary\_macro},\39\\{expression\_tertiary\_macro}$: \37\&{if} $\R% +\\{saving}$ \1\&{then}\5 +$\\{delete\_mac\_ref}(\|q)$;\2\6 +\4\\{tag\_token}: \37\&{if} $\|q\I\\{null}$ \1\&{then}\6 +\&{if} $\\{saving}$ \1\&{then}\5 +$\\{name\_type}(\|q)\K\\{saved\_root}$\6 +\4\&{else} \&{begin} \37$\\{flush\_below\_variable}(\|q)$;\5 +$\\{free\_node}(\|q,\39\\{value\_node\_size})$;\6 +\&{end};\2\6 +\4\&{othercases} \\{do\_nothing}\2\2\6 +\&{endcases};\6 +$\\{eqtb}[\|p]\K\\{eqtb}[\\{frozen\_undefined}]$;\6 +\&{end};\par +\fi + +\N250. \[16] Saving and restoring equivalents. +The nested structure provided by \&{begingroup} and \&{endgroup} +allows \\{eqtb} entries to be saved and restored, so that temporary changes +can be made without difficulty. When the user requests a current value to +be saved, \MF\ puts that value into its ``save stack.'' An appearance of +\&{endgroup} ultimately causes the old values to be removed from the save +stack and put back in their former places. + +The save stack is a linked list containing three kinds of entries, +distinguished by their \\{info} fields. If \|p points to a saved item, +then + +\smallskip\hang +$\\{info}(\|p)=0$ stands for a group boundary; each \&{begingroup} contributes +such an item to the save stack and each \&{endgroup} cuts back the stack +until the most recent such entry has been removed. + +\smallskip\hang +$\\{info}(\|p)=\|q$, where $1\L\|q\L\\{hash\_end}$, means that $\\{mem}[\|p+1]$ +holds the former +contents of $\\{eqtb}[\|q]$. Such save stack entries are generated by \&{save} +commands or suitable \&{interim} commands. + +\smallskip\hang +$\\{info}(\|p)=\\{hash\_end}+\|q$, where $\|q>0$, means that $\\{value}(\|p)$ +is a \\{scaled} +integer to be restored to internal parameter number~\|q. Such entries +are generated by \&{interim} commands. + +\smallskip\noindent +The global variable \\{save\_ptr} points to the top item on the save stack. + +\Y\P\D \37$\\{save\_node\_size}=2$\C{number of words per non-boundary +save-stack node}\par +\P\D \37$\\{saved\_equiv}(\#)\S\\{mem}[\#+1].\\{hh}$\C{where an \\{eqtb} entry +gets saved}\par +\P\D \37$\\{save\_boundary\_item}(\#)\S$\1\6 +\&{begin} \37$\#\K\\{get\_avail}$;\5 +$\\{info}(\#)\K0$;\5 +$\\{link}(\#)\K\\{save\_ptr}$;\5 +$\\{save\_ptr}\K\#$;\6 +\&{end}\2\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{save\_ptr}: \37\\{pointer};\C{the most recently saved item}\par +\fi + +\M251. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{save\_ptr}\K\\{null}$;\par +\fi + +\M252. The \\{save\_variable} routine is given a hash address \|q; it salts +this +address in the save stack, together with its current equivalent, +then makes token~\|q behave as though it were brand new. + +Nothing is stacked when $\\{save\_ptr}=\\{null}$, however; there's no way to +remove +things from the stack when the program is not inside a group, so there's +no point in wasting the space. + +\Y\P\4\&{procedure}\1\ \37$\\{save\_variable}(\|q:\\{pointer})$;\6 +\4\&{var} \37\|p: \37\\{pointer};\C{temporary register}\2\6 +\&{begin} \37\&{if} $\\{save\_ptr}\I\\{null}$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{get\_node}(\\{save\_node\_size})$;\5 +$\\{info}(\|p)\K\|q$;\5 +$\\{link}(\|p)\K\\{save\_ptr}$;\5 +$\\{saved\_equiv}(\|p)\K\\{eqtb}[\|q]$;\5 +$\\{save\_ptr}\K\|p$;\6 +\&{end};\2\6 +$\\{clear\_symbol}(\|q,\39(\\{save\_ptr}\I\\{null}))$;\6 +\&{end};\par +\fi + +\M253. Similarly, \\{save\_internal} is given the location \|q of an internal +quantity like \\{tracing\_pens}. It creates a save stack entry of the +third kind. + +\Y\P\4\&{procedure}\1\ \37$\\{save\_internal}(\|q:\\{halfword})$;\6 +\4\&{var} \37\|p: \37\\{pointer};\C{new item for the save stack}\2\6 +\&{begin} \37\&{if} $\\{save\_ptr}\I\\{null}$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{get\_node}(\\{save\_node\_size})$;\5 +$\\{info}(\|p)\K\\{hash\_end}+\|q$;\5 +$\\{link}(\|p)\K\\{save\_ptr}$;\5 +$\\{value}(\|p)\K\\{internal}[\|q]$;\5 +$\\{save\_ptr}\K\|p$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M254. At the end of a group, the \\{unsave} routine restores all of the saved +equivalents in reverse order. This routine will be called only when there +is at least one boundary item on the save stack. + +\Y\P\4\&{procedure}\1\ \37\\{unsave};\6 +\4\&{var} \37\|q: \37\\{pointer};\C{index to saved item}\6 +\|p: \37\\{pointer};\C{temporary register}\2\6 +\&{begin} \37\&{while} $\\{info}(\\{save\_ptr})\I0$ \1\&{do}\6 +\&{begin} \37$\|q\K\\{info}(\\{save\_ptr})$;\6 +\&{if} $\|q>\\{hash\_end}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{internal}[\\{tracing\_restores}]>0$ \1\&{then}\6 +\&{begin} \37\\{begin\_diagnostic};\5 +$\\{print\_nl}(\.{"\{restoring\ "})$;\5 +$\\{slow\_print}(\\{int\_name}[\|q-(\\{hash\_end})])$;\5 +$\\{print\_char}(\.{"="})$;\5 +$\\{print\_scaled}(\\{value}(\\{save\_ptr}))$;\5 +$\\{print\_char}(\.{"\}"})$;\5 +$\\{end\_diagnostic}(\\{false})$;\6 +\&{end};\2\6 +$\\{internal}[\|q-(\\{hash\_end})]\K\\{value}(\\{save\_ptr})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37\&{if} $\\{internal}[\\{tracing\_restores}]>0$ \1% +\&{then}\6 +\&{begin} \37\\{begin\_diagnostic};\5 +$\\{print\_nl}(\.{"\{restoring\ "})$;\5 +$\\{slow\_print}(\\{text}(\|q))$;\5 +$\\{print\_char}(\.{"\}"})$;\5 +$\\{end\_diagnostic}(\\{false})$;\6 +\&{end};\2\6 +$\\{clear\_symbol}(\|q,\39\\{false})$;\5 +$\\{eqtb}[\|q]\K\\{saved\_equiv}(\\{save\_ptr})$;\6 +\&{if} $\\{eq\_type}(\|q)\mathbin{\&{mod}}\\{outer\_tag}=\\{tag\_token}$ \1% +\&{then}\6 +\&{begin} \37$\|p\K\\{equiv}(\|q)$;\6 +\&{if} $\|p\I\\{null}$ \1\&{then}\5 +$\\{name\_type}(\|p)\K\\{root}$;\2\6 +\&{end};\2\6 +\&{end};\2\6 +$\|p\K\\{link}(\\{save\_ptr})$;\5 +$\\{free\_node}(\\{save\_ptr},\39\\{save\_node\_size})$;\5 +$\\{save\_ptr}\K\|p$;\6 +\&{end};\2\6 +$\|p\K\\{link}(\\{save\_ptr})$;\5 +$\\{free\_avail}(\\{save\_ptr})$;\5 +$\\{save\_ptr}\K\|p$;\6 +\&{end};\par +\fi + +\N255. \[17] Data structures for paths. +When a \MF\ user specifies a path, \MF\ will create a list of knots +and control points for the associated cubic spline curves. If the +knots are $z_0$, $z_1$, \dots, $z_n$, there are control points +$z_k^+$ and $z_{k+1}^-$ such that the cubic splines between knots +$z_k$ and $z_{k+1}$ are defined by B\'ezier's formula +$$\eqalign{z(t)&=B(z_k,z_k^+,z_{k+1}^-,z_{k+1};t)\cr +&=(1-t)^3z_k+3(1-t)^2tz_k^++3(1-t)t^2z_{k+1}^-+t^3z_{k+1}\cr}$$ +for $0\L\|t\L1$. + +There is a 7-word node for each knot $z_k$, containing one word of +control information and six words for the \|x and \|y coordinates +of $z_k^-$ and $z_k$ and~$z_k^+$. The control information appears +in the \\{left\_type} and \\{right\_type} fields, which each occupy +a quarter of the first word in the node; they specify properties +of the curve as it enters and leaves the knot. There's also a +halfword \\{link} field, which points to the following knot. + +If the path is a closed contour, knots 0 and \|n are identical; +i.e., the \\{link} in knot $\|n-1$ points to knot~0. But if the path +is not closed, the \\{left\_type} of knot~0 and the \\{right\_type} of knot~\|n +are equal to \\{endpoint}. In the latter case the \\{link} in knot~\|n points +to knot~0, and the control points $z_0^-$ and $z_n^+$ are not used. + +\Y\P\D \37$\\{left\_type}(\#)\S\\{mem}[\#].\\{hh}.\\{b0}$\C{characterizes the +path entering this knot}\par +\P\D \37$\\{right\_type}(\#)\S\\{mem}[\#].\\{hh}.\\{b1}$\C{characterizes the +path leaving this knot}\par +\P\D \37$\\{endpoint}=0$\C{\\{left\_type} at path beginning and \\{right\_type} +at path end}\par +\P\D \37$\\{x\_coord}(\#)\S\\{mem}[\#+1].\\{sc}$\C{the \|x coordinate of this +knot}\par +\P\D \37$\\{y\_coord}(\#)\S\\{mem}[\#+2].\\{sc}$\C{the \|y coordinate of this +knot}\par +\P\D \37$\\{left\_x}(\#)\S\\{mem}[\#+3].\\{sc}$\C{the \|x coordinate of +previous control point}\par +\P\D \37$\\{left\_y}(\#)\S\\{mem}[\#+4].\\{sc}$\C{the \|y coordinate of +previous control point}\par +\P\D \37$\\{right\_x}(\#)\S\\{mem}[\#+5].\\{sc}$\C{the \|x coordinate of next +control point}\par +\P\D \37$\\{right\_y}(\#)\S\\{mem}[\#+6].\\{sc}$\C{the \|y coordinate of next +control point}\par +\P\D \37$\\{knot\_node\_size}=7$\C{number of words in a knot node}\par +\fi + +\M256. Before the B\'ezier control points have been calculated, the memory +space they will ultimately occupy is taken up by information that can be +used to compute them. There are four cases: + +\yskip +\textindent{$\bullet$} If $\\{right\_type}=\\{open}$, the curve should leave +the knot in the same direction it entered; \MF\ will figure out a +suitable direction. + +\yskip +\textindent{$\bullet$} If $\\{right\_type}=\\{curl}$, the curve should leave +the +knot in a direction depending on the angle at which it enters the next +knot and on the curl parameter stored in \\{right\_curl}. + +\yskip +\textindent{$\bullet$} If $\\{right\_type}=\\{given}$, the curve should leave +the +knot in a nonzero direction stored as an \\{angle} in \\{right\_given}. + +\yskip +\textindent{$\bullet$} If $\\{right\_type}=\\{explicit}$, the B\'ezier control +point for leaving this knot has already been computed; it is in the +\\{right\_x} and \\{right\_y} fields. + +\yskip\noindent +The rules for \\{left\_type} are similar, but they refer to the curve entering +the knot, and to \\{left} fields instead of \\{right} fields. + +Non-\\{explicit} control points will be chosen based on ``tension'' parameters +in the \\{left\_tension} and \\{right\_tension} fields. The +`\&{atleast}' option is represented by negative tension values. + +For example, the \MF\ path specification +$$\.{z0..z1..tension atleast 1..\{curl 2\}z2..z3\{-1,-2\}..tension +3 and 4..p},$$ +where \.p is the path `\.{z4..controls z45 and z54..z5}', will be represented +by the six knots +\def\lodash{\hbox to 1.1em{\thinspace\hrulefill\thinspace}} +$$\vbox{\halign{#\hfil&&\qquad#\hfil\cr +\\{left\_type}&\\{left} info&$\\{x\_coord},\\{y\_coord}$&\\{right\_type}&% +\\{right} info\cr +\noalign{\yskip} +\\{endpoint}&\lodash$,\,$\lodash&$x_0,y_0$&\\{curl}&$1.0,1.0$\cr +\\{open}&\lodash$,1.0$&$x_1,y_1$&\\{open}&\lodash$,-1.0$\cr +\\{curl}&$2.0,-1.0$&$x_2,y_2$&\\{curl}&$2.0,1.0$\cr +\\{given}&$d,1.0$&$x_3,y_3$&\\{given}&$d,3.0$\cr +\\{open}&\lodash$,4.0$&$x_4,y_4$&\\{explicit}&$x_{45},y_{45}$\cr +\\{explicit}&$x_{54},y_{54}$&$x_5,y_5$&\\{endpoint}&\lodash$,\,$\lodash\cr}}$$ +Here \|d is the \\{angle} obtained by calling $\\{n\_arg}(-\\{unity},-% +\\{two})$. +Of course, this example is more complicated than anything a normal user +would ever write. + +These types must satisfy certain restrictions because of the form of \MF's +path syntax: +(i)~\\{open} type never appears in the same node together with \\{endpoint}, +\\{given}, or \\{curl}. +(ii)~The \\{right\_type} of a node is \\{explicit} if and only if the +\\{left\_type} of the following node is \\{explicit}. +(iii)~\\{endpoint} types occur only at the ends, as mentioned above. + +\Y\P\D \37$\\{left\_curl}\S\\{left\_x}$\C{curl information when entering this +knot}\par +\P\D \37$\\{left\_given}\S\\{left\_x}$\C{given direction when entering this +knot}\par +\P\D \37$\\{left\_tension}\S\\{left\_y}$\C{tension information when entering +this knot}\par +\P\D \37$\\{right\_curl}\S\\{right\_x}$\C{curl information when leaving this +knot}\par +\P\D \37$\\{right\_given}\S\\{right\_x}$\C{given direction when leaving this +knot}\par +\P\D \37$\\{right\_tension}\S\\{right\_y}$\C{tension information when leaving +this knot}\par +\P\D \37$\\{explicit}=1$\C{\\{left\_type} or \\{right\_type} when control +points are known}\par +\P\D \37$\\{given}=2$\C{\\{left\_type} or \\{right\_type} when a direction is +given}\par +\P\D \37$\\{curl}=3$\C{\\{left\_type} or \\{right\_type} when a curl is +desired}\par +\P\D \37$\\{open}=4$\C{\\{left\_type} or \\{right\_type} when \MF\ should +choose the direction}\par +\fi + +\M257. Here is a diagnostic routine that prints a given knot list +in symbolic form. It illustrates the conventions discussed above, +and checks for anomalies that might arise while \MF\ is being debugged. + +\Y\P$\4\X257:Declare subroutines for printing expressions\X\S$\6 +\4\&{procedure}\1\ \37$\\{print\_path}(\|h:\\{pointer};\,\35\|s:\\{str% +\_number};\,\35\\{nuline}:\\{boolean})$;\6 +\4\&{label} \37$\\{done},\39\\{done1}$;\6 +\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{for list traversal}\2\6 +\&{begin} \37$\\{print\_diagnostic}(\.{"Path"},\39\|s,\39\\{nuline})$;\5 +\\{print\_ln};\5 +$\|p\K\|h$;\6 +\1\&{repeat} \37$\|q\K\\{link}(\|p)$;\6 +\&{if} $(\|p=\\{null})\V(\|q=\\{null})$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"???"})$;\5 +\&{goto} \37\\{done};\C{this won't happen}\6 +\&{end};\2\6 +\X258:Print information for adjacent knots \|p and \|q\X;\6 +$\|p\K\|q$;\6 +\&{if} $(\|p\I\|h)\V(\\{left\_type}(\|h)\I\\{endpoint})$ \1\&{then}\5 +\X259:Print two dots, followed by \\{given} or \\{curl} if present\X;\2\6 +\4\&{until}\5 +$\|p=\|h$;\2\6 +\&{if} $\\{left\_type}(\|h)\I\\{endpoint}$ \1\&{then}\5 +$\\{print}(\.{"cycle"})$;\2\6 +\4\\{done}: \37$\\{end\_diagnostic}(\\{true})$;\6 +\&{end};\par +\As332, 388, 473, 589, 801\ETs807. +\U246.\fi + +\M258. \P$\X258:Print information for adjacent knots \|p and \|q\X\S$\6 +$\\{print\_two}(\\{x\_coord}(\|p),\39\\{y\_coord}(\|p))$;\6 +\&{case} $\\{right\_type}(\|p)$ \1\&{of}\6 +\4\\{endpoint}: \37\&{begin} \37\&{if} $\\{left\_type}(\|p)=\\{open}$ \1% +\&{then}\5 +$\\{print}(\.{"\{open?\}"})$;\C{can't happen}\2\6 +\&{if} $(\\{left\_type}(\|q)\I\\{endpoint})\V(\|q\I\|h)$ \1\&{then}\5 +$\|q\K\\{null}$;\C{force an error}\2\6 +\&{goto} \37\\{done1};\6 +\&{end};\6 +\4\\{explicit}: \37\X261:Print control points between \|p and \|q, then % +\&{goto} \\{done1}\X;\6 +\4\\{open}: \37\X262:Print information for a curve that begins \\{open}\X;\6 +\4$\\{curl},\39\\{given}$: \37\X263:Print information for a curve that begins % +\\{curl} or \\{given}\X;\6 +\4\&{othercases} \37$\\{print}(\.{"???"})$\C{can't happen}\2\6 +\&{endcases};\6 +\&{if} $\\{left\_type}(\|q)\L\\{explicit}$ \1\&{then}\5 +$\\{print}(\.{"..control?"})$\C{can't happen}\6 +\4\&{else} \&{if} $(\\{right\_tension}(\|p)\I\\{unity})\V(\\{left\_tension}(% +\|q)\I\\{unity})$ \1\&{then}\5 +\X260:Print tension between \|p and \|q\X;\2\2\6 +\4\\{done1}: \37\par +\U257.\fi + +\M259. Since \\{n\_sin\_cos} produces \\{fraction} results, which we will print +as if they +were \\{scaled}, the magnitude of a \\{given} direction vector will be~4096. + +\Y\P$\4\X259:Print two dots, followed by \\{given} or \\{curl} if present\X\S$\6 +\&{begin} \37$\\{print\_nl}(\.{"\ .."})$;\6 +\&{if} $\\{left\_type}(\|p)=\\{given}$ \1\&{then}\6 +\&{begin} \37$\\{n\_sin\_cos}(\\{left\_given}(\|p))$;\5 +$\\{print\_char}(\.{"\{"})$;\5 +$\\{print\_scaled}(\\{n\_cos})$;\5 +$\\{print\_char}(\.{","})$;\5 +$\\{print\_scaled}(\\{n\_sin})$;\5 +$\\{print\_char}(\.{"\}"})$;\6 +\&{end}\6 +\4\&{else} \&{if} $\\{left\_type}(\|p)=\\{curl}$ \1\&{then}\6 +\&{begin} \37$\\{print}(\.{"\{curl\ "})$;\5 +$\\{print\_scaled}(\\{left\_curl}(\|p))$;\5 +$\\{print\_char}(\.{"\}"})$;\6 +\&{end};\2\2\6 +\&{end}\par +\U257.\fi + +\M260. \P$\X260:Print tension between \|p and \|q\X\S$\6 +\&{begin} \37$\\{print}(\.{"..tension\ "})$;\6 +\&{if} $\\{right\_tension}(\|p)<0$ \1\&{then}\5 +$\\{print}(\.{"atleast"})$;\2\6 +$\\{print\_scaled}(\\{abs}(\\{right\_tension}(\|p)))$;\6 +\&{if} $\\{right\_tension}(\|p)\I\\{left\_tension}(\|q)$ \1\&{then}\6 +\&{begin} \37$\\{print}(\.{"\ and\ "})$;\6 +\&{if} $\\{left\_tension}(\|q)<0$ \1\&{then}\5 +$\\{print}(\.{"atleast"})$;\2\6 +$\\{print\_scaled}(\\{abs}(\\{left\_tension}(\|q)))$;\6 +\&{end};\2\6 +\&{end}\par +\U258.\fi + +\M261. \P$\X261:Print control points between \|p and \|q, then \&{goto} % +\\{done1}\X\S$\6 +\&{begin} \37$\\{print}(\.{"..controls\ "})$;\5 +$\\{print\_two}(\\{right\_x}(\|p),\39\\{right\_y}(\|p))$;\5 +$\\{print}(\.{"\ and\ "})$;\6 +\&{if} $\\{left\_type}(\|q)\I\\{explicit}$ \1\&{then}\5 +$\\{print}(\.{"??"})$\C{can't happen}\6 +\4\&{else} $\\{print\_two}(\\{left\_x}(\|q),\39\\{left\_y}(\|q))$;\2\6 +\&{goto} \37\\{done1};\6 +\&{end}\par +\U258.\fi + +\M262. \P$\X262:Print information for a curve that begins \\{open}\X\S$\6 +\&{if} $(\\{left\_type}(\|p)\I\\{explicit})\W(\\{left\_type}(\|p)\I\\{open})$ % +\1\&{then}\5 +$\\{print}(\.{"\{open?\}"})$\C{can't happen}\2\par +\U258.\fi + +\M263. A curl of 1 is shown explicitly, so that the user sees clearly that +\MF's default curl is present. + +The code here uses the fact that $\\{left\_curl}\S\\{left\_given}$ and +$\\{right\_curl}\S\\{right\_given}$. + +\Y\P$\4\X263:Print information for a curve that begins \\{curl} or \\{given}\X% +\S$\6 +\&{begin} \37\&{if} $\\{left\_type}(\|p)=\\{open}$ \1\&{then}\5 +$\\{print}(\.{"??"})$;\C{can't happen}\2\6 +\&{if} $\\{right\_type}(\|p)=\\{curl}$ \1\&{then}\6 +\&{begin} \37$\\{print}(\.{"\{curl\ "})$;\5 +$\\{print\_scaled}(\\{right\_curl}(\|p))$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{n\_sin\_cos}(\\{right\_given}(\|p))$;\5 +$\\{print\_char}(\.{"\{"})$;\5 +$\\{print\_scaled}(\\{n\_cos})$;\5 +$\\{print\_char}(\.{","})$;\5 +$\\{print\_scaled}(\\{n\_sin})$;\6 +\&{end};\2\6 +$\\{print\_char}(\.{"\}"})$;\6 +\&{end}\par +\U258.\fi + +\M264. If we want to duplicate a knot node, we can say \\{copy\_knot}: + +\Y\P\4\&{function}\1\ \37$\\{copy\_knot}(\|p:\\{pointer})$: \37\\{pointer};\6 +\4\&{var} \37\|q: \37\\{pointer};\C{the copy}\6 +\|k: \37$0\to\\{knot\_node\_size}-1$;\C{runs through the words of a knot node}% +\2\6 +\&{begin} \37$\|q\K\\{get\_node}(\\{knot\_node\_size})$;\6 +\&{for} $\|k\K0\mathrel{\&{to}}\\{knot\_node\_size}-1$ \1\&{do}\5 +$\\{mem}[\|q+\|k]\K\\{mem}[\|p+\|k]$;\2\6 +$\\{copy\_knot}\K\|q$;\6 +\&{end};\par +\fi + +\M265. The \\{copy\_path} routine makes a clone of a given path. + +\Y\P\4\&{function}\1\ \37$\\{copy\_path}(\|p:\\{pointer})$: \37\\{pointer};\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37$\|q,\39\\{pp},\39\\{qq}$: \37\\{pointer};\C{for list +manipulation}\2\6 +\&{begin} \37$\|q\K\\{get\_node}(\\{knot\_node\_size})$;\C{this will correspond +to \|p}\6 +$\\{qq}\K\|q$;\5 +$\\{pp}\K\|p$;\6 +\~ \1\&{loop}\ \&{begin} \37$\\{left\_type}(\\{qq})\K\\{left\_type}(\\{pp})$;\5 +$\\{right\_type}(\\{qq})\K\\{right\_type}(\\{pp})$;\6 +$\\{x\_coord}(\\{qq})\K\\{x\_coord}(\\{pp})$;\5 +$\\{y\_coord}(\\{qq})\K\\{y\_coord}(\\{pp})$;\6 +$\\{left\_x}(\\{qq})\K\\{left\_x}(\\{pp})$;\5 +$\\{left\_y}(\\{qq})\K\\{left\_y}(\\{pp})$;\6 +$\\{right\_x}(\\{qq})\K\\{right\_x}(\\{pp})$;\5 +$\\{right\_y}(\\{qq})\K\\{right\_y}(\\{pp})$;\6 +\&{if} $\\{link}(\\{pp})=\|p$ \1\&{then}\6 +\&{begin} \37$\\{link}(\\{qq})\K\|q$;\5 +$\\{copy\_path}\K\|q$;\5 +\&{return};\6 +\&{end};\2\6 +$\\{link}(\\{qq})\K\\{get\_node}(\\{knot\_node\_size})$;\5 +$\\{qq}\K\\{link}(\\{qq})$;\5 +$\\{pp}\K\\{link}(\\{pp})$;\6 +\&{end};\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M266. Similarly, there's a way to copy the {\sl reverse\/} of a path. This +procedure +returns a pointer to the first node of the copy, if the path is a cycle, +but to the final node of a non-cyclic copy. The global +variable \\{path\_tail} will point to the final node of the original path; +this trick makes it easier to implement `\&{doublepath}'. + +All node types are assumed to be \\{endpoint} or \\{explicit} only. + +\Y\P\4\&{function}\1\ \37$\\{htap\_ypoc}(\|p:\\{pointer})$: \37\\{pointer};\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37$\|q,\39\\{pp},\39\\{qq},\39\\{rr}$: \37\\{pointer};\C{for list +manipulation}\2\6 +\&{begin} \37$\|q\K\\{get\_node}(\\{knot\_node\_size})$;\C{this will correspond +to \|p}\6 +$\\{qq}\K\|q$;\5 +$\\{pp}\K\|p$;\6 +\~ \1\&{loop}\ \&{begin} \37$\\{right\_type}(\\{qq})\K\\{left\_type}(\\{pp})$;\5 +$\\{left\_type}(\\{qq})\K\\{right\_type}(\\{pp})$;\6 +$\\{x\_coord}(\\{qq})\K\\{x\_coord}(\\{pp})$;\5 +$\\{y\_coord}(\\{qq})\K\\{y\_coord}(\\{pp})$;\6 +$\\{right\_x}(\\{qq})\K\\{left\_x}(\\{pp})$;\5 +$\\{right\_y}(\\{qq})\K\\{left\_y}(\\{pp})$;\6 +$\\{left\_x}(\\{qq})\K\\{right\_x}(\\{pp})$;\5 +$\\{left\_y}(\\{qq})\K\\{right\_y}(\\{pp})$;\6 +\&{if} $\\{link}(\\{pp})=\|p$ \1\&{then}\6 +\&{begin} \37$\\{link}(\|q)\K\\{qq}$;\5 +$\\{path\_tail}\K\\{pp}$;\5 +$\\{htap\_ypoc}\K\|q$;\5 +\&{return};\6 +\&{end};\2\6 +$\\{rr}\K\\{get\_node}(\\{knot\_node\_size})$;\5 +$\\{link}(\\{rr})\K\\{qq}$;\5 +$\\{qq}\K\\{rr}$;\5 +$\\{pp}\K\\{link}(\\{pp})$;\6 +\&{end};\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M267. \P$\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{path\_tail}: \37\\{pointer};\C{the node that links to the beginning of a +path}\par +\fi + +\M268. When a cyclic list of knot nodes is no longer needed, it can be recycled +by +calling the following subroutine. + +\Y\P$\4\X268:Declare the recycling subroutines\X\S$\6 +\4\&{procedure}\1\ \37$\\{toss\_knot\_list}(\|p:\\{pointer})$;\6 +\4\&{var} \37\|q: \37\\{pointer};\C{the node being freed}\6 +\|r: \37\\{pointer};\C{the next node}\2\6 +\&{begin} \37$\|q\K\|p$;\6 +\1\&{repeat} \37$\|r\K\\{link}(\|q)$;\5 +$\\{free\_node}(\|q,\39\\{knot\_node\_size})$;\5 +$\|q\K\|r$;\6 +\4\&{until}\5 +$\|q=\|p$;\2\6 +\&{end};\par +\As385, 487, 620\ETs809. +\U246.\fi + +\N269. \[18] Choosing control points. +Now we must actually delve into one of \MF's more difficult routines, +the \\{make\_choices} procedure that chooses angles and control points for +the splines of a curve when the user has not specified them explicitly. +The parameter to \\{make\_choices} points to a list of knots and +path information, as described above. + +A path decomposes into independent segments at ``breakpoint'' knots, +which are knots whose left and right angles are both prespecified in +some way (i.e., their \\{left\_type} and \\{right\_type} aren't both open). + +\Y\P\hbox{\4}\X284:Declare the procedure called \\{solve\_choices}\X\6 +\4\&{procedure}\1\ \37$\\{make\_choices}(\\{knots}:\\{pointer})$;\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37\|h: \37\\{pointer};\C{the first breakpoint}\6 +$\|p,\39\|q$: \37\\{pointer};\C{consecutive breakpoints being processed}\6 +\X280:Other local variables for \\{make\_choices}\X\2\6 +\&{begin} \37\\{check\_arith};\C{make sure that $\\{arith\_error}=\\{false}$}\6 +\&{if} $\\{internal}[\\{tracing\_choices}]>0$ \1\&{then}\5 +$\\{print\_path}(\\{knots},\39\.{",\ before\ choices"},\39\\{true})$;\2\6 +\X271:If consecutive knots are equal, join them explicitly\X;\6 +\X272:Find the first breakpoint, \|h, on the path; insert an artificial +breakpoint if the path is an unbroken cycle\X;\6 +$\|p\K\|h$;\6 +\1\&{repeat} \37\X273:Fill in the control points between \|p and the next +breakpoint, then advance \|p to that breakpoint\X;\6 +\4\&{until}\5 +$\|p=\|h$;\2\6 +\&{if} $\\{internal}[\\{tracing\_choices}]>0$ \1\&{then}\5 +$\\{print\_path}(\\{knots},\39\.{",\ after\ choices"},\39\\{true})$;\2\6 +\&{if} $\\{arith\_error}$ \1\&{then}\5 +\X270:Report an unexpected problem during the choice-making\X;\2\6 +\&{end};\par +\fi + +\M270. \P$\X270:Report an unexpected problem during the choice-making\X\S$\6 +\&{begin} \37$\\{print\_err}(\.{"Some\ number\ got\ too\ big"})$;\5 +$\\{help2}(\.{"The\ path\ that\ I\ just\ computed\ is\ out\ of\ range."})$\6 +$(\.{"So\ it\ will\ probably\ look\ funny.\ Proceed,\ for\ a\ laugh."})$;\5 +\\{put\_get\_error};\5 +$\\{arith\_error}\K\\{false}$;\6 +\&{end}\par +\U269.\fi + +\M271. Two knots in a row with the same coordinates will always be joined +by an explicit ``curve'' whose control points are identical with the +knots. + +\Y\P$\4\X271:If consecutive knots are equal, join them explicitly\X\S$\6 +$\|p\K\\{knots}$;\6 +\1\&{repeat} \37$\|q\K\\{link}(\|p)$;\6 +\&{if} $\\{x\_coord}(\|p)=\\{x\_coord}(\|q)$ \1\&{then}\6 +\&{if} $\\{y\_coord}(\|p)=\\{y\_coord}(\|q)$ \1\&{then}\6 +\&{if} $\\{right\_type}(\|p)>\\{explicit}$ \1\&{then}\6 +\&{begin} \37$\\{right\_type}(\|p)\K\\{explicit}$;\6 +\&{if} $\\{left\_type}(\|p)=\\{open}$ \1\&{then}\6 +\&{begin} \37$\\{left\_type}(\|p)\K\\{curl}$;\5 +$\\{left\_curl}(\|p)\K\\{unity}$;\6 +\&{end};\2\6 +$\\{left\_type}(\|q)\K\\{explicit}$;\6 +\&{if} $\\{right\_type}(\|q)=\\{open}$ \1\&{then}\6 +\&{begin} \37$\\{right\_type}(\|q)\K\\{curl}$;\5 +$\\{right\_curl}(\|q)\K\\{unity}$;\6 +\&{end};\2\6 +$\\{right\_x}(\|p)\K\\{x\_coord}(\|p)$;\5 +$\\{left\_x}(\|q)\K\\{x\_coord}(\|p)$;\6 +$\\{right\_y}(\|p)\K\\{y\_coord}(\|p)$;\5 +$\\{left\_y}(\|q)\K\\{y\_coord}(\|p)$;\6 +\&{end};\2\2\2\6 +$\|p\K\|q$;\6 +\4\&{until}\5 +$\|p=\\{knots}$\2\par +\U269.\fi + +\M272. If there are no breakpoints, it is necessary to compute the direction +angles around an entire cycle. In this case the \\{left\_type} of the first +node is temporarily changed to \\{end\_cycle}. + +\Y\P\D \37$\\{end\_cycle}=\\{open}+1$\par +\Y\P$\4\X272:Find the first breakpoint, \|h, on the path; insert an artificial +breakpoint if the path is an unbroken cycle\X\S$\6 +$\|h\K\\{knots}$;\6 +\~ \1\&{loop}\ \&{begin} \37\&{if} $\\{left\_type}(\|h)\I\\{open}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +\&{if} $\\{right\_type}(\|h)\I\\{open}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\|h\K\\{link}(\|h)$;\6 +\&{if} $\|h=\\{knots}$ \1\&{then}\6 +\&{begin} \37$\\{left\_type}(\|h)\K\\{end\_cycle}$;\5 +\&{goto} \37\\{done};\6 +\&{end};\2\6 +\&{end};\2\6 +\4\\{done}: \37\par +\U269.\fi + +\M273. If $\\{right\_type}(\|p)<\\{given}$ and $\|q=\\{link}(\|p)$, we must +have +$\\{right\_type}(\|p)=\\{left\_type}(\|q)=\\{explicit}$ or \\{endpoint}. + +\Y\P$\4\X273:Fill in the control points between \|p and the next breakpoint, +then advance \|p to that breakpoint\X\S$\6 +$\|q\K\\{link}(\|p)$;\6 +\&{if} $\\{right\_type}(\|p)\G\\{given}$ \1\&{then}\6 +\&{begin} \37\&{while} $(\\{left\_type}(\|q)=\\{open})\W(\\{right\_type}(\|q)=% +\\{open})$ \1\&{do}\5 +$\|q\K\\{link}(\|q)$;\2\6 +\X278:Fill in the control information between consecutive breakpoints \|p and % +\|q\X;\6 +\&{end};\2\6 +$\|p\K\|q$\par +\U269.\fi + +\M274. Before we can go further into the way choices are made, we need to +consider the underlying theory. The basic ideas implemented in \\{make% +\_choices} +are due to John Hobby, who introduced the notion of ``mock curvature'' +at a knot. Angles are chosen so that they preserve mock curvature when +a knot is passed, and this has been found to produce excellent results. + +It is convenient to introduce some notations that simplify the necessary +formulas. Let $d_{k,k+1}=\vert z\k-z_k\vert$ be the (nonzero) distance +between knots \|k and $\|k+1$; and let +$${z\k-z_k\over z_k-z_{k-1}}={d_{k,k+1}\over d_{k-1,k}}e^{i\psi_k}$$ +so that a polygonal line from $z_{k-1}$ to $z_k$ to $z\k$ turns left +through an angle of~$\psi_k$. We assume that $\vert\psi_k\vert\L180^\circ$. +The control points for the spline from $z_k$ to $z\k$ will be denoted by +$$\eqalign{z_k^+&=z_k+ +\textstyle{1\over3}\rho_k e^{i\theta_k}(z\k-z_k),\cr +z\k^-&=z\k- +\textstyle{1\over3}\sigma\k e^{-i\phi\k}(z\k-z_k),\cr}$$ +where $\rho_k$ and $\sigma\k$ are nonnegative ``velocity ratios'' at the +beginning and end of the curve, while $\theta_k$ and $\phi\k$ are the +corresponding ``offset angles.'' These angles satisfy the condition +$$\theta_k+\phi_k+\psi_k=0,\eqno(*)$$ +whenever the curve leaves an intermediate knot~\|k in the direction that +it enters. + +\fi + +\M275. Let $\alpha_k$ and $\beta\k$ be the reciprocals of the ``tension'' of +the curve at its beginning and ending points. This means that +$\rho_k=\alpha_k f(\theta_k,\phi\k)$ and $\sigma\k=\beta\k f(\phi\k,\theta_k)$, +where $f(\theta,\phi)$ is \MF's standard velocity function defined in +the \\{velocity} subroutine. The cubic spline $B(z_k^{\phantom+},z_k^+, +z\k^-,z\k^{\phantom+};t)$ +has curvature +$${2\sigma\k\sin(\theta_k+\phi\k)-6\sin\theta_k\over\rho_k^2d_{k,k+1}} +\qquad{\rm and}\qquad +{2\rho_k\sin(\theta_k+\phi\k)-6\sin\phi\k\over\sigma\k^2d_{k,k+1}}$$ +at $\|t=0$ and $\|t=1$, respectively. The mock curvature is the linear +approximation to this true curvature that arises in the limit for +small $\theta_k$ and~$\phi\k$, if second-order terms are discarded. +The standard velocity function satisfies +$$f(\theta,\phi)=1+O(\theta^2+\theta\phi+\phi^2);$$ +hence the mock curvatures are respectively +$${2\beta\k(\theta_k+\phi\k)-6\theta_k\over\alpha_k^2d_{k,k+1}} +\qquad{\rm and}\qquad +{2\alpha_k(\theta_k+\phi\k)-6\phi\k\over\beta\k^2d_{k,k+1}}.\eqno(**)$$ + +\fi + +\M276. The turning angles $\psi_k$ are given, and equation $(*)$ above +determines $\phi_k$ when $\theta_k$ is known, so the task of +angle selection is essentially to choose appropriate values for each +$\theta_k$. When equation~$(*)$ is used to eliminate $\phi$~variables +from $(**)$, we obtain a system of linear equations of the form +$$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta\k=-B_k\psi_k-D_k\psi\k,$$ +where +$$A_k={\alpha_{k-1}\over\beta_k^2d_{k-1,k}}, +\qquad B_k={3-\alpha_{k-1}\over\beta_k^2d_{k-1,k}}, +\qquad C_k={3-\beta\k\over\alpha_k^2d_{k,k+1}}, +\qquad D_k={\beta\k\over\alpha_k^2d_{k,k+1}}.$$ +The tensions are always $3\over4$ or more, hence each $\alpha$ and~$\beta$ +will be at most $4\over3$. It follows that $B_k\G{5\over4}A_k$ and +$C_k\G{5\over4}D_k$; hence the equations are diagonally dominant; +hence they have a unique solution. Moreover, in most cases the tensions +are equal to~1, so that $B_k=2A_k$ and $C_k=2D_k$. This makes the +solution numerically stable, and there is an exponential damping +effect: The data at knot $k\pm j$ affects the angle at knot~$k$ by +a factor of~$O(2^{-j})$. + +\fi + +\M277. However, we still must consider the angles at the starting and ending +knots of a non-cyclic path. These angles might be given explicitly, or +they might be specified implicitly in terms of an amount of ``curl.'' + +Let's assume that angles need to be determined for a non-cyclic path +starting at $z_0$ and ending at~$z_n$. Then equations of the form +$$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta_{k+1}=R_k$$ +have been given for $0<k<n$, and it will be convenient to introduce +equations of the same form for $k=0$ and $k=n$, where +$$A_0=B_0=C_n=D_n=0.$$ +If $\theta_0$ is supposed to have a given value $E_0$, we simply +define $C_0=0$, $D_0=0$, and $R_0=E_0$. Otherwise a curl +parameter, $\gamma_0$, has been specified at~$z_0$; this means +that the mock curvature at $z_0$ should be $\gamma_0$ times the +mock curvature at $z_1$; i.e., +$${2\beta_1(\theta_0+\phi_1)-6\theta_0\over\alpha_0^2d_{01}} +=\gamma_0{2\alpha_0(\theta_0+\phi_1)-6\phi_1\over\beta_1^2d_{01}}.$$ +This equation simplifies to +$$(\alpha_0\chi_0+3-\beta_1)\theta_0+ +\bigl((3-\alpha_0)\chi_0+\beta_1\bigr)\theta_1= +-\bigl((3-\alpha_0)\chi_0+\beta_1\bigr)\psi_1,$$ +where $\chi_0=\alpha_0^2\gamma_0/\beta_1^2$; so we can set $C_0= +\chi_0\alpha_0+3-\beta_1$, $D_0=(3-\alpha_0)\chi_0+\beta_1$, $R_0=-D_0\psi_1$. +It can be shown that $C_0>0$ and $C_0B_1-A_1D_0>0$ when $\gamma_0\G0$, +hence the linear equations remain nonsingular. + +Similar considerations apply at the right end, when the final angle $\phi_n$ +may or may not need to be determined. It is convenient to let $\psi_n=0$, +hence $\theta_n=-\phi_n$. We either have an explicit equation $\theta_n=E_n$, +or we have +$$\bigl((3-\beta_n)\chi_n+\alpha_{n-1}\bigr)\theta_{n-1}+ +(\beta_n\chi_n+3-\alpha_{n-1})\theta_n=0,\qquad +\chi_n={\beta_n^2\gamma_n\over\alpha_{n-1}^2}.$$ + +When \\{make\_choices} chooses angles, it must compute the coefficients of +these linear equations, then solve the equations. To compute the coefficients, +it is necessary to compute arctangents of the given turning angles~$\psi_k$. +When the equations are solved, the chosen directions $\theta_k$ are put +back into the form of control points by essentially computing sines and +cosines. + +\fi + +\M278. OK, we are ready to make the hard choices of \\{make\_choices}. +Most of the work is relegated to an auxiliary procedure +called \\{solve\_choices}, which has been introduced to keep +\\{make\_choices} from being extremely long. + +\Y\P$\4\X278:Fill in the control information between consecutive breakpoints % +\|p and \|q\X\S$\6 +\X281:Calculate the turning angles $\psi_k$ and the distances $d_{k,k+1}$; set +$n$ to the length of the path\X;\6 +\X282:Remove \\{open} types at the breakpoints\X;\6 +$\\{solve\_choices}(\|p,\39\|q,\39\|n)$\par +\U273.\fi + +\M279. It's convenient to precompute quantities that will be needed several +times later. The values of $\\{delta\_x}[\|k]$ and $\\{delta\_y}[\|k]$ will be +the +coordinates of $z\k-z_k$, and the magnitude of this vector will be +$\\{delta}[\|k]=\hbox{$d_{k,k+1}$}$. The path angle $\psi_k$ between +$z_k-z_{k-1}$ +and $z\k-z_k$ will be stored in $\\{psi}[\|k]$. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4$\\{delta\_x},\39\\{delta\_y},\39\\{delta}$: \37\&{array} $[0\to\\{path% +\_size}]$ \1\&{of}\5 +\\{scaled};\C{knot differences}\2\6 +\4\\{psi}: \37\&{array} $[1\to\\{path\_size}]$ \1\&{of}\5 +\\{angle};\C{turning angles}\2\par +\fi + +\M280. \P$\X280:Other local variables for \\{make\_choices}\X\S$\6 +\4$\|k,\39\|n$: \37$0\to\\{path\_size}$;\C{current and final knot numbers}\6 +\4$\|s,\39\|t$: \37\\{pointer};\C{registers for list traversal}\6 +\4$\\{delx},\39\\{dely}$: \37\\{scaled};\C{directions where \\{open} meets % +\\{explicit}}\6 +\4$\\{sine},\39\\{cosine}$: \37\\{fraction};\C{trig functions of various +angles}\par +\U269.\fi + +\M281. \P$\X281:Calculate the turning angles $\psi_k$ and the distances +$d_{k,k+1}$; set $n$ to the length of the path\X\S$\6 +$\|k\K0$;\5 +$\|s\K\|p$;\5 +$\|n\K\\{path\_size}$;\6 +\1\&{repeat} \37$\|t\K\\{link}(\|s)$;\5 +$\\{delta\_x}[\|k]\K\\{x\_coord}(\|t)-\\{x\_coord}(\|s)$;\5 +$\\{delta\_y}[\|k]\K\\{y\_coord}(\|t)-\\{y\_coord}(\|s)$;\5 +$\\{delta}[\|k]\K\\{pyth\_add}(\\{delta\_x}[\|k],\39\\{delta\_y}[\|k])$;\6 +\&{if} $\|k>0$ \1\&{then}\6 +\&{begin} \37$\\{sine}\K\\{make\_fraction}(\\{delta\_y}[\|k-1],\39\\{delta}[% +\|k-1])$;\5 +$\\{cosine}\K\\{make\_fraction}(\\{delta\_x}[\|k-1],\39\\{delta}[\|k-1])$;\5 +$\\{psi}[\|k]\K\\{n\_arg}(\\{take\_fraction}(\\{delta\_x}[\|k],\39\\{cosine})+% +\\{take\_fraction}(\\{delta\_y}[\|k],\39\\{sine}),\39\\{take\_fraction}(% +\\{delta\_y}[\|k],\39\\{cosine})-\\{take\_fraction}(\\{delta\_x}[\|k],\39% +\\{sine}))$;\6 +\&{end};\2\6 +$\\{incr}(\|k)$;\5 +$\|s\K\|t$;\6 +\&{if} $\|k=\\{path\_size}$ \1\&{then}\5 +$\\{overflow}(\.{"path\ size"},\39\\{path\_size})$;\2\6 +\&{if} $\|s=\|q$ \1\&{then}\5 +$\|n\K\|k$;\2\6 +\4\&{until}\5 +$(\|k\G\|n)\W(\\{left\_type}(\|s)\I\\{end\_cycle})$;\2\6 +\&{if} $\|k=\|n$ \1\&{then}\5 +$\\{psi}[\|n]\K0$\ \&{else} $\\{psi}[\|k]\K\\{psi}[1]$\2\par +\U278.\fi + +\M282. When we get to this point of the code, $\\{right\_type}(\|p)$ is either +\\{given} or \\{curl} or \\{open}. If it is \\{open}, we must have +$\\{left\_type}(\|p)=\\{end\_cycle}$ or $\\{left\_type}(\|p)=\\{explicit}$. In +the latter +case, the \\{open} type is converted to \\{given}; however, if the +velocity coming into this knot is zero, the \\{open} type is +converted to a \\{curl}, since we don't know the incoming direction. + +Similarly, $\\{left\_type}(\|q)$ is either \\{given} or \\{curl} or \\{open} or +\\{end\_cycle}. The \\{open} possibility is reduced either to \\{given} or to % +\\{curl}. + +\Y\P$\4\X282:Remove \\{open} types at the breakpoints\X\S$\6 +\&{if} $\\{left\_type}(\|q)=\\{open}$ \1\&{then}\6 +\&{begin} \37$\\{delx}\K\\{right\_x}(\|q)-\\{x\_coord}(\|q)$;\5 +$\\{dely}\K\\{right\_y}(\|q)-\\{y\_coord}(\|q)$;\6 +\&{if} $(\\{delx}=0)\W(\\{dely}=0)$ \1\&{then}\6 +\&{begin} \37$\\{left\_type}(\|q)\K\\{curl}$;\5 +$\\{left\_curl}(\|q)\K\\{unity}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{left\_type}(\|q)\K\\{given}$;\5 +$\\{left\_given}(\|q)\K\\{n\_arg}(\\{delx},\39\\{dely})$;\6 +\&{end};\2\6 +\&{end};\2\6 +\&{if} $(\\{right\_type}(\|p)=\\{open})\W(\\{left\_type}(\|p)=\\{explicit})$ \1% +\&{then}\6 +\&{begin} \37$\\{delx}\K\\{x\_coord}(\|p)-\\{left\_x}(\|p)$;\5 +$\\{dely}\K\\{y\_coord}(\|p)-\\{left\_y}(\|p)$;\6 +\&{if} $(\\{delx}=0)\W(\\{dely}=0)$ \1\&{then}\6 +\&{begin} \37$\\{right\_type}(\|p)\K\\{curl}$;\5 +$\\{right\_curl}(\|p)\K\\{unity}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{right\_type}(\|p)\K\\{given}$;\5 +$\\{right\_given}(\|p)\K\\{n\_arg}(\\{delx},\39\\{dely})$;\6 +\&{end};\2\6 +\&{end}\2\par +\U278.\fi + +\M283. Linear equations need to be solved whenever $\|n>1$; and also when $% +\|n=1$ +and exactly one of the breakpoints involves a curl. The simplest case occurs +when $\|n=1$ and there is a curl at both breakpoints; then we simply draw +a straight line. + +But before coding up the simple cases, we might as well face the general case, +since we must deal with it sooner or later, and since the general case +is likely to give some insight into the way simple cases can be handled best. + +When there is no cycle, the linear equations to be solved form a tri-diagonal +system, and we can apply the standard technique of Gaussian elimination +to convert that system to a sequence of equations of the form +$$\theta_0+u_0\theta_1=v_0,\quad +\theta_1+u_1\theta_2=v_1,\quad\ldots,\quad +\theta_{n-1}+u_{n-1}\theta_n=v_{n-1},\quad +\theta_n=v_n.$$ +It is possible to do this diagonalization while generating the equations. +Once $\theta_n$ is known, it is easy to determine $\theta_{n-1}$, \dots, +$\theta_1$, $\theta_0$; thus, the equations will be solved. + +The procedure is slightly more complex when there is a cycle, but the +basic idea will be nearly the same. In the cyclic case the right-hand +sides will be $v_k+w_k\theta_0$ instead of simply $v_k$, and we will start +the process off with $u_0=v_0=0$, $w_0=1$. The final equation will be not +$\theta_n=v_n$ but $\theta_n+u_n\theta_1=v_n+w_n\theta_0$; an appropriate +ending routine will take account of the fact that $\theta_n=\theta_0$ and +eliminate the $w$'s from the system, after which the solution can be +obtained as before. + +When $u_k$, $v_k$, and $w_k$ are being computed, the three pointer +variables \|r, \|s,~\|t will point respectively to knots $\|k-1$, \|k, +and~$\|k+1$. The $u$'s and $w$'s are scaled by $2^{28}$, i.e., they are +of type \\{fraction}; the $\theta$'s and $v$'s are of type \\{angle}. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{theta}: \37\&{array} $[0\to\\{path\_size}]$ \1\&{of}\5 +\\{angle};\C{values of $\theta_k$}\2\6 +\4\\{uu}: \37\&{array} $[0\to\\{path\_size}]$ \1\&{of}\5 +\\{fraction};\C{values of $u_k$}\2\6 +\4\\{vv}: \37\&{array} $[0\to\\{path\_size}]$ \1\&{of}\5 +\\{angle};\C{values of $v_k$}\2\6 +\4\\{ww}: \37\&{array} $[0\to\\{path\_size}]$ \1\&{of}\5 +\\{fraction};\C{values of $w_k$}\2\par +\fi + +\M284. Our immediate problem is to get the ball rolling by setting up the +first equation or by realizing that no equations are needed, and to fit +this initialization into a framework suitable for the overall computation. + +\Y\P$\4\X284:Declare the procedure called \\{solve\_choices}\X\S$\6 +\hbox{\4}\X296:Declare subroutines needed by \\{solve\_choices}\X\6 +\4\&{procedure}\1\ \37$\\{solve\_choices}(\|p,\39\|q:\\{pointer};\,\35\|n:% +\\{halfword})$;\6 +\4\&{label} \37$\\{found},\39\\{exit}$;\6 +\4\&{var} \37\|k: \37$0\to\\{path\_size}$;\C{current knot number}\6 +$\|r,\39\|s,\39\|t$: \37\\{pointer};\C{registers for list traversal}\6 +\X286:Other local variables for \\{solve\_choices}\X\2\6 +\&{begin} \37$\|k\K0$;\5 +$\|s\K\|p$;\6 +\~ \1\&{loop}\ \&{begin} \37$\|t\K\\{link}(\|s)$;\6 +\&{if} $\|k=0$ \1\&{then}\5 +\X285:Get the linear equations started; or \&{return} with the control points +in place, if linear equations needn't be solved\X\6 +\4\&{else} \&{case} $\\{left\_type}(\|s)$ \1\&{of}\6 +\4$\\{end\_cycle},\39\\{open}$: \37\X287:Set up equation to match mock +curvatures at $z_k$; then \&{goto} \\{found} with $\theta_n$ adjusted to equal +$\theta_0$, if a cycle has ended\X;\6 +\4\\{curl}: \37\X295:Set up equation for a curl at $\theta_n$ and \&{goto} % +\\{found}\X;\6 +\4\\{given}: \37\X292:Calculate the given value of $\theta_n$ and \&{goto} % +\\{found}\X;\2\6 +\&{end};\C{there are no other cases}\2\6 +$\|r\K\|s$;\5 +$\|s\K\|t$;\5 +$\\{incr}(\|k)$;\6 +\&{end};\2\6 +\4\\{found}: \37\X297:Finish choosing angles and assigning control points\X;\6 +\4\\{exit}: \37\&{end};\par +\U269.\fi + +\M285. On the first time through the loop, we have $\|k=0$ and \|r is not yet +defined. The first linear equation, if any, will have $A_0=B_0=0$. + +\Y\P$\4\X285:Get the linear equations started; or \&{return} with the control +points in place, if linear equations needn't be solved\X\S$\6 +\&{case} $\\{right\_type}(\|s)$ \1\&{of}\6 +\4\\{given}: \37\&{if} $\\{left\_type}(\|t)=\\{given}$ \1\&{then}\5 +\X301:Reduce to simple case of two givens and \&{return}\X\6 +\4\&{else} \X293:Set up the equation for a given value of $\theta_0$\X;\2\6 +\4\\{curl}: \37\&{if} $\\{left\_type}(\|t)=\\{curl}$ \1\&{then}\5 +\X302:Reduce to simple case of straight line and \&{return}\X\6 +\4\&{else} \X294:Set up the equation for a curl at $\theta_0$\X;\2\6 +\4\\{open}: \37\&{begin} \37$\\{uu}[0]\K0$;\5 +$\\{vv}[0]\K0$;\5 +$\\{ww}[0]\K\\{fraction\_one}$;\6 +\&{end};\C{this begins a cycle}\2\6 +\&{end}\C{there are no other cases}\par +\U284.\fi + +\M286. The general equation that specifies equality of mock curvature at $z_k$ +is +$$A_k\theta_{k-1}+(B_k+C_k)\theta_k+D_k\theta\k=-B_k\psi_k-D_k\psi\k,$$ +as derived above. We want to combine this with the already-derived equation +$\theta_{k-1}+u_{k-1}\theta_k=v_{k-1}+w_{k-1}\theta_0$ in order to obtain +a new equation +$\theta_k+u_k\theta\k=v_k+w_k\theta_0$. This can be done by dividing the +equation +$$(B_k-u_{k-1}A_k+C_k)\theta_k+D_k\theta\k=-B_k\psi_k-D_k\psi\k-A_kv_{k-1} +-A_kw_{k-1}\theta_0$$ +by $B_k-u_{k-1}A_k+C_k$. The trick is to do this carefully with +fixed-point arithmetic, avoiding the chance of overflow while retaining +suitable precision. + +The calculations will be performed in several registers that +provide temporary storage for intermediate quantities. + +\Y\P$\4\X286:Other local variables for \\{solve\_choices}\X\S$\6 +\4$\\{aa},\39\\{bb},\39\\{cc},\39\\{ff},\39\\{acc}$: \37\\{fraction};% +\C{temporary registers}\6 +\4$\\{dd},\39\\{ee}$: \37\\{scaled};\C{likewise, but \\{scaled}}\6 +\4$\\{lt},\39\\{rt}$: \37\\{scaled};\C{tension values}\par +\U284.\fi + +\M287. \P$\X287:Set up equation to match mock curvatures at $z_k$; then % +\&{goto} \\{found} with $\theta_n$ adjusted to equal $\theta_0$, if a cycle has +ended\X\S$\6 +\&{begin} \37\X288:Calculate the values $\\{aa}=A_k/B_k$, $\\{bb}=D_k/C_k$, $% +\\{dd}=(3-\alpha_{k-1})d_{k,k+1}$, $\\{ee}=(3-\beta\k)d_{k-1,k}$, and $% +\\{cc}=(B_k-u_{k-1}A_k)/B_k$\X;\6 +\X289:Calculate the ratio $\\{ff}=C_k/(C_k+B_k-u_{k-1}A_k)$\X;\6 +$\\{uu}[\|k]\K\\{take\_fraction}(\\{ff},\39\\{bb})$;\5 +\X290:Calculate the values of $v_k$ and $w_k$\X;\6 +\&{if} $\\{left\_type}(\|s)=\\{end\_cycle}$ \1\&{then}\5 +\X291:Adjust $\theta_n$ to equal $\theta_0$ and \&{goto} \\{found}\X;\2\6 +\&{end}\par +\U284.\fi + +\M288. Since tension values are never less than 3/4, the values \\{aa} and +\\{bb} computed here are never more than 4/5. + +\Y\P$\4\X288:Calculate the values $\\{aa}=A_k/B_k$, $\\{bb}=D_k/C_k$, $% +\\{dd}=(3-\alpha_{k-1})d_{k,k+1}$, $\\{ee}=(3-\beta\k)d_{k-1,k}$, and $% +\\{cc}=(B_k-u_{k-1}A_k)/B_k$\X\S$\6 +\&{if} $\\{abs}(\\{right\_tension}(\|r))=\\{unity}$ \1\&{then}\6 +\&{begin} \37$\\{aa}\K\\{fraction\_half}$;\5 +$\\{dd}\K2\ast\\{delta}[\|k]$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{aa}\K\\{make\_fraction}(\\{unity},\393\ast\\{abs}(% +\\{right\_tension}(\|r))-\\{unity})$;\5 +$\\{dd}\K\\{take\_fraction}(\\{delta}[\|k],\39\\{fraction\_three}-\\{make% +\_fraction}(\\{unity},\39\\{abs}(\\{right\_tension}(\|r))))$;\6 +\&{end};\2\6 +\&{if} $\\{abs}(\\{left\_tension}(\|t))=\\{unity}$ \1\&{then}\6 +\&{begin} \37$\\{bb}\K\\{fraction\_half}$;\5 +$\\{ee}\K2\ast\\{delta}[\|k-1]$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{bb}\K\\{make\_fraction}(\\{unity},\393\ast\\{abs}(% +\\{left\_tension}(\|t))-\\{unity})$;\5 +$\\{ee}\K\\{take\_fraction}(\\{delta}[\|k-1],\39\\{fraction\_three}-\\{make% +\_fraction}(\\{unity},\39\\{abs}(\\{left\_tension}(\|t))))$;\6 +\&{end};\2\6 +$\\{cc}\K\\{fraction\_one}-\\{take\_fraction}(\\{uu}[\|k-1],\39\\{aa})$\par +\U287.\fi + +\M289. The ratio to be calculated in this step can be written in the form +$$\beta_k^2\cdot\\{ee}\over\beta_k^2\cdot\\{ee}+\alpha_k^2\cdot +\\{cc}\cdot\\{dd},$$ +because of the quantities just calculated. The values of \\{dd} and \\{ee} +will not be needed after this step has been performed. + +\Y\P$\4\X289:Calculate the ratio $\\{ff}=C_k/(C_k+B_k-u_{k-1}A_k)$\X\S$\6 +$\\{dd}\K\\{take\_fraction}(\\{dd},\39\\{cc})$;\5 +$\\{lt}\K\\{abs}(\\{left\_tension}(\|s))$;\5 +$\\{rt}\K\\{abs}(\\{right\_tension}(\|s))$;\6 +\&{if} $\\{lt}\I\\{rt}$ \1\&{then}\C{$\beta_k^{-1}\ne\alpha_k^{-1}$}\6 +\&{if} $\\{lt}<\\{rt}$ \1\&{then}\6 +\&{begin} \37$\\{ff}\K\\{make\_fraction}(\\{lt},\39\\{rt})$;\5 +$\\{ff}\K\\{take\_fraction}(\\{ff},\39\\{ff})$;\C{$\alpha_k^2/\beta_k^2$}\6 +$\\{dd}\K\\{take\_fraction}(\\{dd},\39\\{ff})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{ff}\K\\{make\_fraction}(\\{rt},\39\\{lt})$;\5 +$\\{ff}\K\\{take\_fraction}(\\{ff},\39\\{ff})$;\C{$\beta_k^2/\alpha_k^2$}\6 +$\\{ee}\K\\{take\_fraction}(\\{ee},\39\\{ff})$;\6 +\&{end};\2\2\6 +$\\{ff}\K\\{make\_fraction}(\\{ee},\39\\{ee}+\\{dd})$\par +\U287.\fi + +\M290. The value of $u_{k-1}$ will be $\L1$ except when $k=1$ and the previous +equation was specified by a curl. In that case we must use a special +method of computation to prevent overflow. + +Fortunately, the calculations turn out to be even simpler in this ``hard'' +case. The curl equation makes $w_0=0$ and $v_0=-u_0\psi_1$, hence +$-B_1\psi_1-A_1v_0=-(B_1-u_0A_1)\psi_1=-\\{cc}\cdot B_1\psi_1$. + +\Y\P$\4\X290:Calculate the values of $v_k$ and $w_k$\X\S$\6 +$\\{acc}\K-\\{take\_fraction}(\\{psi}[\|k+1],\39\\{uu}[\|k])$;\6 +\&{if} $\\{right\_type}(\|r)=\\{curl}$ \1\&{then}\6 +\&{begin} \37$\\{ww}[\|k]\K0$;\5 +$\\{vv}[\|k]\K\\{acc}-\\{take\_fraction}(\\{psi}[1],\39\\{fraction\_one}-% +\\{ff})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{ff}\K\\{make\_fraction}(\\{fraction\_one}-\\{ff},% +\39\\{cc})$;\C{this is $B_k/(C_k+B_k-u_{k-1}A_k)<5$}\6 +$\\{acc}\K\\{acc}-\\{take\_fraction}(\\{psi}[\|k],\39\\{ff})$;\5 +$\\{ff}\K\\{take\_fraction}(\\{ff},\39\\{aa})$;\C{this is +$A_k/(C_k+B_k-u_{k-1}A_k)$}\6 +$\\{vv}[\|k]\K\\{acc}-\\{take\_fraction}(\\{vv}[\|k-1],\39\\{ff})$;\6 +\&{if} $\\{ww}[\|k-1]=0$ \1\&{then}\5 +$\\{ww}[\|k]\K0$\6 +\4\&{else} $\\{ww}[\|k]\K-\\{take\_fraction}(\\{ww}[\|k-1],\39\\{ff})$;\2\6 +\&{end}\2\par +\U287.\fi + +\M291. When a complete cycle has been traversed, we have $\theta_k+u_k\theta\k= +v_k+w_k\theta_0$, for $1\L\|k\L\|n$. We would like to determine the value of +$\theta_n$ and reduce the system to the form $\theta_k+u_k\theta\k=v_k$ +for $0\L\|k<\|n$, so that the cyclic case can be finished up just as if there +were no cycle. + +The idea in the following code is to observe that +$$\eqalign{\theta_n&=v_n+w_n\theta_0-u_n\theta_1=\cdots\cr +&=v_n+w_n\theta_0-u_n\bigl(v_1+w_1\theta_0-u_1(v_2+\cdots +-u_{n-2}(v_{n-1}+w_{n-1}\theta_0-u_{n-1}\theta_0)\ldots{})\bigr),\cr}$$ +so we can solve for $\theta_n=\theta_0$. + +\Y\P$\4\X291:Adjust $\theta_n$ to equal $\theta_0$ and \&{goto} \\{found}\X\S$\6 +\&{begin} \37$\\{aa}\K0$;\5 +$\\{bb}\K\\{fraction\_one}$;\C{we have $\|k=\|n$}\6 +\1\&{repeat} \37$\\{decr}(\|k)$;\6 +\&{if} $\|k=0$ \1\&{then}\5 +$\|k\K\|n$;\2\6 +$\\{aa}\K\\{vv}[\|k]-\\{take\_fraction}(\\{aa},\39\\{uu}[\|k])$;\5 +$\\{bb}\K\\{ww}[\|k]-\\{take\_fraction}(\\{bb},\39\\{uu}[\|k])$;\6 +\4\&{until}\5 +$\|k=\|n$;\C{now $\theta_n=\\{aa}+\\{bb}\cdot\theta_n$}\2\6 +$\\{aa}\K\\{make\_fraction}(\\{aa},\39\\{fraction\_one}-\\{bb})$;\5 +$\\{theta}[\|n]\K\\{aa}$;\5 +$\\{vv}[0]\K\\{aa}$;\6 +\&{for} $\|k\K1\mathrel{\&{to}}\|n-1$ \1\&{do}\5 +$\\{vv}[\|k]\K\\{vv}[\|k]+\\{take\_fraction}(\\{aa},\39\\{ww}[\|k])$;\2\6 +\&{goto} \37\\{found};\6 +\&{end}\par +\U287.\fi + +\M292. \P\D \37$\\{reduce\_angle}(\#)\S$\1\6 +\&{if} $\\{abs}(\#)>\\{one\_eighty\_deg}$ \1\&{then}\6 +\&{if} $\#>0$ \1\&{then}\5 +$\#\K\#-\\{three\_sixty\_deg}$\ \&{else} $\#\K\#+\\{three\_sixty\_deg}$\2\2\2% +\par +\Y\P$\4\X292:Calculate the given value of $\theta_n$ and \&{goto} \\{found}\X% +\S$\6 +\&{begin} \37$\\{theta}[\|n]\K\\{left\_given}(\|s)-\\{n\_arg}(\\{delta\_x}[% +\|n-1],\39\\{delta\_y}[\|n-1])$;\5 +$\\{reduce\_angle}(\\{theta}[\|n])$;\5 +\&{goto} \37\\{found};\6 +\&{end}\par +\U284.\fi + +\M293. \P$\X293:Set up the equation for a given value of $\theta_0$\X\S$\6 +\&{begin} \37$\\{vv}[0]\K\\{right\_given}(\|s)-\\{n\_arg}(\\{delta\_x}[0],\39% +\\{delta\_y}[0])$;\5 +$\\{reduce\_angle}(\\{vv}[0])$;\5 +$\\{uu}[0]\K0$;\5 +$\\{ww}[0]\K0$;\6 +\&{end}\par +\U285.\fi + +\M294. \P$\X294:Set up the equation for a curl at $\theta_0$\X\S$\6 +\&{begin} \37$\\{cc}\K\\{right\_curl}(\|s)$;\5 +$\\{lt}\K\\{abs}(\\{left\_tension}(\|t))$;\5 +$\\{rt}\K\\{abs}(\\{right\_tension}(\|s))$;\6 +\&{if} $(\\{rt}=\\{unity})\W(\\{lt}=\\{unity})$ \1\&{then}\5 +$\\{uu}[0]\K\\{make\_fraction}(\\{cc}+\\{cc}+\\{unity},\39\\{cc}+\\{two})$\6 +\4\&{else} $\\{uu}[0]\K\\{curl\_ratio}(\\{cc},\39\\{rt},\39\\{lt})$;\2\6 +$\\{vv}[0]\K-\\{take\_fraction}(\\{psi}[1],\39\\{uu}[0])$;\5 +$\\{ww}[0]\K0$;\6 +\&{end}\par +\U285.\fi + +\M295. \P$\X295:Set up equation for a curl at $\theta_n$ and \&{goto} \\{found}% +\X\S$\6 +\&{begin} \37$\\{cc}\K\\{left\_curl}(\|s)$;\5 +$\\{lt}\K\\{abs}(\\{left\_tension}(\|s))$;\5 +$\\{rt}\K\\{abs}(\\{right\_tension}(\|r))$;\6 +\&{if} $(\\{rt}=\\{unity})\W(\\{lt}=\\{unity})$ \1\&{then}\5 +$\\{ff}\K\\{make\_fraction}(\\{cc}+\\{cc}+\\{unity},\39\\{cc}+\\{two})$\6 +\4\&{else} $\\{ff}\K\\{curl\_ratio}(\\{cc},\39\\{lt},\39\\{rt})$;\2\6 +$\\{theta}[\|n]\K-\\{make\_fraction}(\\{take\_fraction}(\\{vv}[\|n-1],\39% +\\{ff}),\39\\{fraction\_one}-\\{take\_fraction}(\\{ff},\39\\{uu}[\|n-1]))$;\5 +\&{goto} \37\\{found};\6 +\&{end}\par +\U284.\fi + +\M296. The \\{curl\_ratio} subroutine has three arguments, which our previous +notation +encourages us to call $\gamma$, $\alpha^{-1}$, and $\beta^{-1}$. It is +a somewhat tedious program to calculate +$${(3-\alpha)\alpha^2\gamma+\beta^3\over +\alpha^3\gamma+(3-\beta)\beta^2},$$ +with the result reduced to 4 if it exceeds 4. (This reduction of curl +is necessary only if the curl and tension are both large.) +The values of $\alpha$ and $\beta$ will be at most~4/3. + +\Y\P$\4\X296:Declare subroutines needed by \\{solve\_choices}\X\S$\6 +\4\&{function}\1\ \37$\\{curl\_ratio}(\\{gamma},\39\\{a\_tension},\39\\{b% +\_tension}:\\{scaled})$: \37\\{fraction};\6 +\4\&{var} \37$\\{alpha},\39\\{beta},\39\\{num},\39\\{denom},\39\\{ff}$: \37% +\\{fraction};\C{registers}\2\6 +\&{begin} \37$\\{alpha}\K\\{make\_fraction}(\\{unity},\39\\{a\_tension})$;\5 +$\\{beta}\K\\{make\_fraction}(\\{unity},\39\\{b\_tension})$;\6 +\&{if} $\\{alpha}\L\\{beta}$ \1\&{then}\6 +\&{begin} \37$\\{ff}\K\\{make\_fraction}(\\{alpha},\39\\{beta})$;\5 +$\\{ff}\K\\{take\_fraction}(\\{ff},\39\\{ff})$;\5 +$\\{gamma}\K\\{take\_fraction}(\\{gamma},\39\\{ff})$;\6 +$\\{beta}\K\\{beta}\mathbin{\&{div}}\O{10000}$;\C{convert \\{fraction} to % +\\{scaled}}\6 +$\\{denom}\K\\{take\_fraction}(\\{gamma},\39\\{alpha})+\\{three}-\\{beta}$;\5 +$\\{num}\K\\{take\_fraction}(\\{gamma},\39\\{fraction\_three}-\\{alpha})+% +\\{beta}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{ff}\K\\{make\_fraction}(\\{beta},\39\\{alpha})$;\5 +$\\{ff}\K\\{take\_fraction}(\\{ff},\39\\{ff})$;\5 +$\\{beta}\K\\{take\_fraction}(\\{beta},\39\\{ff})\mathbin{\&{div}}\O{10000}$;% +\C{convert \\{fraction} to \\{scaled}}\6 +$\\{denom}\K\\{take\_fraction}(\\{gamma},\39\\{alpha})+(\\{ff}\mathbin{% +\&{div}}1365)-\\{beta}$;\C{$1365\approx 2^{12}/3$}\6 +$\\{num}\K\\{take\_fraction}(\\{gamma},\39\\{fraction\_three}-\\{alpha})+% +\\{beta}$;\6 +\&{end};\2\6 +\&{if} $\\{num}\G\\{denom}+\\{denom}+\\{denom}+\\{denom}$ \1\&{then}\5 +$\\{curl\_ratio}\K\\{fraction\_four}$\6 +\4\&{else} $\\{curl\_ratio}\K\\{make\_fraction}(\\{num},\39\\{denom})$;\2\6 +\&{end};\par +\A299. +\U284.\fi + +\M297. We're in the home stretch now. + +\Y\P$\4\X297:Finish choosing angles and assigning control points\X\S$\6 +\&{for} $\|k\K\|n-1\mathrel{\&{downto}}0$ \1\&{do}\5 +$\\{theta}[\|k]\K\\{vv}[\|k]-\\{take\_fraction}(\\{theta}[\|k+1],\39\\{uu}[% +\|k])$;\2\6 +$\|s\K\|p$;\5 +$\|k\K0$;\6 +\1\&{repeat} \37$\|t\K\\{link}(\|s)$;\6 +$\\{n\_sin\_cos}(\\{theta}[\|k])$;\5 +$\\{st}\K\\{n\_sin}$;\5 +$\\{ct}\K\\{n\_cos}$;\6 +$\\{n\_sin\_cos}(-\\{psi}[\|k+1]-\\{theta}[\|k+1])$;\5 +$\\{sf}\K\\{n\_sin}$;\5 +$\\{cf}\K\\{n\_cos}$;\6 +$\\{set\_controls}(\|s,\39\|t,\39\|k)$;\6 +$\\{incr}(\|k)$;\5 +$\|s\K\|t$;\6 +\4\&{until}\5 +$\|k=\|n$\2\par +\U284.\fi + +\M298. The \\{set\_controls} routine actually puts the control points into +a pair of consecutive nodes \|p and~\|q. Global variables are used to +record the values of $\sin\theta$, $\cos\theta$, $\sin\phi$, and +$\cos\phi$ needed in this calculation. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4$\\{st},\39\\{ct},\39\\{sf},\39\\{cf}$: \37\\{fraction};\C{sines and cosines}% +\par +\fi + +\M299. \P$\X296:Declare subroutines needed by \\{solve\_choices}\X\mathrel{+}% +\S$\6 +\4\&{procedure}\1\ \37$\\{set\_controls}(\|p,\39\|q:\\{pointer};\,\35\|k:% +\\{integer})$;\6 +\4\&{var} \37$\\{rr},\39\\{ss}$: \37\\{fraction};\C{velocities, divided by +thrice the tension}\6 +$\\{lt},\39\\{rt}$: \37\\{scaled};\C{tensions}\6 +\\{sine}: \37\\{fraction};\C{$\sin(\theta+\phi)$}\2\6 +\&{begin} \37$\\{lt}\K\\{abs}(\\{left\_tension}(\|q))$;\5 +$\\{rt}\K\\{abs}(\\{right\_tension}(\|p))$;\5 +$\\{rr}\K\\{velocity}(\\{st},\39\\{ct},\39\\{sf},\39\\{cf},\39\\{rt})$;\5 +$\\{ss}\K\\{velocity}(\\{sf},\39\\{cf},\39\\{st},\39\\{ct},\39\\{lt})$;\6 +\&{if} $(\\{right\_tension}(\|p)<0)\V(\\{left\_tension}(\|q)<0)$ \1\&{then}\5 +\X300:Decrease the velocities, if necessary, to stay inside the bounding +triangle\X;\2\6 +$\\{right\_x}(\|p)\K\\{x\_coord}(\|p)+\\{take\_fraction}(\\{take\_fraction}(% +\\{delta\_x}[\|k],\39\\{ct})-\\{take\_fraction}(\\{delta\_y}[\|k],\39\\{st}),% +\39\\{rr})$;\5 +$\\{right\_y}(\|p)\K\\{y\_coord}(\|p)+\\{take\_fraction}(\\{take\_fraction}(% +\\{delta\_y}[\|k],\39\\{ct})+\\{take\_fraction}(\\{delta\_x}[\|k],\39\\{st}),% +\39\\{rr})$;\5 +$\\{left\_x}(\|q)\K\\{x\_coord}(\|q)-\\{take\_fraction}(\\{take\_fraction}(% +\\{delta\_x}[\|k],\39\\{cf})+\\{take\_fraction}(\\{delta\_y}[\|k],\39\\{sf}),% +\39\\{ss})$;\5 +$\\{left\_y}(\|q)\K\\{y\_coord}(\|q)-\\{take\_fraction}(\\{take\_fraction}(% +\\{delta\_y}[\|k],\39\\{cf})-\\{take\_fraction}(\\{delta\_x}[\|k],\39\\{sf}),% +\39\\{ss})$;\5 +$\\{right\_type}(\|p)\K\\{explicit}$;\5 +$\\{left\_type}(\|q)\K\\{explicit}$;\6 +\&{end};\par +\fi + +\M300. The boundedness conditions $\\{rr}\L\sin\phi\,/\sin(\theta+\phi)$ and +$\\{ss}\L\sin\theta\,/\sin(\theta+\phi)$ are to be enforced if $\sin\theta$, +$\sin\phi$, and $\sin(\theta+\phi)$ all have the same sign. Otherwise +there is no ``bounding triangle.'' + +\Y\P$\4\X300:Decrease the velocities, if necessary, to stay inside the bounding +triangle\X\S$\6 +\&{if} $((\\{st}\G0)\W(\\{sf}\G0))\V((\\{st}\L0)\W(\\{sf}\L0))$ \1\&{then}\6 +\&{begin} \37$\\{sine}\K\\{take\_fraction}(\\{abs}(\\{st}),\39\\{cf})+\\{take% +\_fraction}(\\{abs}(\\{sf}),\39\\{ct})$;\6 +\&{if} $\\{sine}>0$ \1\&{then}\6 +\&{begin} \37$\\{sine}\K\\{take\_fraction}(\\{sine},\39\\{fraction\_one}+% +\\{unity})$;\C{safety factor}\6 +\&{if} $\\{right\_tension}(\|p)<0$ \1\&{then}\6 +\&{if} $\\{ab\_vs\_cd}(\\{abs}(\\{sf}),\39\\{fraction\_one},\39\\{rr},\39% +\\{sine})<0$ \1\&{then}\5 +$\\{rr}\K\\{make\_fraction}(\\{abs}(\\{sf}),\39\\{sine})$;\2\2\6 +\&{if} $\\{left\_tension}(\|q)<0$ \1\&{then}\6 +\&{if} $\\{ab\_vs\_cd}(\\{abs}(\\{st}),\39\\{fraction\_one},\39\\{ss},\39% +\\{sine})<0$ \1\&{then}\5 +$\\{ss}\K\\{make\_fraction}(\\{abs}(\\{st}),\39\\{sine})$;\2\2\6 +\&{end};\2\6 +\&{end}\2\par +\U299.\fi + +\M301. Only the simple cases remain to be handled. + +\Y\P$\4\X301:Reduce to simple case of two givens and \&{return}\X\S$\6 +\&{begin} \37$\\{aa}\K\\{n\_arg}(\\{delta\_x}[0],\39\\{delta\_y}[0])$;\6 +$\\{n\_sin\_cos}(\\{right\_given}(\|p)-\\{aa})$;\5 +$\\{ct}\K\\{n\_cos}$;\5 +$\\{st}\K\\{n\_sin}$;\6 +$\\{n\_sin\_cos}(\\{left\_given}(\|q)-\\{aa})$;\5 +$\\{cf}\K\\{n\_cos}$;\5 +$\\{sf}\K-\\{n\_sin}$;\6 +$\\{set\_controls}(\|p,\39\|q,\390)$;\5 +\&{return};\6 +\&{end}\par +\U285.\fi + +\M302. \P$\X302:Reduce to simple case of straight line and \&{return}\X\S$\6 +\&{begin} \37$\\{right\_type}(\|p)\K\\{explicit}$;\5 +$\\{left\_type}(\|q)\K\\{explicit}$;\5 +$\\{lt}\K\\{abs}(\\{left\_tension}(\|q))$;\5 +$\\{rt}\K\\{abs}(\\{right\_tension}(\|p))$;\6 +\&{if} $\\{rt}=\\{unity}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{delta\_x}[0]\G0$ \1\&{then}\5 +$\\{right\_x}(\|p)\K\\{x\_coord}(\|p)+((\\{delta\_x}[0]+1)\mathbin{\&{div}}3)$\6 +\4\&{else} $\\{right\_x}(\|p)\K\\{x\_coord}(\|p)+((\\{delta\_x}[0]-1)\mathbin{% +\&{div}}3)$;\2\6 +\&{if} $\\{delta\_y}[0]\G0$ \1\&{then}\5 +$\\{right\_y}(\|p)\K\\{y\_coord}(\|p)+((\\{delta\_y}[0]+1)\mathbin{\&{div}}3)$\6 +\4\&{else} $\\{right\_y}(\|p)\K\\{y\_coord}(\|p)+((\\{delta\_y}[0]-1)\mathbin{% +\&{div}}3)$;\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{ff}\K\\{make\_fraction}(\\{unity},\393\ast\\{rt})$;% +\C{$\alpha/3$}\6 +$\\{right\_x}(\|p)\K\\{x\_coord}(\|p)+\\{take\_fraction}(\\{delta\_x}[0],\39% +\\{ff})$;\5 +$\\{right\_y}(\|p)\K\\{y\_coord}(\|p)+\\{take\_fraction}(\\{delta\_y}[0],\39% +\\{ff})$;\6 +\&{end};\2\6 +\&{if} $\\{lt}=\\{unity}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{delta\_x}[0]\G0$ \1\&{then}\5 +$\\{left\_x}(\|q)\K\\{x\_coord}(\|q)-((\\{delta\_x}[0]+1)\mathbin{\&{div}}3)$\6 +\4\&{else} $\\{left\_x}(\|q)\K\\{x\_coord}(\|q)-((\\{delta\_x}[0]-1)\mathbin{% +\&{div}}3)$;\2\6 +\&{if} $\\{delta\_y}[0]\G0$ \1\&{then}\5 +$\\{left\_y}(\|q)\K\\{y\_coord}(\|q)-((\\{delta\_y}[0]+1)\mathbin{\&{div}}3)$\6 +\4\&{else} $\\{left\_y}(\|q)\K\\{y\_coord}(\|q)-((\\{delta\_y}[0]-1)\mathbin{% +\&{div}}3)$;\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{ff}\K\\{make\_fraction}(\\{unity},\393\ast\\{lt})$;% +\C{$\beta/3$}\6 +$\\{left\_x}(\|q)\K\\{x\_coord}(\|q)-\\{take\_fraction}(\\{delta\_x}[0],\39% +\\{ff})$;\5 +$\\{left\_y}(\|q)\K\\{y\_coord}(\|q)-\\{take\_fraction}(\\{delta\_y}[0],\39% +\\{ff})$;\6 +\&{end};\2\6 +\&{return};\6 +\&{end}\par +\U285.\fi + +\N303. \[19] Generating discrete moves. +The purpose of the next part of \MF\ is to compute discrete approximations +to curves described as parametric polynomial functions $z(t)$. +We shall start with the low level first, because an efficient ``engine'' +is needed to support the high-level constructions. + +Most of the subroutines are based on variations of a single theme, +namely the idea of {\sl bisection}. Given a Bernshte{\u\i}n polynomial +$$B(z_0,z_1,\ldots,z_n;t)=\sum_k{n\choose k}t^k(1-t)^{n-k}z_k,$$ +we can conveniently bisect its range as follows: + +\smallskip +\textindent{1)} Let $z_k^{(0)}=z_k$, for $0\L\|k\L\|n$. + +\smallskip +\textindent{2)} Let $z_k^{(j+1)}={1\over2}(z_k^{(j)}+z\k^{(j)})$, for +$0\L\|k<\|n-\|j$, for $0\L\|j<\|n$. + +\smallskip\noindent +Then +$$B(z_0,z_1,\ldots,z_n;t)=B(z_0^{(0)},z_0^{(1)},\ldots,z_0^{(n)};2t) +=B(z_0^{(n)},z_1^{(n-1)},\ldots,z_n^{(0)};2t-1).$$ +This formula gives us the coefficients of polynomials to use over the ranges +$0\L t\L{1\over2}$ and ${1\over2}\L t\L1$. + +In our applications it will usually be possible to work indirectly with +numbers that allow us to deduce relevant properties of the polynomials +without actually computing the polynomial values. We will deal with +coefficients $Z_k=2^l(z_k-z_{k-1})$ for $1\L\|k\L\|n$, instead of +the actual numbers $z_0$, $z_1$, \dots,~$z_n$, and the value of~\|l will +increase by~1 at each bisection step. This technique reduces the +amount of calculation needed for bisection and also increases the +accuracy of evaluation (since one bit of precision is gained at each +bisection). Indeed, the bisection process now becomes one level shorter: + +\smallskip +\textindent{$1'$)} Let $Z_k^{(1)}=Z_k$, for $1\L\|k\L\|n$. + +\smallskip +\textindent{$2'$)} Let $Z_k^{(j+1)}={1\over2}(Z_k^{(j)}+Z\k^{(j)})$, for +$1\L\|k\L\|n-\|j$, for $1\L\|j<\|n$. + +\smallskip\noindent +The relevant coefficients $(Z'_1,\ldots,Z'_n)$ and $(Z''_1,\ldots,Z''_n)$ +for the two subintervals after bisection are respectively +$(Z_1^{(1)},Z_1^{(2)},\ldots,Z_1^{(n)})$ and +$(Z_1^{(n)},Z_2^{(n-1)},\ldots,Z_n^{(1)})$. +And the values of $z_0$ appropriate for the bisected interval are $z'_0=z_0$ +and $z''_0=z_0+(Z_1+Z_2+\cdots+Z_n)/2^{l+1}$. + +Step $2'$ involves division by~2, which introduces computational errors +of at most $1\over2$ at each step; thus after $l$~levels of bisection the +integers $Z_k$ will differ from their true values by at most $(n-1)l/2$. +This error rate is quite acceptable, considering that we have $l$~more +bits of precision in the $Z$'s by comparison with the~$z$'s. Note also +that the $Z$'s remain bounded; there's no danger of integer overflow, even +though we have the identity $Z_k=2^l(z_k-z_{k-1})$ for arbitrarily large~$l$. + +In fact, we can show not only that the $Z$'s remain bounded, but also that +they become nearly equal, since they are control points for a polynomial +of one less degree. If $\vert Z\k-Z_k\vert\L M$ initially, it is possible +to prove that $\vert Z\k-Z_k\vert\L\lceil M/2^l\rceil$ after $l$~levels +of bisection, even in the presence of rounding errors. Here's the +proof [cf.~Lane and Riesenfeld, {\sl IEEE Trans.\ on Pattern Analysis +and Machine Intelligence\/ \bf PAMI-2} (1980), 35--46]: Assuming that +$\vert Z\k-Z_k\vert\L M$ before bisection, we want to prove that +$\vert Z\k-Z_k\vert\L\lceil M/2\rceil$ afterward. First we show that +$\vert Z\k^{(j)}-Z_k^{(j)}\vert\L M$ for all $j$ and~$k$, by induction +on~$j$; this follows from the fact that +$$\bigl\vert\\{half}(a+b)-\\{half}(b+c)\bigr\vert\L +\max\bigl(\vert a-b\vert,\vert b-c\vert\bigr)$$ +holds for both of the rounding rules $\\{half}(x)=\lfloor x/2\rfloor$ +and $\\{half}(x)={\rm sign}(x)\lfloor\vert x/2\vert\rfloor$. +(If $\vert a-b\vert$ and $\vert b-c\vert$ are equal, then +$a+b$ and $b+c$ are both even or both odd. The rounding errors either +cancel or round the numbers toward each other; hence +$$\eqalign{\bigl\vert\\{half}(a+b)-\\{half}(b+c)\bigr\vert +&\L\textstyle\bigl\vert{1\over2}(a+b)-{1\over2}(b+c)\bigr\vert\cr +&=\textstyle\bigl\vert{1\over2}(a-b)+{1\over2}(b-c)\bigr\vert +\L\max\bigl(\vert a-b\vert,\vert b-c\vert\bigr),\cr}$$ +as required. A simpler argument applies if $\vert a-b\vert$ and +$\vert b-c\vert$ are unequal.) Now it is easy to see that +$\vert Z_1^{(j+1)}-Z_1^{(j)}\vert\L\bigl\lfloor{1\over2} +\vert Z_2^{(j)}-Z_1^{(j)}\vert+{1\over2}\bigr\rfloor +\L\bigl\lfloor{1\over2}(M+1)\bigr\rfloor=\lceil M/2\rceil$. + +Another interesting fact about bisection is the identity +$$Z_1'+\cdots+Z_n'+Z_1''+\cdots+Z_n''=2(Z_1+\cdots+Z_n+E),$$ +where $E$ is the sum of the rounding errors in all of the halving +operations ($\vert E\vert\L n(n-1)/4$). + +\fi + +\M304. We will later reduce the problem of digitizing a complex cubic +$z(t)=B(z_0,z_1,z_2,z_3;t)$ to the following simpler problem: +Given two real cubics +$x(t)=B(x_0,x_1,x_2,x_3;t)$ +and $y(t)=B(y_0,y_1,y_2,y_3;t)$ that are monotone nondecreasing, +determine the set of integer points +$$P=\bigl\{\bigl(\lfloor x(t)\rfloor,\lfloor y(t)\rfloor\bigr) +\bigm\vert 0\L t\L 1\bigr\}.$$ +Well, the problem isn't actually quite so clean as this; when the path +goes very near an integer point $(a,b)$, computational errors may +make us think that $P$ contains $(a-1,b)$ while in reality it should +contain $(a,b-1)$. Furthermore, if the path goes {\sl exactly\/} +through the integer points $(a-1,b-1)$ and +$(a,b)$, we will want $P$ to contain one +of the two points $(a-1,b)$ or $(a,b-1)$, so that $P$ can be described +entirely by ``rook moves'' upwards or to the right; no diagonal +moves from $(a-1,b-1)$ to~$(a,b)$ will be allowed. + +Thus, the set $P$ we wish to compute will merely be an approximation +to the set described in the formula above. It will consist of +$\lfloor x(1)\rfloor-\lfloor x(0)\rfloor$ rightward moves and +$\lfloor y(1)\rfloor-\lfloor y(0)\rfloor$ upward moves, intermixed +in some order. Our job will be to figure out a suitable order. + +The following recursive strategy suggests itself, when we recall that +$x(0)=x_0$, $x(1)=x_3$, $y(0)=y_0$, and $y(1)=y_3$: + +\smallskip +If $\lfloor x_0\rfloor=\lfloor x_3\rfloor$ then take +$\lfloor y_3\rfloor-\lfloor y_0\rfloor$ steps up. + +Otherwise if $\lfloor y_0\rfloor=\lfloor y_3\rfloor$ then take +$\lfloor x_3\rfloor-\lfloor x_0\rfloor$ steps to the right. + +Otherwise bisect the current cubics and repeat the process on both halves. + +\yskip\noindent +This intuitively appealing formulation does not quite solve the problem, +because it may never terminate. For example, it's not hard to see that +no steps will {\sl ever\/} be taken if $(x_0,x_1,x_2,x_3)=(y_0,y_1,y_2,y_3)$! +However, we can surmount this difficulty with a bit of care; so let's +proceed to flesh out the algorithm as stated, before worrying about +such details. + +The bisect-and-double strategy discussed above suggests that we represent +$(x_0,x_1,x_2,x_3)$ by $(X_1,X_2,X_3)$, where $X_k=2^l(x_k-x_{k-1})$ +for some~$l$. Initially $l=16$, since the $x$'s are \\{scaled}. +In order to deal with other aspects of the algorithm we will want to +maintain also the quantities $m=\lfloor x_3\rfloor-\lfloor x_0\rfloor$ +and $R=2^l(x_0\bmod 1)$. Similarly, +$(y_0,y_1,y_2,y_3)$ will be represented by $(Y_1,Y_2,Y_3)$, +$n=\lfloor y_3\rfloor-\lfloor y_0\rfloor$, +and $S=2^l(y_0\bmod 1)$. The algorithm now takes the following form: + +\smallskip +If $m=0$ then take $n$ steps up. + +Otherwise if $n=0$ then take $m$ steps to the right. + +Otherwise bisect the current cubics and repeat the process on both halves. + +\smallskip\noindent +The bisection process for $(X_1,X_2,X_3,m,R,l)$ reduces, in essence, +to the following formulas: +$$\vbox{\halign{$#\hfil$\cr +X_2'=\\{half}(X_1+X_2),\quad +X_2''=\\{half}(X_2+X_3),\quad +X_3'=\\{half}(X_2'+X_2''),\cr +X_1'=X_1,\quad +X_1''=X_3',\quad +X_3''=X_3,\cr +R'=2R,\quad +T=X_1'+X_2'+X_3'+R',\quad +R''=T\bmod 2^{l+1},\cr +m'=\lfloor T/2^{l+1}\rfloor,\quad +m''=m-m'.\cr}}$$ + +\fi + +\M305. When $m=n=1$, the computation can be speeded up because we simply +need to decide between two alternatives, (up,\thinspace right) +versus (right,\thinspace up). There appears to be no simple, direct +way to make the correct decision by looking at the values of +$(X_1,X_2,X_3,R)$ and +$(Y_1,Y_2,Y_3,S)$; but we can streamline the bisection process, and +we can use the fact that only one of the two descendants needs to +be examined after each bisection. Furthermore, we observed earlier +that after several levels of bisection the $X$'s and $Y$'s will be nearly +equal; so we will be justified in assuming that the curve is essentially a +straight line. (This, incidentally, solves the problem of infinite +recursion mentioned earlier.) + +It is possible to show that +$$m=\bigl\lfloor(X_1+X_2+X_3+R+E)\,/\,2^l\bigr\rfloor,$$ +where $E$ is an accumulated rounding error that is at most +$3\cdot(2^{l-16}-1)$ in absolute value. We will make sure that +the $X$'s are less than $2^{28}$; hence when $l=30$ we must +have $\|m\L1$. This proves that the special case $m=n=1$ is +bound to be reached by the time $l=30$. Furthermore $l=30$ is +a suitable time to make the straight line approximation, +if the recursion hasn't already died out, because the maximum +difference between $X$'s will then be $<2^{14}$; this corresponds +to an error of $<1$ with respect to the original scaling. +(Stating this another way, each bisection makes the curve two bits +closer to a straight line, hence 14 bisections are sufficient for +28-bit accuracy.) + +In the case of a straight line, the curve goes first right, then up, +if and only if $(T-2^l)(2^l-S)>(U-2^l)(2^l-R)$, where +$T=X_1+X_2+X_3+R$ and $U=Y_1+Y_2+Y_3+S$. For the actual curve +essentially runs from $(R/2^l,S/2^l)$ to $(T/2^l,U/2^l)$, and +we are testing whether or not $(1,1)$ is above the straight +line connecting these two points. (This formula assumes that $(1,1)$ +is not exactly on the line.) + +\fi + +\M306. We have glossed over the problem of tie-breaking in ambiguous +cases when the cubic curve passes exactly through integer points. +\MF\ finesses this problem by assuming that coordinates +$(x,y)$ actually stand for slightly perturbed values $(x+\xi,y+\eta)$, +where $\xi$ and~$\eta$ are infinitesimals whose signs will determine +what to do when $x$ and/or~$y$ are exact integers. The quantities +$\lfloor x\rfloor$ and~$\lfloor y\rfloor$ in the formulas above +should actually read $\lfloor x+\xi\rfloor$ and $\lfloor y+\eta\rfloor$. + +If $x$ is a \\{scaled} value, we have $\lfloor x+\xi\rfloor=\lfloor x\rfloor$ +if $\xi>0$, and $\lfloor x+\xi\rfloor=\lfloor x-2^{-16}\rfloor$ if +$\xi<0$. It is convenient to represent $\xi$ by the integer \\{xi\_corr}, +defined to be 0~if $\xi>0$ and 1~if $\xi<0$; then, for example, the +integer $\lfloor x+\xi\rfloor$ can be computed as +$\\{floor\_unscaled}(\|x-\\{xi\_corr})$. Similarly, $\eta$ is conveniently +represented by~\\{eta\_corr}. + +In our applications the sign of $\xi-\eta$ will always be the same as +the sign of $\xi$. Therefore it turns out that the rule for straight +lines, as stated above, should be modified as follows in the case of +ties: The line goes first right, then up, if and only if +$(T-2^l)(2^l-S)+\xi>(U-2^l)(2^l-R)$. And this relation holds iff +$\\{ab\_vs\_cd}(T-2^l,2^l-S,U-2^l,2^l-R)-\\{xi\_corr}\ge0$. + +These conventions for rounding are symmetrical, in the sense that the +digitized moves obtained from $(x_0,x_1,x_2,x_3,y_0,y_1,y_2,y_3,\xi,\eta)$ +will be exactly complementary to the moves that would be obtained from +$(-x_3,-x_2,-x_1,-x_0,-y_3,-y_2,-y_1,-y_0,-\xi,-\eta)$, if arithmetic +is exact. However, truncation errors in the bisection process might +upset the symmetry. We can restore much of the lost symmetry by adding +\\{xi\_corr} or \\{eta\_corr} when halving the data. + +\fi + +\M307. One further possibility needs to be mentioned: The algorithm +will be applied only to cubic polynomials $B(x_0,x_1,x_2,x_3;t)$ that +are nondecreasing as $t$~varies from 0 to~1; this condition turns +out to hold if and only if $x_0\L x_1$, $x_2\L x_3$, and either +$x_1\L x_2$ or $(x_1-x_2)^2\L(x_1-x_0)(x_3-x_2)$. If bisection were +carried out with perfect accuracy, these relations would remain +invariant. But rounding errors can creep in, hence the bisection +algorithm can produce non-monotonic subproblems from monotonic +initial conditions. This leads to the potential danger that $m$ or~$n$ +could become negative in the algorithm described above. + +For example, if we start with $(x_1-x_0,x_2-x_1,x_3-x_2)= +(X_1,X_2,X_3)=(7,-16,58)$, the corresponding polynomial is +monotonic, because $16^2<7\cdot39$. But the bisection algorithm +produces the left descendant $(7,-5,3)$, which is nonmonotonic; +its right descendant is~$(0,-1,3)$. + +\def\xt{{\tilde x}} +Fortunately we can prove that such rounding errors will never cause +the algorithm to make a tragic mistake. At every stage we are working +with numbers corresponding to a cubic polynomial $B(\xt_0, +\xt_1,\xt_2,\xt_3)$ that approximates some +monotonic polynomial $B(x_0,x_1,x_2,x_3)$. The accumulated errors are +controlled so that $\vert x_k-\xt_k\vert<\epsilon=3\cdot2^{-16}$. +If bisection is done at some stage of the recursion, we have +$m=\lfloor\xt_3\rfloor-\lfloor\xt_0\rfloor>0$, and the algorithm +computes a bisection value $\bar x$ such that $m'=\lfloor\bar x\rfloor- +\lfloor\xt_0\rfloor$ +and $m''=\lfloor\xt_3\rfloor-\lfloor\bar x\rfloor$. We want to prove +that neither $m'$ nor $m''$ can be negative. Since $\bar x$ is an +approximation to a value in the interval $[x_0,x_3]$, we have +$\bar x>x_0-\epsilon$ and $\bar x<x_3+\epsilon$, hence $\bar x> +\xt_0-2\epsilon$ and $\bar x<\xt_3+2\epsilon$. +If $m'$ is negative we must have $\xt_0\bmod 1<2\epsilon$; +if $m''$ is negative we must have $\xt_3\bmod 1>1-2\epsilon$. +In either case the condition $\lfloor\xt_3\rfloor-\lfloor\xt_0\rfloor>0$ +implies that $\xt_3-\xt_0>1-2\epsilon$, hence $x_3-x_0>1-4\epsilon$. +But it can be shown that if $B(x_0,x_1,x_2,x_3;t)$ is a monotonic +cubic, then $B(x_0,x_1,x_2,x_3;{1\over2})$ is always between +$.14[x_0,x_3]$ and $.86[x_0,x_3]$; and it is impossible for $\bar x$ +to be within~$\epsilon$ of such a number. Contradiction! +(The constant .14 is actually $(7-\sqrt{28}\,)/12$; the worst case +occurs for polynomials like $B(0,28-4\sqrt{28},14-5\sqrt{28},42;t)$.) + +\fi + +\M308. OK, now that a long theoretical preamble has justified the +bisection-and-doubling algorithm, we are ready to proceed with +its actual coding. But we still haven't discussed the +form of the output. + +For reasons to be discussed later, we shall find it convenient to +record the output as follows: Moving one step up is represented by +appending a `1' to a list; moving one step right is represented by +adding unity to the element at the end of the list. Thus, for example, +the net effect of ``(up, right, right, up, right)'' is to append +$(3,2)$. + +The list is kept in a global array called \\{move}. Before starting the +algorithm, \MF\ should check that $\\{move\_ptr}+\lfloor y_3\rfloor +-\lfloor y_0\rfloor\L\\{move\_size}$, so that the list won't exceed +the bounds of this array. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{move}: \37\&{array} $[0\to\\{move\_size}]$ \1\&{of}\5 +\\{integer};\C{the recorded moves}\2\6 +\4\\{move\_ptr}: \37$0\to\\{move\_size}$;\C{the number of items in the \\{move} +list}\par +\fi + +\M309. When bisection occurs, we ``push'' the subproblem corresponding +to the right-hand subinterval onto the \\{bisect\_stack} while +we continue to work on the left-hand subinterval. Thus, the \\{bisect\_stack} +will hold $(X_1,X_2,X_3,R,m,Y_1,Y_2,Y_3,S,n,l)$ values for +subproblems yet to be tackled. + +At most 15 subproblems will be on the stack at once (namely, for +$l=15$,~16, \dots,~29); but the stack is bigger than this, because +it is used also for more complicated bisection algorithms. + +\Y\P\D \37$\\{stack\_x1}\S\\{bisect\_stack}[\\{bisect\_ptr}]$\C{stacked value +of $X_1$}\par +\P\D \37$\\{stack\_x2}\S\\{bisect\_stack}[\\{bisect\_ptr}+1]$\C{stacked value +of $X_2$}\par +\P\D \37$\\{stack\_x3}\S\\{bisect\_stack}[\\{bisect\_ptr}+2]$\C{stacked value +of $X_3$}\par +\P\D \37$\\{stack\_r}\S\\{bisect\_stack}[\\{bisect\_ptr}+3]$\C{stacked value of +$R$}\par +\P\D \37$\\{stack\_m}\S\\{bisect\_stack}[\\{bisect\_ptr}+4]$\C{stacked value of +$m$}\par +\P\D \37$\\{stack\_y1}\S\\{bisect\_stack}[\\{bisect\_ptr}+5]$\C{stacked value +of $Y_1$}\par +\P\D \37$\\{stack\_y2}\S\\{bisect\_stack}[\\{bisect\_ptr}+6]$\C{stacked value +of $Y_2$}\par +\P\D \37$\\{stack\_y3}\S\\{bisect\_stack}[\\{bisect\_ptr}+7]$\C{stacked value +of $Y_3$}\par +\P\D \37$\\{stack\_s}\S\\{bisect\_stack}[\\{bisect\_ptr}+8]$\C{stacked value of +$S$}\par +\P\D \37$\\{stack\_n}\S\\{bisect\_stack}[\\{bisect\_ptr}+9]$\C{stacked value of +$n$}\par +\P\D \37$\\{stack\_l}\S\\{bisect\_stack}[\\{bisect\_ptr}+10]$\C{stacked value +of $l$}\par +\P\D \37$\\{move\_increment}=11$\C{number of items pushed by \\{make\_moves}}% +\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{bisect\_stack}: \37\&{array} $[0\to\\{bistack\_size}]$ \1\&{of}\5 +\\{integer};\2\6 +\4\\{bisect\_ptr}: \37$0\to\\{bistack\_size}$;\par +\fi + +\M310. \P$\X14:Check the ``constant'' values for consistency\X\mathrel{+}\S$\6 +\&{if} $15\ast\\{move\_increment}>\\{bistack\_size}$ \1\&{then}\5 +$\\{bad}\K31$;\2\par +\fi + +\M311. The \\{make\_moves} subroutine is given \\{scaled} values +$(x_0,x_1,x_2,x_3)$ +and $(y_0,y_1,y_2,y_3)$ that represent monotone-nondecreasing polynomials; +it makes $\lfloor x_3+\xi\rfloor-\lfloor x_0+\xi\rfloor$ rightward moves +and $\lfloor y_3+\eta\rfloor-\lfloor y_0+\eta\rfloor$ upward moves, as +explained earlier. (Here $\lfloor x+\xi\rfloor$ actually stands for +$\lfloor x/2^{16}-\\{xi\_corr}\rfloor$, if $x$ is regarded as an integer +without scaling.) The unscaled integers $x_k$ and~$y_k$ should be less +than $2^{28}$ in magnitude. + +It is assumed that $\\{move\_ptr} + \lfloor y_3+\eta\rfloor - +\lfloor y_0+\eta\rfloor < \\{move\_size}$ when this procedure is called, +so that the capacity of the \\{move} array will not be exceeded. + +The variables \|r and \|s in this procedure stand respectively for +$R-\\{xi\_corr}$ and $S-\\{eta\_corr}$ in the theory discussed above. + +\Y\P\4\&{procedure}\1\ \37$\\{make\_moves}(\\{xx0},\39\\{xx1},\39\\{xx2},\39% +\\{xx3},\39\\{yy0},\39\\{yy1},\39\\{yy2},\39\\{yy3}:\\{scaled};\,\35\\{xi% +\_corr},\39\\{eta\_corr}:\\{small\_number})$;\6 +\4\&{label} \37$\\{continue},\39\\{done},\39\\{exit}$;\6 +\4\&{var} \37$\\{x1},\39\\{x2},\39\\{x3},\39\|m,\39\|r,\39\\{y1},\39\\{y2},\39% +\\{y3},\39\|n,\39\|s,\39\|l$: \37\\{integer};\C{bisection variables explained +above}\6 +$\|q,\39\|t,\39\|u,\39\\{x2a},\39\\{x3a},\39\\{y2a},\39\\{y3a}$: \37% +\\{integer};\C{additional temporary registers}\2\6 +\&{begin} \37\&{if} $(\\{xx3}<\\{xx0})\V(\\{yy3}<\\{yy0})$ \1\&{then}\5 +$\\{confusion}(\.{"m"})$;\2\6 +$\|l\K16$;\5 +$\\{bisect\_ptr}\K0$;\6 +$\\{x1}\K\\{xx1}-\\{xx0}$;\5 +$\\{x2}\K\\{xx2}-\\{xx1}$;\5 +$\\{x3}\K\\{xx3}-\\{xx2}$;\6 +\&{if} $\\{xx0}\G\\{xi\_corr}$ \1\&{then}\5 +$\|r\K(\\{xx0}-\\{xi\_corr})\mathbin{\&{mod}}\\{unity}$\6 +\4\&{else} $\|r\K\\{unity}-1-((-\\{xx0}+\\{xi\_corr}-1)\mathbin{\&{mod}}% +\\{unity})$;\2\6 +$\|m\K(\\{xx3}-\\{xx0}+\|r)\mathbin{\&{div}}\\{unity}$;\6 +$\\{y1}\K\\{yy1}-\\{yy0}$;\5 +$\\{y2}\K\\{yy2}-\\{yy1}$;\5 +$\\{y3}\K\\{yy3}-\\{yy2}$;\6 +\&{if} $\\{yy0}\G\\{eta\_corr}$ \1\&{then}\5 +$\|s\K(\\{yy0}-\\{eta\_corr})\mathbin{\&{mod}}\\{unity}$\6 +\4\&{else} $\|s\K\\{unity}-1-((-\\{yy0}+\\{eta\_corr}-1)\mathbin{\&{mod}}% +\\{unity})$;\2\6 +$\|n\K(\\{yy3}-\\{yy0}+\|s)\mathbin{\&{div}}\\{unity}$;\6 +\&{if} $(\\{xx3}-\\{xx0}\G\\{fraction\_one})\V(\\{yy3}-\\{yy0}\G\\{fraction% +\_one})$ \1\&{then}\5 +\X313:Divide the variables by two, to avoid overflow problems\X;\2\6 +\~ \1\&{loop}\ \&{begin} \37\\{continue}: \37\X314:Make moves for current +subinterval; if bisection is necessary, push the second subinterval onto the +stack, and \&{goto} \\{continue} in order to handle the first subinterval\X;\6 +\&{if} $\\{bisect\_ptr}=0$ \1\&{then}\5 +\&{return};\2\6 +\X312:Remove a subproblem for \\{make\_moves} from the stack\X;\6 +\&{end};\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M312. \P$\X312:Remove a subproblem for \\{make\_moves} from the stack\X\S$\6 +$\\{bisect\_ptr}\K\\{bisect\_ptr}-\\{move\_increment}$;\6 +$\\{x1}\K\\{stack\_x1}$;\5 +$\\{x2}\K\\{stack\_x2}$;\5 +$\\{x3}\K\\{stack\_x3}$;\5 +$\|r\K\\{stack\_r}$;\5 +$\|m\K\\{stack\_m}$;\6 +$\\{y1}\K\\{stack\_y1}$;\5 +$\\{y2}\K\\{stack\_y2}$;\5 +$\\{y3}\K\\{stack\_y3}$;\5 +$\|s\K\\{stack\_s}$;\5 +$\|n\K\\{stack\_n}$;\6 +$\|l\K\\{stack\_l}$\par +\U311.\fi + +\M313. Our variables $(\\{x1},\\{x2},\\{x3})$ correspond to $(X_1,X_2,X_3)$ in +the notation +of the theory developed above. We need to keep them less than $2^{28}$ +in order to avoid integer overflow in weird circumstances. +For example, data like $x_0=-2^{28}+2^{16}-1$ and $x_1=x_2=x_3=2^{28}-1$ +would otherwise be problematical. Hence this part of the code is +needed, if only to thwart malicious users. + +\Y\P$\4\X313:Divide the variables by two, to avoid overflow problems\X\S$\6 +\&{begin} \37$\\{x1}\K\\{half}(\\{x1}+\\{xi\_corr})$;\5 +$\\{x2}\K\\{half}(\\{x2}+\\{xi\_corr})$;\5 +$\\{x3}\K\\{half}(\\{x3}+\\{xi\_corr})$;\5 +$\|r\K\\{half}(\|r+\\{xi\_corr})$;\6 +$\\{y1}\K\\{half}(\\{y1}+\\{eta\_corr})$;\5 +$\\{y2}\K\\{half}(\\{y2}+\\{eta\_corr})$;\5 +$\\{y3}\K\\{half}(\\{y3}+\\{eta\_corr})$;\5 +$\|s\K\\{half}(\|s+\\{eta\_corr})$;\6 +$\|l\K15$;\6 +\&{end}\par +\U311.\fi + +\M314. \P$\X314:Make moves for current subinterval; if bisection is necessary, +push the second subinterval onto the stack, and \&{goto} \\{continue} in order +to handle the first subinterval\X\S$\6 +\&{if} $\|m=0$ \1\&{then}\5 +\X315:Move upward \|n steps\X\6 +\4\&{else} \&{if} $\|n=0$ \1\&{then}\5 +\X316:Move to the right \|m steps\X\6 +\4\&{else} \&{if} $\|m+\|n=2$ \1\&{then}\5 +\X317:Make one move of each kind\X\6 +\4\&{else} \&{begin} \37$\\{incr}(\|l)$;\5 +$\\{stack\_l}\K\|l$;\6 +$\\{stack\_x3}\K\\{x3}$;\5 +$\\{stack\_x2}\K\\{half}(\\{x2}+\\{x3}+\\{xi\_corr})$;\5 +$\\{x2}\K\\{half}(\\{x1}+\\{x2}+\\{xi\_corr})$;\5 +$\\{x3}\K\\{half}(\\{x2}+\\{stack\_x2}+\\{xi\_corr})$;\5 +$\\{stack\_x1}\K\\{x3}$;\6 +$\|r\K\|r+\|r+\\{xi\_corr}$;\5 +$\|t\K\\{x1}+\\{x2}+\\{x3}+\|r$;\6 +$\|q\K\|t\mathbin{\&{div}}\\{two\_to\_the}[\|l]$;\5 +$\\{stack\_r}\K\|t\mathbin{\&{mod}}\\{two\_to\_the}[\|l]$;\6 +$\\{stack\_m}\K\|m-\|q$;\5 +$\|m\K\|q$;\6 +$\\{stack\_y3}\K\\{y3}$;\5 +$\\{stack\_y2}\K\\{half}(\\{y2}+\\{y3}+\\{eta\_corr})$;\5 +$\\{y2}\K\\{half}(\\{y1}+\\{y2}+\\{eta\_corr})$;\5 +$\\{y3}\K\\{half}(\\{y2}+\\{stack\_y2}+\\{eta\_corr})$;\5 +$\\{stack\_y1}\K\\{y3}$;\6 +$\|s\K\|s+\|s+\\{eta\_corr}$;\5 +$\|u\K\\{y1}+\\{y2}+\\{y3}+\|s$;\6 +$\|q\K\|u\mathbin{\&{div}}\\{two\_to\_the}[\|l]$;\5 +$\\{stack\_s}\K\|u\mathbin{\&{mod}}\\{two\_to\_the}[\|l]$;\6 +$\\{stack\_n}\K\|n-\|q$;\5 +$\|n\K\|q$;\6 +$\\{bisect\_ptr}\K\\{bisect\_ptr}+\\{move\_increment}$;\5 +\&{goto} \37\\{continue};\6 +\&{end}\2\2\2\par +\U311.\fi + +\M315. \P$\X315:Move upward \|n steps\X\S$\6 +\&{while} $\|n>0$ \1\&{do}\6 +\&{begin} \37$\\{incr}(\\{move\_ptr})$;\5 +$\\{move}[\\{move\_ptr}]\K1$;\5 +$\\{decr}(\|n)$;\6 +\&{end}\2\par +\U314.\fi + +\M316. \P$\X316:Move to the right \|m steps\X\S$\6 +$\\{move}[\\{move\_ptr}]\K\\{move}[\\{move\_ptr}]+\|m$\par +\U314.\fi + +\M317. \P$\X317:Make one move of each kind\X\S$\6 +\&{begin} \37$\|r\K\\{two\_to\_the}[\|l]-\|r$;\5 +$\|s\K\\{two\_to\_the}[\|l]-\|s$;\6 +\&{while} $\|l<30$ \1\&{do}\6 +\&{begin} \37$\\{x3a}\K\\{x3}$;\5 +$\\{x2a}\K\\{half}(\\{x2}+\\{x3}+\\{xi\_corr})$;\5 +$\\{x2}\K\\{half}(\\{x1}+\\{x2}+\\{xi\_corr})$;\5 +$\\{x3}\K\\{half}(\\{x2}+\\{x2a}+\\{xi\_corr})$;\5 +$\|t\K\\{x1}+\\{x2}+\\{x3}$;\5 +$\|r\K\|r+\|r-\\{xi\_corr}$;\6 +$\\{y3a}\K\\{y3}$;\5 +$\\{y2a}\K\\{half}(\\{y2}+\\{y3}+\\{eta\_corr})$;\5 +$\\{y2}\K\\{half}(\\{y1}+\\{y2}+\\{eta\_corr})$;\5 +$\\{y3}\K\\{half}(\\{y2}+\\{y2a}+\\{eta\_corr})$;\5 +$\|u\K\\{y1}+\\{y2}+\\{y3}$;\5 +$\|s\K\|s+\|s-\\{eta\_corr}$;\6 +\&{if} $\|t<\|r$ \1\&{then}\6 +\&{if} $\|u<\|s$ \1\&{then}\5 +\X318:Switch to the right subinterval\X\6 +\4\&{else} \&{begin} \37\X320:Move up then right\X;\6 +\&{goto} \37\\{done};\6 +\&{end}\2\6 +\4\&{else} \&{if} $\|u<\|s$ \1\&{then}\6 +\&{begin} \37\X319:Move right then up\X;\6 +\&{goto} \37\\{done};\6 +\&{end};\2\2\6 +$\\{incr}(\|l)$;\6 +\&{end};\2\6 +$\|r\K\|r-\\{xi\_corr}$;\5 +$\|s\K\|s-\\{eta\_corr}$;\6 +\&{if} $\\{ab\_vs\_cd}(\\{x1}+\\{x2}+\\{x3},\39\|s,\39\\{y1}+\\{y2}+\\{y3},\39% +\|r)-\\{xi\_corr}\G0$ \1\&{then}\5 +\X319:Move right then up\X\6 +\4\&{else} \X320:Move up then right\X;\2\6 +\4\\{done}: \37\&{end}\par +\U314.\fi + +\M318. \P$\X318:Switch to the right subinterval\X\S$\6 +\&{begin} \37$\\{x1}\K\\{x3}$;\5 +$\\{x2}\K\\{x2a}$;\5 +$\\{x3}\K\\{x3a}$;\5 +$\|r\K\|r-\|t$;\5 +$\\{y1}\K\\{y3}$;\5 +$\\{y2}\K\\{y2a}$;\5 +$\\{y3}\K\\{y3a}$;\5 +$\|s\K\|s-\|u$;\6 +\&{end}\par +\U317.\fi + +\M319. \P$\X319:Move right then up\X\S$\6 +\&{begin} \37$\\{incr}(\\{move}[\\{move\_ptr}])$;\5 +$\\{incr}(\\{move\_ptr})$;\5 +$\\{move}[\\{move\_ptr}]\K1$;\6 +\&{end}\par +\Us317\ET317.\fi + +\M320. \P$\X320:Move up then right\X\S$\6 +\&{begin} \37$\\{incr}(\\{move\_ptr})$;\5 +$\\{move}[\\{move\_ptr}]\K2$;\6 +\&{end}\par +\Us317\ET317.\fi + +\M321. After \\{make\_moves} has acted, possibly for several curves that move +toward +the same octant, a ``smoothing'' operation might be done on the \\{move} array. +This removes optical glitches that can arise even when the curve has been +digitized without rounding errors. + +The smoothing process replaces the integers $a_0\ldots a_n$ in +$\\{move}[\|b\to\|t]$ by ``smoothed'' integers $a_0'\ldots a_n'$ defined as +follows: +$$a_k'=a_k+\delta\k-\delta_k;\qquad +\delta_k=\cases{+1,&if $1<k<n$ and $a_{k-2}\G a_{k-1}\ll a_k\G a\k$;\cr +-1,&if $1<k<n$ and $a_{k-2}\L a_{k-1}\gg a_k\L a\k$;\cr +0,&otherwise.\cr}$$ +Here $a\ll b$ means that $a\L b-2$, and $a\gg b$ means that $a\G b+2$. + +The smoothing operation is symmetric in the sense that, if $a_0\ldots a_n$ +smoothes to $a_0'\ldots a_n'$, then the reverse sequence $a_n\ldots a_0$ +smoothes to $a_n'\ldots a_0'$; also the complementary sequence +$(m-a_0)\ldots(m-a_n)$ smoothes to $(m-a_0')\ldots(m-a_n')$. +We have $a_0'+\cdots+a_n'=a_0+\cdots+a_n$ because $\delta_0=\delta_{n+1}=0$. + +\Y\P\4\&{procedure}\1\ \37$\\{smooth\_moves}(\|b,\39\|t:\\{integer})$;\6 +\4\&{var} \37\|k: \37$1\to\\{move\_size}$;\C{index into \\{move}}\6 +$\|a,\39\\{aa},\39\\{aaa}$: \37\\{integer};\C{original values of $\\{move}[% +\|k],\\{move}[\|k-1],\\{move}[\|k-2]$}\2\6 +\&{begin} \37\&{if} $\|t-\|b\G3$ \1\&{then}\6 +\&{begin} \37$\|k\K\|b+2$;\5 +$\\{aa}\K\\{move}[\|k-1]$;\5 +$\\{aaa}\K\\{move}[\|k-2]$;\6 +\1\&{repeat} \37$\|a\K\\{move}[\|k]$;\6 +\&{if} $\\{abs}(\|a-\\{aa})>1$ \1\&{then}\5 +\X322:Increase and decrease $\\{move}[\|k-1]$ and $\\{move}[\|k]$ by $\delta_k$% +\X;\2\6 +$\\{incr}(\|k)$;\5 +$\\{aaa}\K\\{aa}$;\5 +$\\{aa}\K\|a$;\6 +\4\&{until}\5 +$\|k=\|t$;\2\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M322. \P$\X322:Increase and decrease $\\{move}[\|k-1]$ and $\\{move}[\|k]$ by +$\delta_k$\X\S$\6 +\&{if} $\|a>\\{aa}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{aaa}\G\\{aa}$ \1\&{then}\6 +\&{if} $\|a\G\\{move}[\|k+1]$ \1\&{then}\6 +\&{begin} \37$\\{incr}(\\{move}[\|k-1])$;\5 +$\\{move}[\|k]\K\|a-1$;\6 +\&{end};\2\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37\&{if} $\\{aaa}\L\\{aa}$ \1\&{then}\6 +\&{if} $\|a\L\\{move}[\|k+1]$ \1\&{then}\6 +\&{begin} \37$\\{decr}(\\{move}[\|k-1])$;\5 +$\\{move}[\|k]\K\|a+1$;\6 +\&{end};\2\2\6 +\&{end}\2\par +\U321.\fi + +\N323. \[20] Edge structures. +Now we come to \MF's internal scheme for representing what the user can +actually ``see,'' the edges between pixels. Each pixel has an integer +weight, obtained by summing the weights on all edges to its left. \MF\ +represents only the nonzero edge weights, since most of the edges are +weightless; in this way, the data storage requirements grow only linearly +with respect to the number of pixels per point, even though two-dimensional +data is being represented. (Well, the actual dependence on the underlying +resolution is order $n\log n$, but the the $\log n$ factor is buried in our +implicit restriction on the maximum raster size.) The sum of all edge +weights in each row should be zero. + +The data structure for edge weights must be compact and flexible, +yet it should support efficient updating and display operations. We +want to be able to have many different edge structures in memory at +once, and we want the computer to be able to translate them, reflect them, +and/or merge them together with relative ease. + +\MF's solution to this problem requires one single-word node per +nonzero edge weight, plus one two-word node for each row in a contiguous +set of rows. There's also a header node that provides global information +about the entire structure. + +\fi + +\M324. Let's consider the edge-weight nodes first. The \\{info} field of such +nodes contains both an $m$~value and a weight~$w$, in the form +$8m+w+c$, where $c$ is a constant that depends on data found in the header. +We shall consider $c$ in detail later; for now, it's best just to think +of it as a way to compensate for the fact that $m$ and~$w$ can be negative, +together with the fact that an \\{info} field must have a value between +\\{min\_halfword} and \\{max\_halfword}. The $m$ value is an unscaled +$x$~coordinate, +so it satisfies $\vert m\vert< +4096$; the $w$ value is always in the range $1\L\vert w\vert\L3$. We can +unpack the data in the \\{info} field by fetching $\\{ho}(\\{info}(\|p))=% +\\{info}(\|p)-\\{min\_halfword}$ and dividing this nonnegative number by~8; +the constant~$c$ will be chosen so that the remainder of this division +is $4+w$. Thus, for example, a remainder of~3 will correspond to +the edge weight $w=-1$. + +Every row of an edge structure contains two lists of such edge-weight +nodes, called the \\{sorted} and \\{unsorted} lists, linked together by their +\\{link} fields in the normal way. The difference between them is that we +always have $\\{info}(\|p)\L\\{info}(\\{link}(\|p))$ in the \\{sorted} list, +but there's no +such restriction on the elements of the \\{unsorted} list. The reason for +this distinction is that it would take unnecessarily long to maintain +edge-weight lists in sorted order while they're being updated; but when we +need to process an entire row from left to right in order of the +$m$~values, it's fairly easy and quick to sort a short list of unsorted +elements and to merge them into place among their sorted cohorts. +Furthermore, the fact that the \\{unsorted} list is empty can sometimes be +used to good advantage, because it allows us to conclude that a particular +row has not changed since the last time we sorted it. + +The final \\{link} of the \\{sorted} list will be \\{sentinel}, which points to +a special one-word node whose \\{info} field is essentially infinite; this +facilitates the sorting and merging operations. The final \\{link} of the +\\{unsorted} list will be either \\{null} or \\{void}, where $\\{void}=% +\\{null}+1$ +is used to avoid redisplaying data that has not changed: +A \\{void} value is stored at the head of the +unsorted list whenever the corresponding row has been displayed. + +\Y\P\D \37$\\{zero\_w}=4$\par +\P\D \37$\\{void}\S\\{null}+1$\par +\Y\P$\4\X176:Initialize table entries (done by \.{INIMF} only)\X\mathrel{+}\S$\6 +$\\{info}(\\{sentinel})\K\\{max\_halfword}$;\C{$\\{link}(\\{sentinel})=% +\\{null}$}\par +\fi + +\M325. The rows themselves are represented by row-header nodes that +contain four link fields. Two of these four, \\{sorted} and \\{unsorted}, +point to the first items of the edge-weight lists just mentioned. +The other two, \\{link} and \\{knil}, point to the headers of the two +adjacent rows. If \|p points to the header for row number~\|n, then +$\\{link}(\|p)$ points up to the header for row~$\|n+1$, and $\\{knil}(\|p)$ +points +down to the header for row~$\|n-1$. This double linking makes it +convenient to move through consecutive rows either upward or downward; +as usual, we have $\\{link}(\\{knil}(\|p))=\\{knil}(\\{link}(\|p))=\|p$ for all +row headers~\|p. + +The row associated with a given value of \|n contains weights for +edges that run between the lattice points $(\|m,\|n)$ and $(\|m,\|n+1)$. + +\Y\P\D \37$\\{knil}\S\\{info}$\C{inverse of the \\{link} field, in a doubly +linked list}\par +\P\D \37$\\{sorted\_loc}(\#)\S\#+1$\C{where the \\{sorted} link field resides}% +\par +\P\D \37$\\{sorted}(\#)\S\\{link}(\\{sorted\_loc}(\#))$\C{beginning of the list +of sorted edge weights}\par +\P\D \37$\\{unsorted}(\#)\S\\{info}(\#+1)$\C{beginning of the list of unsorted +edge weights}\par +\P\D \37$\\{row\_node\_size}=2$\C{number of words in a row header node}\par +\fi + +\M326. The main header node \|h for an edge structure has \\{link} and \\{knil} +fields that link it above the topmost row and below the bottommost row. +It also has fields called \\{m\_min}, \\{m\_max}, \\{n\_min}, and \\{n\_max} +that +bound the current extent of the edge data: All \|m values in edge-weight +nodes should lie between $\\{m\_min}(\|h)-4096$ and $\\{m\_max}(\|h)-4096$, +inclusive. +Furthermore the topmost row header, pointed to by $\\{knil}(\|h)$, +is for row number $\\{n\_max}(\|h)-4096$; the bottommost row header, pointed to +by +$\\{link}(\|h)$, is for row number $\\{n\_min}(\|h)-4096$. + +The offset constant \|c that's used in all of the edge-weight data is +represented implicitly in $\\{m\_offset}(\|h)$; its actual value is +$$\hbox{$\|c=\\{min\_halfword}+\\{zero\_w}+8\ast\\{m\_offset}(\|h)$.}$$ +Notice that it's possible to shift an entire edge structure by an +amount $(\Delta m,\Delta n)$ by adding $\Delta n$ to $\\{n\_min}(\|h)$ and $% +\\{n\_max}(\|h)$, +adding $\Delta m$ to $\\{m\_min}(\|h)$ and $\\{m\_max}(\|h)$, and subtracting +$\Delta m$ from $\\{m\_offset}(\|h)$; +none of the other edge data needs to be modified. Initially the \\{m\_offset} +field is~4096, but it will change if the user requests such a shift. +The contents of these five fields should always be positive and less than +8192; \\{n\_max} should, in fact, be less than 8191. Furthermore +$\\{m\_min}+\\{m\_offset}-4096$ and $\\{m\_max}+\\{m\_offset}-4096$ must also +lie strictly +between 0 and 8192, so that the \\{info} fields of edge-weight nodes will +fit in a halfword. + +The header node of an edge structure also contains two somewhat unusual +fields that are called $\\{last\_window}(\|h)$ and $\\{last\_window\_time}(% +\|h)$. When this +structure is displayed in window~\|k of the user's screen, after that +window has been updated \|t times, \MF\ sets $\\{last\_window}(\|h)\K\|k$ and +$\\{last\_window\_time}(\|h)\K\|t$; it also sets $\\{unsorted}(\|p)\K\\{void}$ +for all row +headers~\|p, after merging any existing unsorted weights with the sorted +ones. A subsequent display in the same window will be able to avoid +redisplaying rows whose \\{unsorted} list is still \\{void}, if the window +hasn't been used for something else in the meantime. + +A pointer to the row header of row $\\{n\_pos}(\|h)-4096$ is provided in +$\\{n\_rover}(\|h)$. Most of the algorithms that update an edge structure +are able to get by without random row references; they usually +access rows that are neighbors of each other or of the current \\{n\_pos} row. +Exception: If $\\{link}(\|h)=\|h$ (so that the edge structure contains +no rows), we have $\\{n\_rover}(\|h)=\|h$, and $\\{n\_pos}(\|h)$ is irrelevant. + +\Y\P\D \37$\\{zero\_field}=4096$\C{amount added to coordinates to make them +positive}\par +\P\D \37$\\{n\_min}(\#)\S\\{info}(\#+1)$\C{minimum row number present, plus % +\\{zero\_field}}\par +\P\D \37$\\{n\_max}(\#)\S\\{link}(\#+1)$\C{maximum row number present, plus % +\\{zero\_field}}\par +\P\D \37$\\{m\_min}(\#)\S\\{info}(\#+2)$\C{minimum column number present, plus % +\\{zero\_field}}\par +\P\D \37$\\{m\_max}(\#)\S\\{link}(\#+2)$\C{maximum column number present, plus % +\\{zero\_field}}\par +\P\D \37$\\{m\_offset}(\#)\S\\{info}(\#+3)$\C{translation of $m$ data in +edge-weight nodes}\par +\P\D \37$\\{last\_window}(\#)\S\\{link}(\#+3)$\C{the last display went into +this window}\par +\P\D \37$\\{last\_window\_time}(\#)\S\\{mem}[\#+4].\\{int}$\C{after this many +window updates}\par +\P\D \37$\\{n\_pos}(\#)\S\\{info}(\#+5)$\C{the row currently in \\{n\_rover}, +plus \\{zero\_field}}\par +\P\D \37$\\{n\_rover}(\#)\S\\{link}(\#+5)$\C{a row recently referenced}\par +\P\D \37$\\{edge\_header\_size}=6$\C{number of words in an edge-structure +header}\par +\P\D \37$\\{valid\_range}(\#)\S(\\{abs}(\#-4096)<4096)$\C{is $\#$ strictly +between 0 and 8192?}\par +\P\D \37$\\{empty\_edges}(\#)\S\\{link}(\#)=\#$\C{are there no rows in this +edge header?}\par +\Y\P\4\&{procedure}\1\ \37$\\{init\_edges}(\|h:\\{pointer})$;\C{initialize an +edge header to null values}\2\6 +\&{begin} \37$\\{knil}(\|h)\K\|h$;\5 +$\\{link}(\|h)\K\|h$;\6 +$\\{n\_min}(\|h)\K\\{zero\_field}+4095$;\5 +$\\{n\_max}(\|h)\K\\{zero\_field}-4095$;\5 +$\\{m\_min}(\|h)\K\\{zero\_field}+4095$;\5 +$\\{m\_max}(\|h)\K\\{zero\_field}-4095$;\5 +$\\{m\_offset}(\|h)\K\\{zero\_field}$;\6 +$\\{last\_window}(\|h)\K0$;\5 +$\\{last\_window\_time}(\|h)\K0$;\6 +$\\{n\_rover}(\|h)\K\|h$;\5 +$\\{n\_pos}(\|h)\K0$;\6 +\&{end};\par +\fi + +\M327. When a lot of work is being done on a particular edge structure, we +plant +a pointer to its main header in the global variable \\{cur\_edges}. +This saves us from having to pass this pointer as a parameter over and +over again between subroutines. + +Similarly, \\{cur\_wt} is a global weight that is being used by several +procedures at once. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{cur\_edges}: \37\\{pointer};\C{the edge structure of current interest}\6 +\4\\{cur\_wt}: \37\\{integer};\C{the edge weight of current interest}\par +\fi + +\M328. The \\{fix\_offset} routine goes through all the edge-weight nodes of +\\{cur\_edges} and adds a constant to their \\{info} fields, so that +$\\{m\_offset}(\\{cur\_edges})$ can be brought back to \\{zero\_field}. (This +is necessary only in unusual cases when the offset has gotten too +large or too small.) + +\Y\P\4\&{procedure}\1\ \37\\{fix\_offset};\6 +\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{list traversers}\6 +\\{delta}: \37\\{integer};\C{the amount of change}\2\6 +\&{begin} \37$\\{delta}\K8\ast(\\{m\_offset}(\\{cur\_edges})-\\{zero\_field})$;% +\5 +$\\{m\_offset}(\\{cur\_edges})\K\\{zero\_field}$;\5 +$\|q\K\\{link}(\\{cur\_edges})$;\6 +\&{while} $\|q\I\\{cur\_edges}$ \1\&{do}\6 +\&{begin} \37$\|p\K\\{sorted}(\|q)$;\6 +\&{while} $\|p\I\\{sentinel}$ \1\&{do}\6 +\&{begin} \37$\\{info}(\|p)\K\\{info}(\|p)-\\{delta}$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +$\|p\K\\{unsorted}(\|q)$;\6 +\&{while} $\|p>\\{void}$ \1\&{do}\6 +\&{begin} \37$\\{info}(\|p)\K\\{info}(\|p)-\\{delta}$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +$\|q\K\\{link}(\|q)$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M329. The \\{edge\_prep} routine makes the \\{cur\_edges} structure ready to +accept new data whose coordinates satisfy $\\{ml}\L\|m\L\\{mr}$ and $\\{nl}\L% +\|n\L\\{nr}-1$, +assuming that $-4096<\\{ml}\L\\{mr}<4096$ and $-4096<\\{nl}\L\\{nr}<4096$. It +makes +appropriate adjustments to \\{m\_min}, \\{m\_max}, \\{n\_min}, and \\{n\_max}, +adding new empty rows if necessary. + +\Y\P\4\&{procedure}\1\ \37$\\{edge\_prep}(\\{ml},\39\\{mr},\39\\{nl},\39% +\\{nr}:\\{integer})$;\6 +\4\&{var} \37\\{delta}: \37\\{halfword};\C{amount of change}\6 +$\|p,\39\|q$: \37\\{pointer};\C{for list manipulation}\2\6 +\&{begin} \37$\\{ml}\K\\{ml}+\\{zero\_field}$;\5 +$\\{mr}\K\\{mr}+\\{zero\_field}$;\5 +$\\{nl}\K\\{nl}+\\{zero\_field}$;\5 +$\\{nr}\K\\{nr}-1+\\{zero\_field}$;\6 +\&{if} $\\{ml}<\\{m\_min}(\\{cur\_edges})$ \1\&{then}\5 +$\\{m\_min}(\\{cur\_edges})\K\\{ml}$;\2\6 +\&{if} $\\{mr}>\\{m\_max}(\\{cur\_edges})$ \1\&{then}\5 +$\\{m\_max}(\\{cur\_edges})\K\\{mr}$;\2\6 +\&{if} $\R\\{valid\_range}(\\{m\_min}(\\{cur\_edges})+\\{m\_offset}(\\{cur% +\_edges})-\\{zero\_field})\V\30\R\\{valid\_range}(\\{m\_max}(\\{cur\_edges})+% +\\{m\_offset}(\\{cur\_edges})-\\{zero\_field})$ \1\&{then}\5 +\\{fix\_offset};\2\6 +\&{if} $\\{empty\_edges}(\\{cur\_edges})$ \1\&{then}\C{there are no rows}\6 +\&{begin} \37$\\{n\_min}(\\{cur\_edges})\K\\{nr}+1$;\5 +$\\{n\_max}(\\{cur\_edges})\K\\{nr}$;\6 +\&{end};\2\6 +\&{if} $\\{nl}<\\{n\_min}(\\{cur\_edges})$ \1\&{then}\5 +\X330:Insert exactly $\\{n\_min}(\\{cur\_edges})-\\{nl}$ empty rows at the +bottom\X;\2\6 +\&{if} $\\{nr}>\\{n\_max}(\\{cur\_edges})$ \1\&{then}\5 +\X331:Insert exactly $\\{nr}-\\{n\_max}(\\{cur\_edges})$ empty rows at the top% +\X;\2\6 +\&{end};\par +\fi + +\M330. \P$\X330:Insert exactly $\\{n\_min}(\\{cur\_edges})-\\{nl}$ empty rows +at the bottom\X\S$\6 +\&{begin} \37$\\{delta}\K\\{n\_min}(\\{cur\_edges})-\\{nl}$;\5 +$\\{n\_min}(\\{cur\_edges})\K\\{nl}$;\5 +$\|p\K\\{link}(\\{cur\_edges})$;\6 +\1\&{repeat} \37$\|q\K\\{get\_node}(\\{row\_node\_size})$;\5 +$\\{sorted}(\|q)\K\\{sentinel}$;\5 +$\\{unsorted}(\|q)\K\\{void}$;\5 +$\\{knil}(\|p)\K\|q$;\5 +$\\{link}(\|q)\K\|p$;\5 +$\|p\K\|q$;\5 +$\\{decr}(\\{delta})$;\6 +\4\&{until}\5 +$\\{delta}=0$;\2\6 +$\\{knil}(\|p)\K\\{cur\_edges}$;\5 +$\\{link}(\\{cur\_edges})\K\|p$;\6 +\&{if} $\\{n\_rover}(\\{cur\_edges})=\\{cur\_edges}$ \1\&{then}\5 +$\\{n\_pos}(\\{cur\_edges})\K\\{nl}-1$;\2\6 +\&{end}\par +\U329.\fi + +\M331. \P$\X331:Insert exactly $\\{nr}-\\{n\_max}(\\{cur\_edges})$ empty rows +at the top\X\S$\6 +\&{begin} \37$\\{delta}\K\\{nr}-\\{n\_max}(\\{cur\_edges})$;\5 +$\\{n\_max}(\\{cur\_edges})\K\\{nr}$;\5 +$\|p\K\\{knil}(\\{cur\_edges})$;\6 +\1\&{repeat} \37$\|q\K\\{get\_node}(\\{row\_node\_size})$;\5 +$\\{sorted}(\|q)\K\\{sentinel}$;\5 +$\\{unsorted}(\|q)\K\\{void}$;\5 +$\\{link}(\|p)\K\|q$;\5 +$\\{knil}(\|q)\K\|p$;\5 +$\|p\K\|q$;\5 +$\\{decr}(\\{delta})$;\6 +\4\&{until}\5 +$\\{delta}=0$;\2\6 +$\\{link}(\|p)\K\\{cur\_edges}$;\5 +$\\{knil}(\\{cur\_edges})\K\|p$;\6 +\&{if} $\\{n\_rover}(\\{cur\_edges})=\\{cur\_edges}$ \1\&{then}\5 +$\\{n\_pos}(\\{cur\_edges})\K\\{nr}+1$;\2\6 +\&{end}\par +\U329.\fi + +\M332. The \\{print\_edges} subroutine gives a symbolic rendition of an edge +structure, for use in `\&{show}' commands. A rather terse output +format has been chosen since edge structures can grow quite large. + +\Y\P$\4\X257:Declare subroutines for printing expressions\X\mathrel{+}\S$\6 +\hbox{\4}\X333:Declare the procedure called \\{print\_weight}\X\6 +\4\&{procedure}\1\ \37$\\{print\_edges}(\|s:\\{str\_number};\,\35\\{nuline}:% +\\{boolean};\,\35\\{x\_off},\39\\{y\_off}:\\{integer})$;\6 +\4\&{var} \37$\|p,\39\|q,\39\|r$: \37\\{pointer};\C{for list traversal}\6 +\|n: \37\\{integer};\C{row number}\2\6 +\&{begin} \37$\\{print\_diagnostic}(\.{"Edge\ structure"},\39\|s,\39% +\\{nuline})$;\5 +$\|p\K\\{knil}(\\{cur\_edges})$;\5 +$\|n\K\\{n\_max}(\\{cur\_edges})-\\{zero\_field}$;\6 +\&{while} $\|p\I\\{cur\_edges}$ \1\&{do}\6 +\&{begin} \37$\|q\K\\{unsorted}(\|p)$;\5 +$\|r\K\\{sorted}(\|p)$;\6 +\&{if} $(\|q>\\{void})\V(\|r\I\\{sentinel})$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"row\ "})$;\5 +$\\{print\_int}(\|n+\\{y\_off})$;\5 +$\\{print\_char}(\.{":"})$;\6 +\&{while} $\|q>\\{void}$ \1\&{do}\6 +\&{begin} \37$\\{print\_weight}(\|q,\39\\{x\_off})$;\5 +$\|q\K\\{link}(\|q)$;\6 +\&{end};\2\6 +$\\{print}(\.{"\ |"})$;\6 +\&{while} $\|r\I\\{sentinel}$ \1\&{do}\6 +\&{begin} \37$\\{print\_weight}(\|r,\39\\{x\_off})$;\5 +$\|r\K\\{link}(\|r)$;\6 +\&{end};\2\6 +\&{end};\2\6 +$\|p\K\\{knil}(\|p)$;\5 +$\\{decr}(\|n)$;\6 +\&{end};\2\6 +$\\{end\_diagnostic}(\\{true})$;\6 +\&{end};\par +\fi + +\M333. \P$\X333:Declare the procedure called \\{print\_weight}\X\S$\6 +\4\&{procedure}\1\ \37$\\{print\_weight}(\|q:\\{pointer};\,\35\\{x\_off}:% +\\{integer})$;\6 +\4\&{var} \37$\|w,\39\|m$: \37\\{integer};\C{unpacked weight and coordinate}\6 +\|d: \37\\{integer};\C{temporary data register}\2\6 +\&{begin} \37$\|d\K\\{ho}(\\{info}(\|q))$;\5 +$\|w\K\|d\mathbin{\&{mod}}8$;\5 +$\|m\K(\|d\mathbin{\&{div}}8)-\\{m\_offset}(\\{cur\_edges})$;\6 +\&{if} $\\{file\_offset}>\\{max\_print\_line}-9$ \1\&{then}\5 +$\\{print\_nl}(\.{"\ "})$\6 +\4\&{else} $\\{print\_char}(\.{"\ "})$;\2\6 +$\\{print\_int}(\|m+\\{x\_off})$;\6 +\&{while} $\|w>\\{zero\_w}$ \1\&{do}\6 +\&{begin} \37$\\{print\_char}(\.{"+"})$;\5 +$\\{decr}(\|w)$;\6 +\&{end};\2\6 +\&{while} $\|w<\\{zero\_w}$ \1\&{do}\6 +\&{begin} \37$\\{print\_char}(\.{"-"})$;\5 +$\\{incr}(\|w)$;\6 +\&{end};\2\6 +\&{end};\par +\U332.\fi + +\M334. Here's a trivial subroutine that copies an edge structure. (Let's hope +that the given structure isn't too gigantic.) + +\Y\P\4\&{function}\1\ \37$\\{copy\_edges}(\|h:\\{pointer})$: \37\\{pointer};\6 +\4\&{var} \37$\|p,\39\|r$: \37\\{pointer};\C{variables that traverse the given +structure}\6 +$\\{hh},\39\\{pp},\39\\{qq},\39\\{rr},\39\\{ss}$: \37\\{pointer};\C{variables +that traverse the new structure}\2\6 +\&{begin} \37$\\{hh}\K\\{get\_node}(\\{edge\_header\_size})$;\5 +$\\{mem}[\\{hh}+1]\K\\{mem}[\|h+1]$;\5 +$\\{mem}[\\{hh}+2]\K\\{mem}[\|h+2]$;\5 +$\\{mem}[\\{hh}+3]\K\\{mem}[\|h+3]$;\5 +$\\{mem}[\\{hh}+4]\K\\{mem}[\|h+4]$;\C{we've now copied \\{n\_min}, \\{n\_max}, + \\{m\_min}, \\{m\_max}, \\{m\_offset}, \\{last\_window}, and \\{last\_window% +\_time}}\6 +$\\{n\_pos}(\\{hh})\K\\{n\_max}(\\{hh})+1$;\5 +$\\{n\_rover}(\\{hh})\K\\{hh}$;\6 +$\|p\K\\{link}(\|h)$;\5 +$\\{qq}\K\\{hh}$;\6 +\&{while} $\|p\I\|h$ \1\&{do}\6 +\&{begin} \37$\\{pp}\K\\{get\_node}(\\{row\_node\_size})$;\5 +$\\{link}(\\{qq})\K\\{pp}$;\5 +$\\{knil}(\\{pp})\K\\{qq}$;\5 +\X335:Copy both \\{sorted} and \\{unsorted} lists of \|p to \\{pp}\X;\6 +$\|p\K\\{link}(\|p)$;\5 +$\\{qq}\K\\{pp}$;\6 +\&{end};\2\6 +$\\{link}(\\{qq})\K\\{hh}$;\5 +$\\{knil}(\\{hh})\K\\{qq}$;\5 +$\\{copy\_edges}\K\\{hh}$;\6 +\&{end};\par +\fi + +\M335. \P$\X335:Copy both \\{sorted} and \\{unsorted} lists of \|p to \\{pp}\X% +\S$\6 +$\|r\K\\{sorted}(\|p)$;\5 +$\\{rr}\K\\{sorted\_loc}(\\{pp})$;\C{$\\{link}(\\{rr})=\\{sorted}(\\{pp})$}\6 +\&{while} $\|r\I\\{sentinel}$ \1\&{do}\6 +\&{begin} \37$\\{ss}\K\\{get\_avail}$;\5 +$\\{link}(\\{rr})\K\\{ss}$;\5 +$\\{rr}\K\\{ss}$;\5 +$\\{info}(\\{rr})\K\\{info}(\|r)$;\6 +$\|r\K\\{link}(\|r)$;\6 +\&{end};\2\6 +$\\{link}(\\{rr})\K\\{sentinel}$;\6 +$\|r\K\\{unsorted}(\|p)$;\5 +$\\{rr}\K\\{temp\_head}$;\6 +\&{while} $\|r>\\{void}$ \1\&{do}\6 +\&{begin} \37$\\{ss}\K\\{get\_avail}$;\5 +$\\{link}(\\{rr})\K\\{ss}$;\5 +$\\{rr}\K\\{ss}$;\5 +$\\{info}(\\{rr})\K\\{info}(\|r)$;\6 +$\|r\K\\{link}(\|r)$;\6 +\&{end};\2\6 +$\\{link}(\\{rr})\K\|r$;\5 +$\\{unsorted}(\\{pp})\K\\{link}(\\{temp\_head})$\par +\Us334\ET341.\fi + +\M336. Another trivial routine flips \\{cur\_edges} about the \|x-axis +(i.e., negates all the \|y coordinates), assuming that at least +one row is present. + +\Y\P\4\&{procedure}\1\ \37\\{y\_reflect\_edges};\6 +\4\&{var} \37$\|p,\39\|q,\39\|r$: \37\\{pointer};\C{list manipulation +registers}\2\6 +\&{begin} \37$\|p\K\\{n\_min}(\\{cur\_edges})$;\5 +$\\{n\_min}(\\{cur\_edges})\K\\{zero\_field}+\\{zero\_field}-1-\\{n\_max}(% +\\{cur\_edges})$;\5 +$\\{n\_max}(\\{cur\_edges})\K\\{zero\_field}+\\{zero\_field}-1-\|p$;\5 +$\\{n\_pos}(\\{cur\_edges})\K\\{zero\_field}+\\{zero\_field}-1-\\{n\_pos}(% +\\{cur\_edges})$;\6 +$\|p\K\\{link}(\\{cur\_edges})$;\5 +$\|q\K\\{cur\_edges}$;\C{we assume that $\|p\I\|q$}\6 +\1\&{repeat} \37$\|r\K\\{link}(\|p)$;\5 +$\\{link}(\|p)\K\|q$;\5 +$\\{knil}(\|q)\K\|p$;\5 +$\|q\K\|p$;\5 +$\|p\K\|r$;\6 +\4\&{until}\5 +$\|q=\\{cur\_edges}$;\2\6 +$\\{last\_window\_time}(\\{cur\_edges})\K0$;\6 +\&{end};\par +\fi + +\M337. It's somewhat more difficult, yet not too hard, to reflect about the % +\|y-axis. + +\Y\P\4\&{procedure}\1\ \37\\{x\_reflect\_edges};\6 +\4\&{var} \37$\|p,\39\|q,\39\|r,\39\|s$: \37\\{pointer};\C{list manipulation +registers}\6 +\|m: \37\\{integer};\C{\\{info} fields will be reflected with respect to this +number}\2\6 +\&{begin} \37$\|p\K\\{m\_min}(\\{cur\_edges})$;\5 +$\\{m\_min}(\\{cur\_edges})\K\\{zero\_field}+\\{zero\_field}-\\{m\_max}(\\{cur% +\_edges})$;\5 +$\\{m\_max}(\\{cur\_edges})\K\\{zero\_field}+\\{zero\_field}-\|p$;\5 +$\|m\K(\\{zero\_field}+\\{m\_offset}(\\{cur\_edges}))\ast8+\\{zero\_w}+\\{min% +\_halfword}+\\{zero\_w}+\\{min\_halfword}$;\5 +$\\{m\_offset}(\\{cur\_edges})\K\\{zero\_field}$;\5 +$\|p\K\\{link}(\\{cur\_edges})$;\6 +\1\&{repeat} \37\X339:Reflect the edge-and-weight data in $\\{sorted}(\|p)$\X;\6 +\X338:Reflect the edge-and-weight data in $\\{unsorted}(\|p)$\X;\6 +$\|p\K\\{link}(\|p)$;\6 +\4\&{until}\5 +$\|p=\\{cur\_edges}$;\2\6 +$\\{last\_window\_time}(\\{cur\_edges})\K0$;\6 +\&{end};\par +\fi + +\M338. We want to change the sign of the weight as we change the sign of the +\|x~coordinate. Fortunately, it's easier to do this than to negate +one without the other. + +\Y\P$\4\X338:Reflect the edge-and-weight data in $\\{unsorted}(\|p)$\X\S$\6 +$\|q\K\\{unsorted}(\|p)$;\6 +\&{while} $\|q>\\{void}$ \1\&{do}\6 +\&{begin} \37$\\{info}(\|q)\K\|m-\\{info}(\|q)$;\5 +$\|q\K\\{link}(\|q)$;\6 +\&{end}\2\par +\U337.\fi + +\M339. Reversing the order of a linked list is best thought of as the process +of +popping nodes off one stack and pushing them on another. In this case we +pop from stack~\|q and push to stack~\|r. + +\Y\P$\4\X339:Reflect the edge-and-weight data in $\\{sorted}(\|p)$\X\S$\6 +$\|q\K\\{sorted}(\|p)$;\5 +$\|r\K\\{sentinel}$;\6 +\&{while} $\|q\I\\{sentinel}$ \1\&{do}\6 +\&{begin} \37$\|s\K\\{link}(\|q)$;\5 +$\\{link}(\|q)\K\|r$;\5 +$\|r\K\|q$;\5 +$\\{info}(\|r)\K\|m-\\{info}(\|q)$;\5 +$\|q\K\|s$;\6 +\&{end};\2\6 +$\\{sorted}(\|p)\K\|r$\par +\U337.\fi + +\M340. Now let's multiply all the $y$~coordinates of a nonempty edge structure +by a small integer $s>1$: + +\Y\P\4\&{procedure}\1\ \37$\\{y\_scale\_edges}(\|s:\\{integer})$;\6 +\4\&{var} \37$\|p,\39\|q,\39\\{pp},\39\|r,\39\\{rr},\39\\{ss}$: \37\\{pointer};% +\C{list manipulation registers}\6 +\|t: \37\\{integer};\C{replication counter}\2\6 +\&{begin} \37\&{if} $(\|s\ast(\\{n\_max}(\\{cur\_edges})+1-\\{zero\_field})% +\G4096)\V\30(\|s\ast(\\{n\_min}(\\{cur\_edges})-\\{zero\_field})\L-4096)$ \1% +\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"Scaled\ picture\ would\ be\ too\ big"})$;\5 +$\\{help3}(\.{"I\ can\'t\ yscale\ the\ picture\ as\ requested---it\ would"})$\6 +$(\.{"make\ some\ coordinates\ too\ large\ or\ too\ small."})$\6 +$(\.{"Proceed,\ and\ I\'ll\ omit\ the\ transformation."})$;\5 +\\{put\_get\_error};\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{n\_max}(\\{cur\_edges})\K\|s\ast(\\{n\_max}(\\{cur% +\_edges})+1-\\{zero\_field})-1+\\{zero\_field}$;\5 +$\\{n\_min}(\\{cur\_edges})\K\|s\ast(\\{n\_min}(\\{cur\_edges})-\\{zero% +\_field})+\\{zero\_field}$;\5 +\X341:Replicate every row exactly $s$ times\X;\6 +$\\{last\_window\_time}(\\{cur\_edges})\K0$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M341. \P$\X341:Replicate every row exactly $s$ times\X\S$\6 +$\|p\K\\{cur\_edges}$;\6 +\1\&{repeat} \37$\|q\K\|p$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{for} $\|t\K2\mathrel{\&{to}}\|s$ \1\&{do}\6 +\&{begin} \37$\\{pp}\K\\{get\_node}(\\{row\_node\_size})$;\5 +$\\{link}(\|q)\K\\{pp}$;\5 +$\\{knil}(\|p)\K\\{pp}$;\5 +$\\{link}(\\{pp})\K\|p$;\5 +$\\{knil}(\\{pp})\K\|q$;\5 +$\|q\K\\{pp}$;\5 +\X335:Copy both \\{sorted} and \\{unsorted} lists of \|p to \\{pp}\X;\6 +\&{end};\2\6 +\4\&{until}\5 +$\\{link}(\|p)=\\{cur\_edges}$\2\par +\U340.\fi + +\M342. Scaling the $x$~coordinates is, of course, our next task. + +\Y\P\4\&{procedure}\1\ \37$\\{x\_scale\_edges}(\|s:\\{integer})$;\6 +\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{list manipulation registers}\6 +\|t: \37$0\to65535$;\C{unpacked \\{info} field}\6 +\|w: \37$0\to7$;\C{unpacked weight}\6 +\\{delta}: \37\\{integer};\C{amount added to scaled \\{info}}\2\6 +\&{begin} \37\&{if} $(\|s\ast(\\{m\_max}(\\{cur\_edges})-\\{zero\_field})% +\G4096)\V\30(\|s\ast(\\{m\_min}(\\{cur\_edges})-\\{zero\_field})\L-4096)$ \1% +\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"Scaled\ picture\ would\ be\ too\ big"})$;\5 +$\\{help3}(\.{"I\ can\'t\ xscale\ the\ picture\ as\ requested---it\ would"})$\6 +$(\.{"make\ some\ coordinates\ too\ large\ or\ too\ small."})$\6 +$(\.{"Proceed,\ and\ I\'ll\ omit\ the\ transformation."})$;\5 +\\{put\_get\_error};\6 +\&{end}\6 +\4\&{else} \&{if} $(\\{m\_max}(\\{cur\_edges})\I\\{zero\_field})\V(\\{m\_min}(% +\\{cur\_edges})\I\\{zero\_field})$ \1\&{then}\6 +\&{begin} \37$\\{m\_max}(\\{cur\_edges})\K\|s\ast(\\{m\_max}(\\{cur\_edges})-% +\\{zero\_field})+\\{zero\_field}$;\5 +$\\{m\_min}(\\{cur\_edges})\K\|s\ast(\\{m\_min}(\\{cur\_edges})-\\{zero% +\_field})+\\{zero\_field}$;\5 +$\\{delta}\K8\ast(\\{zero\_field}-\|s\ast\\{m\_offset}(\\{cur\_edges}))+\\{min% +\_halfword}$;\5 +$\\{m\_offset}(\\{cur\_edges})\K\\{zero\_field}$;\6 +\X343:Scale the $x$~coordinates of each row by $s$\X;\6 +$\\{last\_window\_time}(\\{cur\_edges})\K0$;\6 +\&{end};\2\2\6 +\&{end};\par +\fi + +\M343. The multiplications cannot overflow because we know that $\|s<4096$. + +\Y\P$\4\X343:Scale the $x$~coordinates of each row by $s$\X\S$\6 +$\|q\K\\{link}(\\{cur\_edges})$;\6 +\1\&{repeat} \37$\|p\K\\{sorted}(\|q)$;\6 +\&{while} $\|p\I\\{sentinel}$ \1\&{do}\6 +\&{begin} \37$\|t\K\\{ho}(\\{info}(\|p))$;\5 +$\|w\K\|t\mathbin{\&{mod}}8$;\5 +$\\{info}(\|p)\K(\|t-\|w)\ast\|s+\|w+\\{delta}$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +$\|p\K\\{unsorted}(\|q)$;\6 +\&{while} $\|p>\\{void}$ \1\&{do}\6 +\&{begin} \37$\|t\K\\{ho}(\\{info}(\|p))$;\5 +$\|w\K\|t\mathbin{\&{mod}}8$;\5 +$\\{info}(\|p)\K(\|t-\|w)\ast\|s+\|w+\\{delta}$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +$\|q\K\\{link}(\|q)$;\6 +\4\&{until}\5 +$\|q=\\{cur\_edges}$\2\par +\U342.\fi + +\M344. Here is a routine that changes the signs of all the weights, without +changing anything else. + +\Y\P\4\&{procedure}\1\ \37$\\{negate\_edges}(\|h:\\{pointer})$;\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37$\|p,\39\|q,\39\|r,\39\|s,\39\|t,\39\|u$: \37\\{pointer};% +\C{structure traversers}\2\6 +\&{begin} \37$\|p\K\\{link}(\|h)$;\6 +\&{while} $\|p\I\|h$ \1\&{do}\6 +\&{begin} \37$\|q\K\\{unsorted}(\|p)$;\6 +\&{while} $\|q>\\{void}$ \1\&{do}\6 +\&{begin} \37$\\{info}(\|q)\K8-2\ast((\\{ho}(\\{info}(\|q)))\mathbin{% +\&{mod}}8)+\\{info}(\|q)$;\5 +$\|q\K\\{link}(\|q)$;\6 +\&{end};\2\6 +$\|q\K\\{sorted}(\|p)$;\6 +\&{if} $\|q\I\\{sentinel}$ \1\&{then}\6 +\&{begin} \37\1\&{repeat} \37$\\{info}(\|q)\K8-2\ast((\\{ho}(\\{info}(\|q)))% +\mathbin{\&{mod}}8)+\\{info}(\|q)$;\5 +$\|q\K\\{link}(\|q)$;\6 +\4\&{until}\5 +$\|q=\\{sentinel}$;\2\6 +\X345:Put the list $\\{sorted}(\|p)$ back into sort\X;\6 +\&{end};\2\6 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +$\\{last\_window\_time}(\|h)\K0$;\6 +\&{end};\par +\fi + +\M345. \MF\ would work even if the code in this section were omitted, because +a list of edge-and-weight data that is sorted only by +\|m but not~\|w turns out to be good enough for correct operation. +However, the author decided not to make the program even trickier than +it is already, since \\{negate\_edges} isn't needed very often. +The simpler-to-state condition, ``keep the \\{sorted} list fully sorted,'' +is therefore being preserved at the cost of extra computation. + +\Y\P$\4\X345:Put the list $\\{sorted}(\|p)$ back into sort\X\S$\6 +$\|u\K\\{sorted\_loc}(\|p)$;\5 +$\|q\K\\{link}(\|u)$;\5 +$\|r\K\|q$;\5 +$\|s\K\\{link}(\|r)$;\C{$\|q=\\{sorted}(\|p)$}\6 +\~ \1\&{loop}\ \&{if} $\\{info}(\|s)>\\{info}(\|r)$ \1\&{then}\6 +\&{begin} \37$\\{link}(\|u)\K\|q$;\6 +\&{if} $\|s=\\{sentinel}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\|u\K\|r$;\5 +$\|q\K\|s$;\5 +$\|r\K\|q$;\5 +$\|s\K\\{link}(\|r)$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|t\K\|s$;\5 +$\|s\K\\{link}(\|t)$;\5 +$\\{link}(\|t)\K\|q$;\5 +$\|q\K\|t$;\6 +\&{end};\2\2\6 +\4\\{done}: \37$\\{link}(\|r)\K\\{sentinel}$\par +\U344.\fi + +\M346. The \\{unsorted} edges of a row are merged into the \\{sorted} ones by +a subroutine called \\{sort\_edges}. It uses simple insertion sort, +followed by a merge, because the unsorted list is supposedly quite short. +However, the unsorted list is assumed to be nonempty. + +\Y\P\4\&{procedure}\1\ \37$\\{sort\_edges}(\|h:\\{pointer})$;\C{\|h is a row +header}\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37\|k: \37\\{halfword};\C{key register that we compare to $\\{info}(% +\|q)$}\6 +$\|p,\39\|q,\39\|r,\39\|s$: \37\\{pointer};\2\6 +\&{begin} \37$\|r\K\\{unsorted}(\|h)$;\5 +$\\{unsorted}(\|h)\K\\{null}$;\5 +$\|p\K\\{link}(\|r)$;\5 +$\\{link}(\|r)\K\\{sentinel}$;\5 +$\\{link}(\\{temp\_head})\K\|r$;\6 +\&{while} $\|p>\\{void}$ \1\&{do}\C{sort node \|p into the list that starts at % +\\{temp\_head}}\6 +\&{begin} \37$\|k\K\\{info}(\|p)$;\5 +$\|q\K\\{temp\_head}$;\6 +\1\&{repeat} \37$\|r\K\|q$;\5 +$\|q\K\\{link}(\|r)$;\6 +\4\&{until}\5 +$\|k\L\\{info}(\|q)$;\2\6 +$\\{link}(\|r)\K\|p$;\5 +$\|r\K\\{link}(\|p)$;\5 +$\\{link}(\|p)\K\|q$;\5 +$\|p\K\|r$;\6 +\&{end};\2\6 +\X347:Merge the \\{temp\_head} list into $\\{sorted}(\|h)$\X;\6 +\&{end};\par +\fi + +\M347. In this step we use the fact that $\\{sorted}(\|h)=\\{link}(\\{sorted% +\_loc}(\|h))$. + +\Y\P$\4\X347:Merge the \\{temp\_head} list into $\\{sorted}(\|h)$\X\S$\6 +\&{begin} \37$\|r\K\\{sorted\_loc}(\|h)$;\5 +$\|q\K\\{link}(\|r)$;\5 +$\|p\K\\{link}(\\{temp\_head})$;\6 +\~ \1\&{loop}\ \&{begin} \37$\|k\K\\{info}(\|p)$;\6 +\&{while} $\|k>\\{info}(\|q)$ \1\&{do}\6 +\&{begin} \37$\|r\K\|q$;\5 +$\|q\K\\{link}(\|r)$;\6 +\&{end};\2\6 +$\\{link}(\|r)\K\|p$;\5 +$\|s\K\\{link}(\|p)$;\5 +$\\{link}(\|p)\K\|q$;\6 +\&{if} $\|s=\\{sentinel}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\|r\K\|p$;\5 +$\|p\K\|s$;\6 +\&{end};\2\6 +\4\\{done}: \37\&{end}\par +\U346.\fi + +\M348. The \\{cull\_edges} procedure ``optimizes'' an edge structure by making +all +the pixel weights either \\{w\_out} or~\\{w\_in}. The weight will be~\\{w\_in} +after the +operation if and only if it was in the closed interval $[\\{w\_lo},\\{w\_hi}]$ +before, where $\\{w\_lo}\L\\{w\_hi}$. Either \\{w\_out} or \\{w\_in} is zero, +while the other is +$\pm1$, $\pm2$, or $\pm3$. The parameters will be such that zero-weight +pixels will remain of weight zero. (This is fortunate, +because there are infinitely many of them.) + +The procedure also computes the tightest possible bounds on the resulting +data, by updating \\{m\_min}, \\{m\_max}, \\{n\_min}, and~\\{n\_max}. + +\Y\P\4\&{procedure}\1\ \37$\\{cull\_edges}(\\{w\_lo},\39\\{w\_hi},\39\\{w% +\_out},\39\\{w\_in}:\\{integer})$;\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37$\|p,\39\|q,\39\|r,\39\|s$: \37\\{pointer};\C{for list +manipulation}\6 +\|w: \37\\{integer};\C{new weight after culling}\6 +\|d: \37\\{integer};\C{data register for unpacking}\6 +\|m: \37\\{integer};\C{the previous column number, including \\{m\_offset}}\6 +\\{mm}: \37\\{integer};\C{the next column number, including \\{m\_offset}}\6 +\\{ww}: \37\\{integer};\C{accumulated weight before culling}\6 +\\{prev\_w}: \37\\{integer};\C{value of \|w before column \|m}\6 +$\|n,\39\\{min\_n},\39\\{max\_n}$: \37\\{pointer};\C{current and extreme row +numbers}\6 +$\\{min\_d},\39\\{max\_d}$: \37\\{pointer};\C{extremes of the new +edge-and-weight data}\2\6 +\&{begin} \37$\\{min\_d}\K\\{max\_halfword}$;\5 +$\\{max\_d}\K\\{min\_halfword}$;\5 +$\\{min\_n}\K\\{max\_halfword}$;\5 +$\\{max\_n}\K\\{min\_halfword}$;\6 +$\|p\K\\{link}(\\{cur\_edges})$;\5 +$\|n\K\\{n\_min}(\\{cur\_edges})$;\6 +\&{while} $\|p\I\\{cur\_edges}$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{unsorted}(\|p)>\\{void}$ \1\&{then}\5 +$\\{sort\_edges}(\|p)$;\2\6 +\&{if} $\\{sorted}(\|p)\I\\{sentinel}$ \1\&{then}\5 +\X349:Cull superfluous edge-weight entries from $\\{sorted}(\|p)$\X;\2\6 +$\|p\K\\{link}(\|p)$;\5 +$\\{incr}(\|n)$;\6 +\&{end};\2\6 +\X352:Delete empty rows at the top and/or bottom; update the boundary values in +the header\X;\6 +$\\{last\_window\_time}(\\{cur\_edges})\K0$;\6 +\&{end};\par +\fi + +\M349. The entire \\{sorted} list is returned to available memory in this step; +a new list is built starting (temporarily) at \\{temp\_head}. +Since several edges can occur at the same column, we need to be looking +ahead of where the actual culling takes place. This means that it's +slightly tricky to get the iteration started and stopped. + +\Y\P$\4\X349:Cull superfluous edge-weight entries from $\\{sorted}(\|p)$\X\S$\6 +\&{begin} \37$\|r\K\\{temp\_head}$;\5 +$\|q\K\\{sorted}(\|p)$;\5 +$\\{ww}\K0$;\5 +$\|m\K1000000$;\5 +$\\{prev\_w}\K0$;\6 +\~ \1\&{loop}\ \&{begin} \37\&{if} $\|q=\\{sentinel}$ \1\&{then}\5 +$\\{mm}\K1000000$\6 +\4\&{else} \&{begin} \37$\|d\K\\{ho}(\\{info}(\|q))$;\5 +$\\{mm}\K\|d\mathbin{\&{div}}8$;\5 +$\\{ww}\K\\{ww}+(\|d\mathbin{\&{mod}}8)-\\{zero\_w}$;\6 +\&{end};\2\6 +\&{if} $\\{mm}>\|m$ \1\&{then}\6 +\&{begin} \37\X350:Insert an edge-weight for edge \|m, if the new pixel weight +has changed\X;\6 +\&{if} $\|q=\\{sentinel}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +\&{end};\2\6 +$\|m\K\\{mm}$;\6 +\&{if} $\\{ww}\G\\{w\_lo}$ \1\&{then}\6 +\&{if} $\\{ww}\L\\{w\_hi}$ \1\&{then}\5 +$\|w\K\\{w\_in}$\6 +\4\&{else} $\|w\K\\{w\_out}$\2\6 +\4\&{else} $\|w\K\\{w\_out}$;\2\6 +$\|s\K\\{link}(\|q)$;\5 +$\\{free\_avail}(\|q)$;\5 +$\|q\K\|s$;\6 +\&{end};\2\6 +\4\\{done}: \37$\\{link}(\|r)\K\\{sentinel}$;\5 +$\\{sorted}(\|p)\K\\{link}(\\{temp\_head})$;\6 +\&{if} $\|r\I\\{temp\_head}$ \1\&{then}\5 +\X351:Update the max/min amounts\X;\2\6 +\&{end}\par +\U348.\fi + +\M350. \P$\X350:Insert an edge-weight for edge \|m, if the new pixel weight has +changed\X\S$\6 +\&{if} $\|w\I\\{prev\_w}$ \1\&{then}\6 +\&{begin} \37$\|s\K\\{get\_avail}$;\5 +$\\{link}(\|r)\K\|s$;\5 +$\\{info}(\|s)\K8\ast\|m+\\{min\_halfword}+\\{zero\_w}+\|w-\\{prev\_w}$;\5 +$\|r\K\|s$;\5 +$\\{prev\_w}\K\|w$;\6 +\&{end}\2\par +\U349.\fi + +\M351. \P$\X351:Update the max/min amounts\X\S$\6 +\&{begin} \37\&{if} $\\{min\_n}=\\{max\_halfword}$ \1\&{then}\5 +$\\{min\_n}\K\|n$;\2\6 +$\\{max\_n}\K\|n$;\6 +\&{if} $\\{min\_d}>\\{info}(\\{link}(\\{temp\_head}))$ \1\&{then}\5 +$\\{min\_d}\K\\{info}(\\{link}(\\{temp\_head}))$;\2\6 +\&{if} $\\{max\_d}<\\{info}(\|r)$ \1\&{then}\5 +$\\{max\_d}\K\\{info}(\|r)$;\2\6 +\&{end}\par +\U349.\fi + +\M352. \P$\X352:Delete empty rows at the top and/or bottom; update the boundary +values in the header\X\S$\6 +\&{if} $\\{min\_n}>\\{max\_n}$ \1\&{then}\5 +\X353:Delete all the row headers\X\6 +\4\&{else} \&{begin} \37$\|n\K\\{n\_min}(\\{cur\_edges})$;\5 +$\\{n\_min}(\\{cur\_edges})\K\\{min\_n}$;\6 +\&{while} $\\{min\_n}>\|n$ \1\&{do}\6 +\&{begin} \37$\|p\K\\{link}(\\{cur\_edges})$;\5 +$\\{link}(\\{cur\_edges})\K\\{link}(\|p)$;\5 +$\\{knil}(\\{link}(\|p))\K\\{cur\_edges}$;\5 +$\\{free\_node}(\|p,\39\\{row\_node\_size})$;\5 +$\\{incr}(\|n)$;\6 +\&{end};\2\6 +$\|n\K\\{n\_max}(\\{cur\_edges})$;\5 +$\\{n\_max}(\\{cur\_edges})\K\\{max\_n}$;\5 +$\\{n\_pos}(\\{cur\_edges})\K\\{max\_n}+1$;\5 +$\\{n\_rover}(\\{cur\_edges})\K\\{cur\_edges}$;\6 +\&{while} $\\{max\_n}<\|n$ \1\&{do}\6 +\&{begin} \37$\|p\K\\{knil}(\\{cur\_edges})$;\5 +$\\{knil}(\\{cur\_edges})\K\\{knil}(\|p)$;\5 +$\\{link}(\\{knil}(\|p))\K\\{cur\_edges}$;\5 +$\\{free\_node}(\|p,\39\\{row\_node\_size})$;\5 +$\\{decr}(\|n)$;\6 +\&{end};\2\6 +$\\{m\_min}(\\{cur\_edges})\K((\\{ho}(\\{min\_d}))\mathbin{\&{div}}8)-\\{m% +\_offset}(\\{cur\_edges})+\\{zero\_field}$;\5 +$\\{m\_max}(\\{cur\_edges})\K((\\{ho}(\\{max\_d}))\mathbin{\&{div}}8)-\\{m% +\_offset}(\\{cur\_edges})+\\{zero\_field}$;\6 +\&{end}\2\par +\U348.\fi + +\M353. We get here if the edges have been entirely culled away. + +\Y\P$\4\X353:Delete all the row headers\X\S$\6 +\&{begin} \37$\|p\K\\{link}(\\{cur\_edges})$;\6 +\&{while} $\|p\I\\{cur\_edges}$ \1\&{do}\6 +\&{begin} \37$\|q\K\\{link}(\|p)$;\5 +$\\{free\_node}(\|p,\39\\{row\_node\_size})$;\5 +$\|p\K\|q$;\6 +\&{end};\2\6 +$\\{init\_edges}(\\{cur\_edges})$;\6 +\&{end}\par +\U352.\fi + +\M354. The last and most difficult routine for transforming an edge +structure---and +the most interesting one!---is \\{xy\_swap\_edges}, which interchanges the +r\^^Doles of rows and columns. Its task can be viewed as the job of +creating an edge structure that contains only horizontal edges, linked +together in columns, given an edge structure that contains only +vertical edges linked together in rows; we must do this without changing +the implied pixel weights. + +Given any two adjacent rows of an edge structure, it is not difficult to +determine the horizontal edges that lie ``between'' them: We simply look +for vertically adjacent pixels that have different weight, and insert +a horizontal edge containing the difference in weights. Every horizontal +edge determined in this way should be put into an appropriate linked +list. Since random access to these linked lists is desirable, we use +the \\{move} array to hold the list heads. If we work through the given +edge structure from top to bottom, the constructed lists will not need +to be sorted, since they will already be in order. + +The following algorithm makes use of some ideas suggested by John Hobby. +It assumes that the edge structure is non-null, i.e., that $\\{link}(\\{cur% +\_edges})\I\\{cur\_edges}$, hence $\\{m\_max}(\\{cur\_edges})\G\\{m\_min}(% +\\{cur\_edges})$. + +\Y\P\4\&{procedure}\1\ \37\\{xy\_swap\_edges};\C{interchange \|x and \|y in % +\\{cur\_edges}}\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37$\\{m\_magic},\39\\{n\_magic}$: \37\\{integer};\C{special values +that account for offsets}\6 +$\|p,\39\|q,\39\|r,\39\|s$: \37\\{pointer};\C{pointers that traverse the given +structure}\6 +\X357:Other local variables for \\{xy\_swap\_edges}\X\2\6 +\&{begin} \37\X356:Initialize the array of new edge list heads\X;\6 +\X355:Insert blank rows at the top and bottom, and set \|p to the new top row% +\X;\6 +\X365:Compute the magic offset values\X;\6 +\1\&{repeat} \37$\|q\K\\{knil}(\|p)$;\ \&{if} $\\{unsorted}(\|q)>\\{void}$ \1% +\&{then}\5 +$\\{sort\_edges}(\|q)$;\2\6 +\X358:Insert the horizontal edges defined by adjacent rows $\|p,\|q$, and +destroy row~\|p\X;\6 +$\|p\K\|q$;\5 +$\\{n\_magic}\K\\{n\_magic}-8$;\6 +\4\&{until}\5 +$\\{knil}(\|p)=\\{cur\_edges}$;\2\6 +$\\{free\_node}(\|p,\39\\{row\_node\_size})$;\C{now all original rows have been +recycled}\6 +\X364:Adjust the header to reflect the new edges\X;\6 +\&{end};\par +\fi + +\M355. Here we don't bother to keep the \\{link} entries up to date, since the +procedure looks only at the \\{knil} fields as it destroys the former +edge structure. + +\Y\P$\4\X355:Insert blank rows at the top and bottom, and set \|p to the new +top row\X\S$\6 +$\|p\K\\{get\_node}(\\{row\_node\_size})$;\5 +$\\{sorted}(\|p)\K\\{sentinel}$;\5 +$\\{unsorted}(\|p)\K\\{null}$;\6 +$\\{knil}(\|p)\K\\{cur\_edges}$;\5 +$\\{knil}(\\{link}(\\{cur\_edges}))\K\|p$;\C{the new bottom row}\6 +$\|p\K\\{get\_node}(\\{row\_node\_size})$;\5 +$\\{sorted}(\|p)\K\\{sentinel}$;\5 +$\\{knil}(\|p)\K\\{knil}(\\{cur\_edges})$;\C{the new top row}\par +\U354.\fi + +\M356. The new lists will become \\{sorted} lists later, so we initialize +empty lists to \\{sentinel}. + +\Y\P$\4\X356:Initialize the array of new edge list heads\X\S$\6 +$\\{m\_spread}\K\\{m\_max}(\\{cur\_edges})-\\{m\_min}(\\{cur\_edges})$;\C{this +is $\G0$ by assumption}\6 +\&{if} $\\{m\_spread}>\\{move\_size}$ \1\&{then}\5 +$\\{overflow}(\.{"move\ table\ size"},\39\\{move\_size})$;\2\6 +\&{for} $\|j\K0\mathrel{\&{to}}\\{m\_spread}$ \1\&{do}\5 +$\\{move}[\|j]\K\\{sentinel}$\2\par +\U354.\fi + +\M357. \P$\X357:Other local variables for \\{xy\_swap\_edges}\X\S$\6 +\4\\{m\_spread}: \37\\{integer};\C{the difference between \\{m\_max} and \\{m% +\_min}}\6 +\4$\|j,\39\\{jj}$: \37$0\to\\{move\_size}$;\C{indices into \\{move}}\6 +\4$\|m,\39\\{mm}$: \37\\{integer};\C{\|m values at vertical edges}\6 +\4$\\{pd},\39\\{rd}$: \37\\{integer};\C{data fields from edge-and-weight nodes}% +\6 +\4$\\{pm},\39\\{rm}$: \37\\{integer};\C{\|m values from edge-and-weight nodes}\6 +\4\|w: \37\\{integer};\C{the difference in accumulated weight}\6 +\4\\{ww}: \37\\{integer};\C{as much of \|w that can be stored in a single node}% +\6 +\4\\{dw}: \37\\{integer};\C{an increment to be added to \|w}\par +\A363. +\U354.\fi + +\M358. At the point where we test $\|w\I0$, variable \|w contains +the accumulated weight from edges already passed in +row~\|p minus the accumulated weight from edges already passed in row~\|q. + +\Y\P$\4\X358:Insert the horizontal edges defined by adjacent rows $\|p,\|q$, +and destroy row~\|p\X\S$\6 +$\|r\K\\{sorted}(\|p)$;\5 +$\\{free\_node}(\|p,\39\\{row\_node\_size})$;\5 +$\|p\K\|r$;\6 +$\\{pd}\K\\{ho}(\\{info}(\|p))$;\5 +$\\{pm}\K\\{pd}\mathbin{\&{div}}8$;\6 +$\|r\K\\{sorted}(\|q)$;\5 +$\\{rd}\K\\{ho}(\\{info}(\|r))$;\5 +$\\{rm}\K\\{rd}\mathbin{\&{div}}8$;\5 +$\|w\K0$;\6 +\~ \1\&{loop}\ \&{begin} \37\&{if} $\\{pm}<\\{rm}$ \1\&{then}\5 +$\\{mm}\K\\{pm}$\ \&{else} $\\{mm}\K\\{rm}$;\2\6 +\&{if} $\|w\I0$ \1\&{then}\5 +\X362:Insert horizontal edges of weight \|w between \|m and~\\{mm}\X;\2\6 +\&{if} $\\{pd}<\\{rd}$ \1\&{then}\6 +\&{begin} \37$\\{dw}\K(\\{pd}\mathbin{\&{mod}}8)-\\{zero\_w}$;\5 +\X360:Advance pointer \|p to the next vertical edge, after destroying the +previous one\X;\6 +\&{end}\6 +\4\&{else} \&{begin} \37\&{if} $\|r=\\{sentinel}$ \1\&{then}\5 +\&{goto} \37\\{done};\C{$\\{rd}=\\{pd}=\\{ho}(\\{max\_halfword})$}\2\6 +$\\{dw}\K-((\\{rd}\mathbin{\&{mod}}8)-\\{zero\_w})$;\5 +\X359:Advance pointer \|r to the next vertical edge\X;\6 +\&{end};\2\6 +$\|m\K\\{mm}$;\5 +$\|w\K\|w+\\{dw}$;\6 +\&{end};\2\6 +\4\\{done}: \37\par +\U354.\fi + +\M359. \P$\X359:Advance pointer \|r to the next vertical edge\X\S$\6 +$\|r\K\\{link}(\|r)$;\5 +$\\{rd}\K\\{ho}(\\{info}(\|r))$;\5 +$\\{rm}\K\\{rd}\mathbin{\&{div}}8$\par +\U358.\fi + +\M360. \P$\X360:Advance pointer \|p to the next vertical edge, after destroying +the previous one\X\S$\6 +$\|s\K\\{link}(\|p)$;\5 +$\\{free\_avail}(\|p)$;\5 +$\|p\K\|s$;\5 +$\\{pd}\K\\{ho}(\\{info}(\|p))$;\5 +$\\{pm}\K\\{pd}\mathbin{\&{div}}8$\par +\U358.\fi + +\M361. Certain ``magic'' values are needed to make the following code work, +because of the various offsets in our data structure. For now, let's not +worry about their precise values; we shall compute \\{m\_magic} and \\{n% +\_magic} +later, after we see what the code looks like. + +\fi + +\M362. \P$\X362:Insert horizontal edges of weight \|w between \|m and~\\{mm}\X% +\S$\6 +\&{if} $\|m\I\\{mm}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{mm}-\\{m\_magic}\G\\{move\_size}$ \1\&{then}\5 +$\\{confusion}(\.{"xy"})$;\2\6 +$\\{extras}\K(\\{abs}(\|w)-1)\mathbin{\&{div}}3$;\6 +\&{if} $\\{extras}>0$ \1\&{then}\6 +\&{begin} \37\&{if} $\|w>0$ \1\&{then}\5 +$\\{xw}\K+3$\ \&{else} $\\{xw}\K-3$;\2\6 +$\\{ww}\K\|w-\\{extras}\ast\\{xw}$;\6 +\&{end}\6 +\4\&{else} $\\{ww}\K\|w$;\2\6 +\1\&{repeat} \37$\|j\K\|m-\\{m\_magic}$;\6 +\&{for} $\|k\K1\mathrel{\&{to}}\\{extras}$ \1\&{do}\6 +\&{begin} \37$\|s\K\\{get\_avail}$;\5 +$\\{info}(\|s)\K\\{n\_magic}+\\{xw}$;\5 +$\\{link}(\|s)\K\\{move}[\|j]$;\5 +$\\{move}[\|j]\K\|s$;\6 +\&{end};\2\6 +$\|s\K\\{get\_avail}$;\5 +$\\{info}(\|s)\K\\{n\_magic}+\\{ww}$;\5 +$\\{link}(\|s)\K\\{move}[\|j]$;\5 +$\\{move}[\|j]\K\|s$;\6 +$\\{incr}(\|m)$;\6 +\4\&{until}\5 +$\|m=\\{mm}$;\2\6 +\&{end}\2\par +\U358.\fi + +\M363. \P$\X357:Other local variables for \\{xy\_swap\_edges}\X\mathrel{+}\S$\6 +\4\\{extras}: \37\\{integer};\C{the number of additional nodes to make weights +$>3$}\6 +\4\\{xw}: \37$-3\to3$;\C{the additional weight in extra nodes}\6 +\4\|k: \37\\{integer};\C{loop counter for inserting extra nodes}\par +\fi + +\M364. At the beginning of this step, $\\{move}[\\{m\_spread}]=\\{sentinel}$, +because no +horizontal edges will extend to the right of column $\\{m\_max}(\\{cur% +\_edges})$. + +\Y\P$\4\X364:Adjust the header to reflect the new edges\X\S$\6 +$\\{move}[\\{m\_spread}]\K0$;\5 +$\|j\K0$;\6 +\&{while} $\\{move}[\|j]=\\{sentinel}$ \1\&{do}\5 +$\\{incr}(\|j)$;\2\6 +\&{if} $\|j=\\{m\_spread}$ \1\&{then}\5 +$\\{init\_edges}(\\{cur\_edges})$\C{all edge weights are zero}\6 +\4\&{else} \&{begin} \37$\\{mm}\K\\{m\_min}(\\{cur\_edges})$;\5 +$\\{m\_min}(\\{cur\_edges})\K\\{n\_min}(\\{cur\_edges})$;\5 +$\\{m\_max}(\\{cur\_edges})\K\\{n\_max}(\\{cur\_edges})+1$;\5 +$\\{m\_offset}(\\{cur\_edges})\K\\{zero\_field}$;\5 +$\\{jj}\K\\{m\_spread}-1$;\6 +\&{while} $\\{move}[\\{jj}]=\\{sentinel}$ \1\&{do}\5 +$\\{decr}(\\{jj})$;\2\6 +$\\{n\_min}(\\{cur\_edges})\K\|j+\\{mm}$;\5 +$\\{n\_max}(\\{cur\_edges})\K\\{jj}+\\{mm}$;\5 +$\|q\K\\{cur\_edges}$;\6 +\1\&{repeat} \37$\|p\K\\{get\_node}(\\{row\_node\_size})$;\5 +$\\{link}(\|q)\K\|p$;\5 +$\\{knil}(\|p)\K\|q$;\5 +$\\{sorted}(\|p)\K\\{move}[\|j]$;\5 +$\\{unsorted}(\|p)\K\\{null}$;\5 +$\\{incr}(\|j)$;\5 +$\|q\K\|p$;\6 +\4\&{until}\5 +$\|j>\\{jj}$;\2\6 +$\\{link}(\|q)\K\\{cur\_edges}$;\5 +$\\{knil}(\\{cur\_edges})\K\|q$;\5 +$\\{n\_pos}(\\{cur\_edges})\K\\{n\_max}(\\{cur\_edges})+1$;\5 +$\\{n\_rover}(\\{cur\_edges})\K\\{cur\_edges}$;\5 +$\\{last\_window\_time}(\\{cur\_edges})\K0$;\6 +\&{end};\2\par +\U354.\fi + +\M365. The values of \\{m\_magic} and \\{n\_magic} can be worked out by trying +the +code above on a small example; if they work correctly in simple cases, +they should work in general. + +\Y\P$\4\X365:Compute the magic offset values\X\S$\6 +$\\{m\_magic}\K\\{m\_min}(\\{cur\_edges})+\\{m\_offset}(\\{cur\_edges})-\\{zero% +\_field}$;\5 +$\\{n\_magic}\K8\ast\\{n\_max}(\\{cur\_edges})+8+\\{zero\_w}+\\{min\_halfword}$% +\par +\U354.\fi + +\M366. Now let's look at the subroutine that merges the edges from a given +edge structure into \\{cur\_edges}. The given edge structure loses all its +edges. + +\Y\P\4\&{procedure}\1\ \37$\\{merge\_edges}(\|h:\\{pointer})$;\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37$\|p,\39\|q,\39\|r,\39\\{pp},\39\\{qq},\39\\{rr}$: \37\\{pointer};% +\C{list manipulation registers}\6 +\|n: \37\\{integer};\C{row number}\6 +\|k: \37\\{halfword};\C{key register that we compare to $\\{info}(\|q)$}\6 +\\{delta}: \37\\{integer};\C{change to the edge/weight data}\2\6 +\&{begin} \37\&{if} $\\{link}(\|h)\I\|h$ \1\&{then}\6 +\&{begin} \37\&{if} $(\\{m\_min}(\|h)<\\{m\_min}(\\{cur\_edges}))\V(\\{m\_max}(% +\|h)>\\{m\_max}(\\{cur\_edges}))\V\30(\\{n\_min}(\|h)<\\{n\_min}(\\{cur% +\_edges}))\V(\\{n\_max}(\|h)>\\{n\_max}(\\{cur\_edges}))$ \1\&{then}\5 +$\\{edge\_prep}(\\{m\_min}(\|h)-\\{zero\_field},\39\\{m\_max}(\|h)-\\{zero% +\_field},\39\\{n\_min}(\|h)-\\{zero\_field},\39\\{n\_max}(\|h)-\\{zero% +\_field}+1)$;\2\6 +\&{if} $\\{m\_offset}(\|h)\I\\{m\_offset}(\\{cur\_edges})$ \1\&{then}\5 +\X367:Adjust the data of \|h to account for a difference of offsets\X;\2\6 +$\|n\K\\{n\_min}(\\{cur\_edges})$;\5 +$\|p\K\\{link}(\\{cur\_edges})$;\5 +$\\{pp}\K\\{link}(\|h)$;\6 +\&{while} $\|n<\\{n\_min}(\|h)$ \1\&{do}\6 +\&{begin} \37$\\{incr}(\|n)$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +\1\&{repeat} \37\X368:Merge row \\{pp} into row \|p\X;\6 +$\\{pp}\K\\{link}(\\{pp})$;\5 +$\|p\K\\{link}(\|p)$;\6 +\4\&{until}\5 +$\\{pp}=\|h$;\2\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M367. \P$\X367:Adjust the data of \|h to account for a difference of offsets\X% +\S$\6 +\&{begin} \37$\\{pp}\K\\{link}(\|h)$;\5 +$\\{delta}\K8\ast(\\{m\_offset}(\\{cur\_edges})-\\{m\_offset}(\|h))$;\6 +\1\&{repeat} \37$\\{qq}\K\\{sorted}(\\{pp})$;\6 +\&{while} $\\{qq}\I\\{sentinel}$ \1\&{do}\6 +\&{begin} \37$\\{info}(\\{qq})\K\\{info}(\\{qq})+\\{delta}$;\5 +$\\{qq}\K\\{link}(\\{qq})$;\6 +\&{end};\2\6 +$\\{qq}\K\\{unsorted}(\\{pp})$;\6 +\&{while} $\\{qq}>\\{void}$ \1\&{do}\6 +\&{begin} \37$\\{info}(\\{qq})\K\\{info}(\\{qq})+\\{delta}$;\5 +$\\{qq}\K\\{link}(\\{qq})$;\6 +\&{end};\2\6 +$\\{pp}\K\\{link}(\\{pp})$;\6 +\4\&{until}\5 +$\\{pp}=\|h$;\2\6 +\&{end}\par +\U366.\fi + +\M368. The \\{sorted} and \\{unsorted} lists are merged separately. After this +step, row~\\{pp} will have no edges remaining, since they will all have +been merged into row~\|p. + +\Y\P$\4\X368:Merge row \\{pp} into row \|p\X\S$\6 +$\\{qq}\K\\{unsorted}(\\{pp})$;\6 +\&{if} $\\{qq}>\\{void}$ \1\&{then}\6 +\&{if} $\\{unsorted}(\|p)\L\\{void}$ \1\&{then}\5 +$\\{unsorted}(\|p)\K\\{qq}$\6 +\4\&{else} \&{begin} \37\&{while} $\\{link}(\\{qq})>\\{void}$ \1\&{do}\5 +$\\{qq}\K\\{link}(\\{qq})$;\2\6 +$\\{link}(\\{qq})\K\\{unsorted}(\|p)$;\5 +$\\{unsorted}(\|p)\K\\{unsorted}(\\{pp})$;\6 +\&{end};\2\2\6 +$\\{unsorted}(\\{pp})\K\\{null}$;\5 +$\\{qq}\K\\{sorted}(\\{pp})$;\6 +\&{if} $\\{qq}\I\\{sentinel}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{unsorted}(\|p)=\\{void}$ \1\&{then}\5 +$\\{unsorted}(\|p)\K\\{null}$;\2\6 +$\\{sorted}(\\{pp})\K\\{sentinel}$;\5 +$\|r\K\\{sorted\_loc}(\|p)$;\5 +$\|q\K\\{link}(\|r)$;\C{$\|q=\\{sorted}(\|p)$}\6 +\&{if} $\|q=\\{sentinel}$ \1\&{then}\5 +$\\{sorted}(\|p)\K\\{qq}$\6 +\4\&{else} \~ \1\&{loop}\ \&{begin} \37$\|k\K\\{info}(\\{qq})$;\6 +\&{while} $\|k>\\{info}(\|q)$ \1\&{do}\6 +\&{begin} \37$\|r\K\|q$;\5 +$\|q\K\\{link}(\|r)$;\6 +\&{end};\2\6 +$\\{link}(\|r)\K\\{qq}$;\5 +$\\{rr}\K\\{link}(\\{qq})$;\5 +$\\{link}(\\{qq})\K\|q$;\6 +\&{if} $\\{rr}=\\{sentinel}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\|r\K\\{qq}$;\5 +$\\{qq}\K\\{rr}$;\6 +\&{end};\2\2\6 +\&{end};\2\6 +\4\\{done}: \37\par +\U366.\fi + +\M369. The \\{total\_weight} routine computes the total of all pixel weights +in a given edge structure. It's not difficult to prove that this is +the sum of $(-w)$ times $x$ taken over all edges, +where $w$ and~$x$ are the weight and $x$~coordinates stored in an edge. +It's not necessary to worry that this quantity will overflow the +size of an \\{integer} register, because it will be less than~$2^{31}$ +unless the edge structure has more than 174,762 edges. However, we had +better not try to compute it as a \\{scaled} integer, because a total +weight of almost $12\times 2^{12}$ can be produced by only four edges. + +\Y\P\4\&{function}\1\ \37$\\{total\_weight}(\|h:\\{pointer})$: \37\\{integer};% +\C{\|h is an edge header}\6 +\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{variables that traverse the given +structure}\6 +\|n: \37\\{integer};\C{accumulated total so far}\6 +\|m: \37$0\to65535$;\C{packed $x$ and $w$ values, including offsets}\2\6 +\&{begin} \37$\|n\K0$;\5 +$\|p\K\\{link}(\|h)$;\6 +\&{while} $\|p\I\|h$ \1\&{do}\6 +\&{begin} \37$\|q\K\\{sorted}(\|p)$;\6 +\&{while} $\|q\I\\{sentinel}$ \1\&{do}\5 +\X370:Add the contribution of node \|q to the total weight, and set $\|q\K% +\\{link}(\|q)$\X;\2\6 +$\|q\K\\{unsorted}(\|p)$;\6 +\&{while} $\|q>\\{void}$ \1\&{do}\5 +\X370:Add the contribution of node \|q to the total weight, and set $\|q\K% +\\{link}(\|q)$\X;\2\6 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +$\\{total\_weight}\K\|n$;\6 +\&{end};\par +\fi + +\M370. It's not necessary to add the offsets to the $x$ coordinates, because +an entire edge structure can be shifted without affecting its total weight. +Similarly, we don't need to subtract \\{zero\_field}. + +\Y\P$\4\X370:Add the contribution of node \|q to the total weight, and set $\|q% +\K\\{link}(\|q)$\X\S$\6 +\&{begin} \37$\|m\K\\{ho}(\\{info}(\|q))$;\5 +$\|n\K\|n-((\|m\mathbin{\&{mod}}8)-\\{zero\_w})\ast(\|m\mathbin{\&{div}}8)$;\5 +$\|q\K\\{link}(\|q)$;\6 +\&{end}\par +\Us369\ET369.\fi + +\M371. So far we've done lots of things to edge structures assuming that +edges are actually present, but we haven't seen how edges get created +in the first place. Let's turn now to the problem of generating new edges. + +\MF\ will display new edges as they are being computed, if \\{tracing\_edges} +is positive. In order to keep such data reasonably compact, only the +points at which the path makes a $90^\circ$ or $180^\circ$ turn are listed. + +The tracing algorithm must remember some past history in order to suppress +unnecessary data. Three variables \\{trace\_x}, \\{trace\_y}, and \\{trace\_yy} +provide this history: The last coordinates printed were $(\\{trace\_x},\\{trace% +\_y})$, +and the previous edge traced ended at $(\\{trace\_x},\\{trace\_yy})$. Before +anything +at all has been traced, $\\{trace\_x}=-4096$. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{trace\_x}: \37\\{integer};\C{$x$~coordinate most recently shown in a +trace}\6 +\4\\{trace\_y}: \37\\{integer};\C{$y$~coordinate most recently shown in a +trace}\6 +\4\\{trace\_yy}: \37\\{integer};\C{$y$~coordinate most recently encountered}\par +\fi + +\M372. Edge tracing is initiated by the \\{begin\_edge\_tracing} routine, +continued by the \\{trace\_a\_corner} routine, and terminated by the +\\{end\_edge\_tracing} routine. + +\Y\P\4\&{procedure}\1\ \37\\{begin\_edge\_tracing};\2\6 +\&{begin} \37$\\{print\_diagnostic}(\.{"Tracing\ edges"},\39\.{""},\39% +\\{true})$;\5 +$\\{print}(\.{"\ (weight\ "})$;\5 +$\\{print\_int}(\\{cur\_wt})$;\5 +$\\{print\_char}(\.{")"})$;\5 +$\\{trace\_x}\K-4096$;\6 +\&{end};\7 +\4\&{procedure}\1\ \37\\{trace\_a\_corner};\2\6 +\&{begin} \37\&{if} $\\{file\_offset}>\\{max\_print\_line}-13$ \1\&{then}\5 +$\\{print\_nl}(\.{""})$;\2\6 +$\\{print\_char}(\.{"("})$;\5 +$\\{print\_int}(\\{trace\_x})$;\5 +$\\{print\_char}(\.{","})$;\5 +$\\{print\_int}(\\{trace\_yy})$;\5 +$\\{print\_char}(\.{")"})$;\5 +$\\{trace\_y}\K\\{trace\_yy}$;\6 +\&{end};\7 +\4\&{procedure}\1\ \37\\{end\_edge\_tracing};\2\6 +\&{begin} \37\&{if} $\\{trace\_x}=-4096$ \1\&{then}\5 +$\\{print\_nl}(\.{"(No\ new\ edges\ added.)"})$\6 +\4\&{else} \&{begin} \37\\{trace\_a\_corner};\5 +$\\{print\_char}(\.{"."})$;\6 +\&{end};\2\6 +$\\{end\_diagnostic}(\\{true})$;\6 +\&{end};\par +\fi + +\M373. Just after a new edge weight has been put into the \\{info} field of +node~\|r, in row~\|n, the following routine continues an ongoing trace. + +\Y\P\4\&{procedure}\1\ \37$\\{trace\_new\_edge}(\|r:\\{pointer};\,\35\|n:% +\\{integer})$;\6 +\4\&{var} \37\|d: \37\\{integer};\C{temporary data register}\6 +\|w: \37$-3\to3$;\C{weight associated with an edge transition}\6 +$\|m,\39\\{n0},\39\\{n1}$: \37\\{integer};\C{column and row numbers}\2\6 +\&{begin} \37$\|d\K\\{ho}(\\{info}(\|r))$;\5 +$\|w\K(\|d\mathbin{\&{mod}}8)-\\{zero\_w}$;\5 +$\|m\K(\|d\mathbin{\&{div}}8)-\\{m\_offset}(\\{cur\_edges})$;\6 +\&{if} $\|w=\\{cur\_wt}$ \1\&{then}\6 +\&{begin} \37$\\{n0}\K\|n+1$;\5 +$\\{n1}\K\|n$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{n0}\K\|n$;\5 +$\\{n1}\K\|n+1$;\6 +\&{end};\C{the edges run from $(\|m,\\{n0})$ to $(\|m,\\{n1})$}\2\6 +\&{if} $\|m\I\\{trace\_x}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{trace\_x}=-4096$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{""})$;\5 +$\\{trace\_yy}\K\\{n0}$;\6 +\&{end}\6 +\4\&{else} \&{if} $\\{trace\_yy}\I\\{n0}$ \1\&{then}\5 +$\\{print\_char}(\.{"?"})$\C{shouldn't happen}\6 +\4\&{else} \\{trace\_a\_corner};\2\2\6 +$\\{trace\_x}\K\|m$;\5 +\\{trace\_a\_corner};\6 +\&{end}\6 +\4\&{else} \&{begin} \37\&{if} $\\{n0}\I\\{trace\_yy}$ \1\&{then}\5 +$\\{print\_char}(\.{"!"})$;\C{shouldn't happen}\2\6 +\&{if} $((\\{n0}<\\{n1})\W(\\{trace\_y}>\\{trace\_yy}))\V((\\{n0}>\\{n1})\W(% +\\{trace\_y}<\\{trace\_yy}))$ \1\&{then}\5 +\\{trace\_a\_corner};\2\6 +\&{end};\2\6 +$\\{trace\_yy}\K\\{n1}$;\6 +\&{end};\par +\fi + +\M374. One way to put new edge weights into an edge structure is to use the +following routine, which simply draws a straight line from $(\\{x0},\\{y0})$ to +$(\\{x1},\\{y1})$. More precisely, it introduces weights for the edges of the +discrete path $\bigl(\lfloor t[x_0,x_1]+{1\over2}+\epsilon\rfloor, +\lfloor t[y_0,y_1]+{1\over2}+\epsilon\delta\rfloor\bigr)$, +as $t$ varies from 0 to~1, where $\epsilon$ and $\delta$ are extremely small +positive numbers. + +The structure header is assumed to be \\{cur\_edges}; downward edge weights +will be \\{cur\_wt}, while upward ones will be $-\\{cur\_wt}$. + +Of course, this subroutine will be called only in connection with others +that eventually draw a complete cycle, so that the sum of the edge weights +in each row will be zero whenever the row is displayed. + +\Y\P\4\&{procedure}\1\ \37$\\{line\_edges}(\\{x0},\39\\{y0},\39\\{x1},\39% +\\{y1}:\\{scaled})$;\6 +\4\&{label} \37$\\{done},\39\\{done1}$;\6 +\4\&{var} \37$\\{m0},\39\\{n0},\39\\{m1},\39\\{n1}$: \37\\{integer};\C{rounded +and unscaled coordinates}\6 +$\\{delx},\39\\{dely}$: \37\\{scaled};\C{the coordinate differences of the +line}\6 +\\{yt}: \37\\{scaled};\C{smallest \|y coordinate that rounds the same as % +\\{y0}}\6 +\\{tx}: \37\\{scaled};\C{tentative change in \|x}\6 +$\|p,\39\|r$: \37\\{pointer};\C{list manipulation registers}\6 +\\{base}: \37\\{integer};\C{amount added to edge-and-weight data}\6 +\|n: \37\\{integer};\C{current row number}\2\6 +\&{begin} \37$\\{n0}\K\\{round\_unscaled}(\\{y0})$;\5 +$\\{n1}\K\\{round\_unscaled}(\\{y1})$;\6 +\&{if} $\\{n0}\I\\{n1}$ \1\&{then}\6 +\&{begin} \37$\\{m0}\K\\{round\_unscaled}(\\{x0})$;\5 +$\\{m1}\K\\{round\_unscaled}(\\{x1})$;\5 +$\\{delx}\K\\{x1}-\\{x0}$;\5 +$\\{dely}\K\\{y1}-\\{y0}$;\5 +$\\{yt}\K\\{n0}\ast\\{unity}-\\{half\_unit}$;\5 +$\\{y0}\K\\{y0}-\\{yt}$;\5 +$\\{y1}\K\\{y1}-\\{yt}$;\6 +\&{if} $\\{n0}<\\{n1}$ \1\&{then}\5 +\X375:Insert upward edges for a line\X\6 +\4\&{else} \X376:Insert downward edges for a line\X;\2\6 +$\\{n\_rover}(\\{cur\_edges})\K\|p$;\5 +$\\{n\_pos}(\\{cur\_edges})\K\|n+\\{zero\_field}$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M375. Here we are careful to cancel any effect of rounding error. + +\Y\P$\4\X375:Insert upward edges for a line\X\S$\6 +\&{begin} \37$\\{base}\K8\ast\\{m\_offset}(\\{cur\_edges})+\\{min\_halfword}+% +\\{zero\_w}-\\{cur\_wt}$;\6 +\&{if} $\\{m0}\L\\{m1}$ \1\&{then}\5 +$\\{edge\_prep}(\\{m0},\39\\{m1},\39\\{n0},\39\\{n1})$\ \&{else} $\\{edge% +\_prep}(\\{m1},\39\\{m0},\39\\{n0},\39\\{n1})$;\2\6 +\X377:Move to row \\{n0}, pointed to by \|p\X;\6 +$\\{y0}\K\\{unity}-\\{y0}$;\6 +\~ \1\&{loop}\ \&{begin} \37$\|r\K\\{get\_avail}$;\5 +$\\{link}(\|r)\K\\{unsorted}(\|p)$;\5 +$\\{unsorted}(\|p)\K\|r$;\6 +$\\{tx}\K\\{take\_fraction}(\\{delx},\39\\{make\_fraction}(\\{y0},\39% +\\{dely}))$;\6 +\&{if} $\\{ab\_vs\_cd}(\\{delx},\39\\{y0},\39\\{dely},\39\\{tx})<0$ \1\&{then}\5 +$\\{decr}(\\{tx})$;\C{now $\\{tx}=\lfloor\\{y0}\cdot\\{delx}/\\{dely}\rfloor$}% +\2\6 +$\\{info}(\|r)\K8\ast\\{round\_unscaled}(\\{x0}+\\{tx})+\\{base}$;\6 +$\\{y1}\K\\{y1}-\\{unity}$;\6 +\&{if} $\\{internal}[\\{tracing\_edges}]>0$ \1\&{then}\5 +$\\{trace\_new\_edge}(\|r,\39\|n)$;\2\6 +\&{if} $\\{y1}<\\{unity}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\|p\K\\{link}(\|p)$;\5 +$\\{y0}\K\\{y0}+\\{unity}$;\5 +$\\{incr}(\|n)$;\6 +\&{end};\2\6 +\4\\{done}: \37\&{end}\par +\U374.\fi + +\M376. \P$\X376:Insert downward edges for a line\X\S$\6 +\&{begin} \37$\\{base}\K8\ast\\{m\_offset}(\\{cur\_edges})+\\{min\_halfword}+% +\\{zero\_w}+\\{cur\_wt}$;\6 +\&{if} $\\{m0}\L\\{m1}$ \1\&{then}\5 +$\\{edge\_prep}(\\{m0},\39\\{m1},\39\\{n1},\39\\{n0})$\ \&{else} $\\{edge% +\_prep}(\\{m1},\39\\{m0},\39\\{n1},\39\\{n0})$;\2\6 +$\\{decr}(\\{n0})$;\5 +\X377:Move to row \\{n0}, pointed to by \|p\X;\6 +\~ \1\&{loop}\ \&{begin} \37$\|r\K\\{get\_avail}$;\5 +$\\{link}(\|r)\K\\{unsorted}(\|p)$;\5 +$\\{unsorted}(\|p)\K\|r$;\6 +$\\{tx}\K\\{take\_fraction}(\\{delx},\39\\{make\_fraction}(\\{y0},\39% +\\{dely}))$;\6 +\&{if} $\\{ab\_vs\_cd}(\\{delx},\39\\{y0},\39\\{dely},\39\\{tx})<0$ \1\&{then}\5 +$\\{incr}(\\{tx})$;\C{now $\\{tx}=\lceil\\{y0}\cdot\\{delx}/\\{dely}\rceil$, +since $\\{dely}<0$}\2\6 +$\\{info}(\|r)\K8\ast\\{round\_unscaled}(\\{x0}-\\{tx})+\\{base}$;\6 +$\\{y1}\K\\{y1}+\\{unity}$;\6 +\&{if} $\\{internal}[\\{tracing\_edges}]>0$ \1\&{then}\5 +$\\{trace\_new\_edge}(\|r,\39\|n)$;\2\6 +\&{if} $\\{y1}\G0$ \1\&{then}\5 +\&{goto} \37\\{done1};\2\6 +$\|p\K\\{knil}(\|p)$;\5 +$\\{y0}\K\\{y0}+\\{unity}$;\5 +$\\{decr}(\|n)$;\6 +\&{end};\2\6 +\4\\{done1}: \37\&{end}\par +\U374.\fi + +\M377. \P$\X377:Move to row \\{n0}, pointed to by \|p\X\S$\6 +$\|n\K\\{n\_pos}(\\{cur\_edges})-\\{zero\_field}$;\5 +$\|p\K\\{n\_rover}(\\{cur\_edges})$;\6 +\&{if} $\|n\I\\{n0}$ \1\&{then}\6 +\&{if} $\|n<\\{n0}$ \1\&{then}\6 +\1\&{repeat} \37$\\{incr}(\|n)$;\5 +$\|p\K\\{link}(\|p)$;\6 +\4\&{until}\5 +$\|n=\\{n0}$\2\6 +\4\&{else} \1\&{repeat} \37$\\{decr}(\|n)$;\5 +$\|p\K\\{knil}(\|p)$;\6 +\4\&{until}\5 +$\|n=\\{n0}$\2\2\2\par +\Us375, 376, 381, 382, 383\ETs384.\fi + +\M378. \MF\ inserts most of its edges into edge structures via the +\\{move\_to\_edges} subroutine, which uses the data stored in the \\{move} +array +to specify a sequence of ``rook moves.'' The starting point $(\\{m0},\\{n0})$ +and finishing point $(\\{m1},\\{n1})$ of these moves, as seen from the +standpoint +of the first octant, are supplied as parameters; the moves should, however, +be rotated into a given octant. (We're going to study octant +transformations in great detail later; the reader may wish to come back to +this part of the program after mastering the mysteries of octants.) + +The rook moves themselves are defined as follows, from a \\{first\_octant} +point of view: ``Go right $\\{move}[\|k]$ steps, then go up one, for $0\L\|k<% +\\{n1}-\\{n0}$; +then go right $\\{move}[\\{n1}-\\{n0}]$ steps and stop.'' The sum of $\\{move}[% +\|k]$ +for $0\L\|k\L\\{n1}-\\{n0}$ will be equal to $\\{m1}-\\{m0}$. + +As in the \\{line\_edges} routine, we use $+\\{cur\_wt}$ as the weight of +all downward edges and $-\\{cur\_wt}$ as the weight of all upward edges, +after the moves have been rotated to the proper octant direction. + +There are two main cases to consider: \\{fast\_case} is for moves that +travel in the direction of octants 1, 4, 5, and~8, while \\{slow\_case} +is for moves that travel toward octants 2, 3, 6, and~7. The latter directions +are comparatively cumbersome because they generate more upward or downward +edges; a curve that travels horizontally doesn't produce any edges at all, +but a curve that travels vertically touches lots of rows. + +\Y\P\D \37$\\{fast\_case\_up}=60$\C{for octants 1 and 4}\par +\P\D \37$\\{fast\_case\_down}=61$\C{for octants 5 and 8}\par +\P\D \37$\\{slow\_case\_up}=62$\C{for octants 2 and 3}\par +\P\D \37$\\{slow\_case\_down}=63$\C{for octants 6 and 7}\par +\Y\P\4\&{procedure}\1\ \37$\\{move\_to\_edges}(\\{m0},\39\\{n0},\39\\{m1},\39% +\\{n1}:\\{integer})$;\6 +\4\&{label} \37$\\{fast\_case\_up},\39\\{fast\_case\_down},\39\\{slow\_case% +\_up},\39\\{slow\_case\_down},\39\\{done}$;\6 +\4\&{var} \37\\{delta}: \37$0\to\\{move\_size}$;\C{extent of \\{move} data}\6 +\|k: \37$0\to\\{move\_size}$;\C{index into \\{move}}\6 +$\|p,\39\|r$: \37\\{pointer};\C{list manipulation registers}\6 +\\{dx}: \37\\{integer};\C{change in edge-weight \\{info} when \|x changes by 1}% +\6 +\\{edge\_and\_weight}: \37\\{integer};\C{\\{info} to insert}\6 +\|j: \37\\{integer};\C{number of consecutive vertical moves}\6 +\|n: \37\\{integer};\C{the current row pointed to by \|p}\2\6 +\&{debug} \37\\{sum}: \37\\{integer};\ \&{gubed}\6 +\&{begin} \37$\\{delta}\K\\{n1}-\\{n0}$;\6 +\&{debug} \37$\\{sum}\K\\{move}[0]$;\6 +\&{for} $\|k\K1\mathrel{\&{to}}\\{delta}$ \1\&{do}\5 +$\\{sum}\K\\{sum}+\\{abs}(\\{move}[\|k])$;\2\6 +\&{if} $\\{sum}\I\\{m1}-\\{m0}$ \1\&{then}\5 +$\\{confusion}(\.{"0"})$;\ \2\6 +\&{gubed}\6 +\X380:Prepare for and switch to the appropriate case, based on \\{octant}\X;\6 +\4\\{fast\_case\_up}: \37\X381:Add edges for first or fourth octants, then % +\&{goto} \\{done}\X;\6 +\4\\{fast\_case\_down}: \37\X382:Add edges for fifth or eighth octants, then % +\&{goto} \\{done}\X;\6 +\4\\{slow\_case\_up}: \37\X383:Add edges for second or third octants, then % +\&{goto} \\{done}\X;\6 +\4\\{slow\_case\_down}: \37\X384:Add edges for sixth or seventh octants, then % +\&{goto} \\{done}\X;\6 +\4\\{done}: \37$\\{n\_pos}(\\{cur\_edges})\K\|n+\\{zero\_field}$;\5 +$\\{n\_rover}(\\{cur\_edges})\K\|p$;\6 +\&{end};\par +\fi + +\M379. The current octant code appears in a global variable. If, for example, +we have $\\{octant}=\\{third\_octant}$, it means that a curve traveling in a +north to +north-westerly direction has been rotated for the purposes of internal +calculations so that the \\{move} data travels in an east to north-easterly +direction. We want to unrotate as we update the edge structure. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{octant}: \37$\\{first\_octant}\to\\{sixth\_octant}$;\C{the current octant +of interest}\par +\fi + +\M380. \P$\X380:Prepare for and switch to the appropriate case, based on % +\\{octant}\X\S$\6 +\&{case} $\\{octant}$ \1\&{of}\6 +\4\\{first\_octant}: \37\&{begin} \37$\\{dx}\K8$;\5 +$\\{edge\_prep}(\\{m0},\39\\{m1},\39\\{n0},\39\\{n1})$;\5 +\&{goto} \37\\{fast\_case\_up};\6 +\&{end};\6 +\4\\{second\_octant}: \37\&{begin} \37$\\{dx}\K8$;\5 +$\\{edge\_prep}(\\{n0},\39\\{n1},\39\\{m0},\39\\{m1})$;\5 +\&{goto} \37\\{slow\_case\_up};\6 +\&{end};\6 +\4\\{third\_octant}: \37\&{begin} \37$\\{dx}\K-8$;\5 +$\\{edge\_prep}(-\\{n1},\39-\\{n0},\39\\{m0},\39\\{m1})$;\5 +$\\{negate}(\\{n0})$;\5 +\&{goto} \37\\{slow\_case\_up};\6 +\&{end};\6 +\4\\{fourth\_octant}: \37\&{begin} \37$\\{dx}\K-8$;\5 +$\\{edge\_prep}(-\\{m1},\39-\\{m0},\39\\{n0},\39\\{n1})$;\5 +$\\{negate}(\\{m0})$;\5 +\&{goto} \37\\{fast\_case\_up};\6 +\&{end};\6 +\4\\{fifth\_octant}: \37\&{begin} \37$\\{dx}\K-8$;\5 +$\\{edge\_prep}(-\\{m1},\39-\\{m0},\39-\\{n1},\39-\\{n0})$;\5 +$\\{negate}(\\{m0})$;\5 +\&{goto} \37\\{fast\_case\_down};\6 +\&{end};\6 +\4\\{sixth\_octant}: \37\&{begin} \37$\\{dx}\K-8$;\5 +$\\{edge\_prep}(-\\{n1},\39-\\{n0},\39-\\{m1},\39-\\{m0})$;\5 +$\\{negate}(\\{n0})$;\5 +\&{goto} \37\\{slow\_case\_down};\6 +\&{end};\6 +\4\\{seventh\_octant}: \37\&{begin} \37$\\{dx}\K8$;\5 +$\\{edge\_prep}(\\{n0},\39\\{n1},\39-\\{m1},\39-\\{m0})$;\5 +\&{goto} \37\\{slow\_case\_down};\6 +\&{end};\6 +\4\\{eighth\_octant}: \37\&{begin} \37$\\{dx}\K8$;\5 +$\\{edge\_prep}(\\{m0},\39\\{m1},\39-\\{n1},\39-\\{n0})$;\5 +\&{goto} \37\\{fast\_case\_down};\6 +\&{end};\2\6 +\&{end};\C{there are only eight octants}\par +\U378.\fi + +\M381. \P$\X381:Add edges for first or fourth octants, then \&{goto} \\{done}\X% +\S$\6 +\X377:Move to row \\{n0}, pointed to by \|p\X;\6 +\&{if} $\\{delta}>0$ \1\&{then}\6 +\&{begin} \37$\|k\K0$;\5 +$\\{edge\_and\_weight}\K8\ast(\\{m0}+\\{m\_offset}(\\{cur\_edges}))+\\{min% +\_halfword}+\\{zero\_w}-\\{cur\_wt}$;\6 +\1\&{repeat} \37$\\{edge\_and\_weight}\K\\{edge\_and\_weight}+\\{dx}\ast% +\\{move}[\|k]$;\5 +$\\{fast\_get\_avail}(\|r)$;\5 +$\\{link}(\|r)\K\\{unsorted}(\|p)$;\5 +$\\{info}(\|r)\K\\{edge\_and\_weight}$;\6 +\&{if} $\\{internal}[\\{tracing\_edges}]>0$ \1\&{then}\5 +$\\{trace\_new\_edge}(\|r,\39\|n)$;\2\6 +$\\{unsorted}(\|p)\K\|r$;\5 +$\|p\K\\{link}(\|p)$;\5 +$\\{incr}(\|k)$;\5 +$\\{incr}(\|n)$;\6 +\4\&{until}\5 +$\|k=\\{delta}$;\2\6 +\&{end};\2\6 +\&{goto} \37\\{done}\par +\U378.\fi + +\M382. \P$\X382:Add edges for fifth or eighth octants, then \&{goto} \\{done}\X% +\S$\6 +$\\{n0}\K-\\{n0}-1$;\5 +\X377:Move to row \\{n0}, pointed to by \|p\X;\6 +\&{if} $\\{delta}>0$ \1\&{then}\6 +\&{begin} \37$\|k\K0$;\5 +$\\{edge\_and\_weight}\K8\ast(\\{m0}+\\{m\_offset}(\\{cur\_edges}))+\\{min% +\_halfword}+\\{zero\_w}+\\{cur\_wt}$;\6 +\1\&{repeat} \37$\\{edge\_and\_weight}\K\\{edge\_and\_weight}+\\{dx}\ast% +\\{move}[\|k]$;\5 +$\\{fast\_get\_avail}(\|r)$;\5 +$\\{link}(\|r)\K\\{unsorted}(\|p)$;\5 +$\\{info}(\|r)\K\\{edge\_and\_weight}$;\6 +\&{if} $\\{internal}[\\{tracing\_edges}]>0$ \1\&{then}\5 +$\\{trace\_new\_edge}(\|r,\39\|n)$;\2\6 +$\\{unsorted}(\|p)\K\|r$;\5 +$\|p\K\\{knil}(\|p)$;\5 +$\\{incr}(\|k)$;\5 +$\\{decr}(\|n)$;\6 +\4\&{until}\5 +$\|k=\\{delta}$;\2\6 +\&{end};\2\6 +\&{goto} \37\\{done}\par +\U378.\fi + +\M383. \P$\X383:Add edges for second or third octants, then \&{goto} \\{done}\X% +\S$\6 +$\\{edge\_and\_weight}\K8\ast(\\{n0}+\\{m\_offset}(\\{cur\_edges}))+\\{min% +\_halfword}+\\{zero\_w}-\\{cur\_wt}$;\5 +$\\{n0}\K\\{m0}$;\5 +$\|k\K0$;\5 +\X377:Move to row \\{n0}, pointed to by \|p\X;\6 +\1\&{repeat} \37$\|j\K\\{move}[\|k]$;\6 +\&{while} $\|j>0$ \1\&{do}\6 +\&{begin} \37$\\{fast\_get\_avail}(\|r)$;\5 +$\\{link}(\|r)\K\\{unsorted}(\|p)$;\5 +$\\{info}(\|r)\K\\{edge\_and\_weight}$;\6 +\&{if} $\\{internal}[\\{tracing\_edges}]>0$ \1\&{then}\5 +$\\{trace\_new\_edge}(\|r,\39\|n)$;\2\6 +$\\{unsorted}(\|p)\K\|r$;\5 +$\|p\K\\{link}(\|p)$;\5 +$\\{decr}(\|j)$;\5 +$\\{incr}(\|n)$;\6 +\&{end};\2\6 +$\\{edge\_and\_weight}\K\\{edge\_and\_weight}+\\{dx}$;\5 +$\\{incr}(\|k)$;\6 +\4\&{until}\5 +$\|k>\\{delta}$;\2\6 +\&{goto} \37\\{done}\par +\U378.\fi + +\M384. \P$\X384:Add edges for sixth or seventh octants, then \&{goto} \\{done}% +\X\S$\6 +$\\{edge\_and\_weight}\K8\ast(\\{n0}+\\{m\_offset}(\\{cur\_edges}))+\\{min% +\_halfword}+\\{zero\_w}+\\{cur\_wt}$;\5 +$\\{n0}\K-\\{m0}-1$;\5 +$\|k\K0$;\5 +\X377:Move to row \\{n0}, pointed to by \|p\X;\6 +\1\&{repeat} \37$\|j\K\\{move}[\|k]$;\6 +\&{while} $\|j>0$ \1\&{do}\6 +\&{begin} \37$\\{fast\_get\_avail}(\|r)$;\5 +$\\{link}(\|r)\K\\{unsorted}(\|p)$;\5 +$\\{info}(\|r)\K\\{edge\_and\_weight}$;\6 +\&{if} $\\{internal}[\\{tracing\_edges}]>0$ \1\&{then}\5 +$\\{trace\_new\_edge}(\|r,\39\|n)$;\2\6 +$\\{unsorted}(\|p)\K\|r$;\5 +$\|p\K\\{knil}(\|p)$;\5 +$\\{decr}(\|j)$;\5 +$\\{decr}(\|n)$;\6 +\&{end};\2\6 +$\\{edge\_and\_weight}\K\\{edge\_and\_weight}+\\{dx}$;\5 +$\\{incr}(\|k)$;\6 +\4\&{until}\5 +$\|k>\\{delta}$;\2\6 +\&{goto} \37\\{done}\par +\U378.\fi + +\M385. All the hard work of building an edge structure is undone by the +following +subroutine. + +\Y\P$\4\X268:Declare the recycling subroutines\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{toss\_edges}(\|h:\\{pointer})$;\6 +\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{for list manipulation}\2\6 +\&{begin} \37$\|q\K\\{link}(\|h)$;\6 +\&{while} $\|q\I\|h$ \1\&{do}\6 +\&{begin} \37$\\{flush\_list}(\\{sorted}(\|q))$;\6 +\&{if} $\\{unsorted}(\|q)>\\{void}$ \1\&{then}\5 +$\\{flush\_list}(\\{unsorted}(\|q))$;\2\6 +$\|p\K\|q$;\5 +$\|q\K\\{link}(\|q)$;\5 +$\\{free\_node}(\|p,\39\\{row\_node\_size})$;\6 +\&{end};\2\6 +$\\{free\_node}(\|h,\39\\{edge\_header\_size})$;\6 +\&{end};\par +\fi + +\N386. \[21] Subdivision into octants. +When \MF\ digitizes a path, it reduces the problem to the special +case of paths that travel in ``first octant'' directions; i.e., +each cubic $z(t)=\bigl(x(t),y(t)\bigr)$ being digitized will have the property +that $0\L y'(t)\L x'(t)$. This assumption makes digitizing simpler +and faster than if the direction of motion has to be tested repeatedly. + +When $z(t)$ is cubic, $x'(t)$ and $y'(t)$ are quadratic, hence the four +polynomials $x'(t)$, $y'(t)$, $x'(t)-y'(t)$, and $x'(t)+y'(t)$ cross +through~0 at most twice each. If we subdivide the given cubic at these +places, we get at most nine subintervals in each of which +$x'(t)$, $y'(t)$, $x'(t)-y'(t)$, and $x'(t)+y'(t)$ all have a constant +sign. The curve can be transformed in each of these subintervals so that +it travels entirely in first octant directions, if we reflect $x\swap-x$, +$y\swap-y$, and/or $x\swap y$ as necessary. (Incidentally, it can be +shown that a cubic such that $x'(t)=16(2t-1)^2+2(2t-1)-1$ and +$y'(t)=8(2t-1)^2+4(2t-1)$ does indeed split into nine subintervals.) + +\fi + +\M387. The transformation that rotates coordinates, so that first octant motion +can be assumed, is defined by the \\{skew} subroutine, which sets global +variables \\{cur\_x} and \\{cur\_y} to the values that are appropriate in a +given octant. (Octants are encoded as they were in the \\{n\_arg} subroutine.) + +This transformation is ``skewed'' by replacing $(\|x,\|y)$ by $(\|x-\|y,\|y)$, +once first octant motion has been established. It turns out that +skewed coordinates are somewhat better to work with when curves are +actually digitized. + +\Y\P\D \37$\\{set\_two\_end}(\#)\S\\{cur\_y}\K\#$;\ \&{end} \par +\P\D $\\{set\_two}(\#)\S$ \6 +\&{begin} \37$\\{cur\_x}\K\#$;\5 +\\{set\_two\_end}\par +\Y\P\4\&{procedure}\1\ \37$\\{skew}(\|x,\39\|y:\\{scaled};\,\35\\{octant}:% +\\{small\_number})$;\2\6 +\&{begin} \37\&{case} $\\{octant}$ \1\&{of}\6 +\4\\{first\_octant}: \37$\\{set\_two}(\|x-\|y)(\|y)$;\6 +\4\\{second\_octant}: \37$\\{set\_two}(\|y-\|x)(\|x)$;\6 +\4\\{third\_octant}: \37$\\{set\_two}(\|y+\|x)(-\|x)$;\6 +\4\\{fourth\_octant}: \37$\\{set\_two}(-\|x-\|y)(\|y)$;\6 +\4\\{fifth\_octant}: \37$\\{set\_two}(-\|x+\|y)(-\|y)$;\6 +\4\\{sixth\_octant}: \37$\\{set\_two}(-\|y+\|x)(-\|x)$;\6 +\4\\{seventh\_octant}: \37$\\{set\_two}(-\|y-\|x)(\|x)$;\6 +\4\\{eighth\_octant}: \37$\\{set\_two}(\|x+\|y)(-\|y)$;\2\6 +\&{end};\C{there are no other cases}\6 +\&{end};\par +\fi + +\M388. Conversely, the following subroutine sets \\{cur\_x} and +\\{cur\_y} to the original coordinate values of a point, given an octant +code and the point's coordinates $(\|x,\|y)$ after they have been mapped into +the first octant and skewed. + +\Y\P$\4\X257:Declare subroutines for printing expressions\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{unskew}(\|x,\39\|y:\\{scaled};\,\35\\{octant}:% +\\{small\_number})$;\2\6 +\&{begin} \37\&{case} $\\{octant}$ \1\&{of}\6 +\4\\{first\_octant}: \37$\\{set\_two}(\|x+\|y)(\|y)$;\6 +\4\\{second\_octant}: \37$\\{set\_two}(\|y)(\|x+\|y)$;\6 +\4\\{third\_octant}: \37$\\{set\_two}(-\|y)(\|x+\|y)$;\6 +\4\\{fourth\_octant}: \37$\\{set\_two}(-\|x-\|y)(\|y)$;\6 +\4\\{fifth\_octant}: \37$\\{set\_two}(-\|x-\|y)(-\|y)$;\6 +\4\\{sixth\_octant}: \37$\\{set\_two}(-\|y)(-\|x-\|y)$;\6 +\4\\{seventh\_octant}: \37$\\{set\_two}(\|y)(-\|x-\|y)$;\6 +\4\\{eighth\_octant}: \37$\\{set\_two}(\|x+\|y)(-\|y)$;\2\6 +\&{end};\C{there are no other cases}\6 +\&{end};\par +\fi + +\M389. \P$\X13:Global variables\X\mathrel{+}\S$\6 +\4$\\{cur\_x},\39\\{cur\_y}$: \37\\{scaled};\C{outputs of \\{rotate}, % +\\{unrotate}, and a few other routines}\par +\fi + +\M390. The conversion to skewed and rotated coordinates takes place in +stages, and at one point in the transformation we will have negated the +$x$ and/or $y$ coordinates so as to make curves travel in the first +{\sl quadrant}. At this point the relevant ``octant'' code will be +either \\{first\_octant} (when no transformation has been done), +or $\\{fourth\_octant}=\\{first\_octant}+\\{negate\_x}$ (when $x$ has been +negated), +or $\\{fifth\_octant}=\\{first\_octant}+\\{negate\_x}+\\{negate\_y}$ (when both +have been +negated), or $\\{eighth\_octant}=\\{first\_octant}+\\{negate\_y}$ (when $y$ has +been +negated). The \\{abnegate} routine is sometimes needed to convert +from one of these transformations to another. + +\Y\P\4\&{procedure}\1\ \37$\\{abnegate}(\|x,\39\|y:\\{scaled};\,\35\\{octant% +\_before},\39\\{octant\_after}:\\{small\_number})$;\2\6 +\&{begin} \37\&{if} $\\{odd}(\\{octant\_before})=\\{odd}(\\{octant\_after})$ \1% +\&{then}\5 +$\\{cur\_x}\K\|x$\6 +\4\&{else} $\\{cur\_x}\K-\|x$;\2\6 +\&{if} $(\\{octant\_before}>\\{negate\_y})=(\\{octant\_after}>\\{negate\_y})$ % +\1\&{then}\5 +$\\{cur\_y}\K\|y$\6 +\4\&{else} $\\{cur\_y}\K-\|y$;\2\6 +\&{end};\par +\fi + +\M391. Now here's a subroutine that's handy for subdivision: Given a +quadratic polynomial $B(a,b,c;t)$, the \\{crossing\_point} function +returns the unique \\{fraction} value \|t between 0 and~1 at which +$B(a,b,c;t)$ changes from positive to negative, or returns +$\|t=\\{fraction\_one}+1$ if no such value exists. If $\|a<0$ (so that +$B(a,b,c;t)$ +is already negative at $\|t=0$), \\{crossing\_point} returns the value zero. + +\Y\P\D \37$\\{no\_crossing}\S$\1\6 +\&{begin} \37$\\{crossing\_point}\K\\{fraction\_one}+1$;\5 +\&{return};\6 +\&{end}\2\par +\P\D \37$\\{one\_crossing}\S$\1\6 +\&{begin} \37$\\{crossing\_point}\K\\{fraction\_one}$;\5 +\&{return};\6 +\&{end}\2\par +\P\D \37$\\{zero\_crossing}\S$\1\6 +\&{begin} \37$\\{crossing\_point}\K0$;\5 +\&{return};\6 +\&{end}\2\par +\Y\P\4\&{function}\1\ \37$\\{crossing\_point}(\|a,\39\|b,\39\|c:\\{integer})$: +\37\\{fraction};\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37\|d: \37\\{integer};\C{recursive counter}\6 +$\|x,\39\\{xx},\39\\{x0},\39\\{x1},\39\\{x2}$: \37\\{integer};\C{temporary +registers for bisection}\2\6 +\&{begin} \37\&{if} $\|a<0$ \1\&{then}\5 +\\{zero\_crossing};\2\6 +\&{if} $\|c\G0$ \1\&{then}\6 +\&{begin} \37\&{if} $\|b\G0$ \1\&{then}\6 +\&{if} $\|c>0$ \1\&{then}\5 +\\{no\_crossing}\6 +\4\&{else} \&{if} $(\|a=0)\W(\|b=0)$ \1\&{then}\5 +\\{no\_crossing}\6 +\4\&{else} \\{one\_crossing};\2\2\2\6 +\&{if} $\|a=0$ \1\&{then}\5 +\\{zero\_crossing};\2\6 +\&{end}\6 +\4\&{else} \&{if} $\|a=0$ \1\&{then}\6 +\&{if} $\|b\L0$ \1\&{then}\5 +\\{zero\_crossing};\2\2\2\6 +\X392:Use bisection to find the crossing point, if one exists\X;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M392. The general bisection method is quite simple when $n=2$, hence +\\{crossing\_point} does not take much time. At each stage in the +recursion we have a subinterval defined by \|l and~\|j such that +$B(a,b,c;2^{-l}(j+t))=B(x_0,x_1,x_2;t)$, and we want to ``zero in'' on +the subinterval where $x_0\G0$ and $\min(x_1,x_2)<0$. + +It is convenient for purposes of calculation to combine the values +of \|l and~\|j in a single variable $d=2^l+j$, because the operation +of bisection then corresponds simply to doubling $d$ and possibly +adding~1. Furthermore it proves to be convenient to modify +our previous conventions for bisection slightly, maintaining the +variables $X_0=2^lx_0$, $X_1=2^l(x_0-x_1)$, and $X_2=2^l(x_1-x_2)$. +With these variables the conditions $x_0\ge0$ and $\min(x_1,x_2)<0$ are +equivalent to $\max(X_1,X_1+X_2)>X_0\ge0$. + +The following code maintains the invariant relations +$0\L\\{x0}<\max(\\{x1},\\{x1}+\\{x2})$, +$\vert\\{x1}\vert<2^{30}$, $\vert\\{x2}\vert<2^{30}$; +it has been constructed in such a way that no arithmetic overflow +will occur if the inputs satisfy +$a<2^{30}$, $\vert a-b\vert<2^{30}$, and $\vert b-c\vert<2^{30}$. + +\Y\P$\4\X392:Use bisection to find the crossing point, if one exists\X\S$\6 +$\|d\K1$;\5 +$\\{x0}\K\|a$;\5 +$\\{x1}\K\|a-\|b$;\5 +$\\{x2}\K\|b-\|c$;\6 +\1\&{repeat} \37$\|x\K\\{half}(\\{x1}+\\{x2})$;\6 +\&{if} $\\{x1}-\\{x0}>\\{x0}$ \1\&{then}\6 +\&{begin} \37$\\{x2}\K\|x$;\5 +$\\{double}(\\{x0})$;\5 +$\\{double}(\|d)$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{xx}\K\\{x1}+\|x-\\{x0}$;\6 +\&{if} $\\{xx}>\\{x0}$ \1\&{then}\6 +\&{begin} \37$\\{x2}\K\|x$;\5 +$\\{double}(\\{x0})$;\5 +$\\{double}(\|d)$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{x0}\K\\{x0}-\\{xx}$;\6 +\&{if} $\|x\L\\{x0}$ \1\&{then}\6 +\&{if} $\|x+\\{x2}\L\\{x0}$ \1\&{then}\5 +\\{no\_crossing};\2\2\6 +$\\{x1}\K\|x$;\5 +$\|d\K\|d+\|d+1$;\6 +\&{end};\2\6 +\&{end};\2\6 +\4\&{until}\5 +$\|d\G\\{fraction\_one}$;\2\6 +$\\{crossing\_point}\K\|d-\\{fraction\_one}$\par +\U391.\fi + +\M393. Octant subdivision is applied only to cycles, i.e., to closed paths. +A ``cycle spec'' is a data structure that contains specifications of +cubic curves and octant mappings for the cycle that has been subdivided +into segments belonging to single octants. It is composed entirely of +knot nodes, similar to those in the representation of paths; but the +\\{explicit} type indications have been replaced by positive numbers +that give further information. Additional \\{endpoint} data is also +inserted at the octant boundaries. + +Recall that a cubic polynomial is represented by four control points +that appear in adjacent nodes \|p and~\|q of a knot list. The \|x~coordinates +are $\\{x\_coord}(\|p)$, $\\{right\_x}(\|p)$, $\\{left\_x}(\|q)$, and $\\{x% +\_coord}(\|q)$; the +\|y~coordinates are similar. We shall call this ``the cubic following~\|p'' +or ``the cubic between \|p and~\|q'' or ``the cubic preceding~\|q.'' + +Cycle specs are circular lists of cubic curves mixed with octant +boundaries. Like cubics, the octant boundaries are represented in +consecutive knot nodes \|p and~\|q. In such cases $\\{right\_type}(\|p)=\\{left% +\_type}(\|q)=\\{endpoint}$, and the fields $\\{right\_x}(\|p)$, $\\{right\_y}(% +\|p)$, +$\\{left\_x}(\|q)$, and $\\{left\_y}(\|q)$ are replaced by other fields called +$\\{right\_octant}(\|p)$, $\\{right\_transition}(\|p)$, $\\{left\_octant}(% +\|q)$, and +$\\{left\_transition}(\|q)$, respectively. For example, when the curve +direction +moves from the third octant to the fourth octant, the boundary nodes say +$\\{right\_octant}(\|p)=\\{third\_octant}$, $\\{left\_octant}(\|q)=\\{fourth% +\_octant}$, +and $\\{right\_transition}(\|p)=\\{left\_transition}(\|q)=\\{diagonal}$. A % +\\{diagonal} +transition occurs when moving between octants 1~\AM~2, 3~\AM~4, 5~\AM~6, or +7~\AM~8; an \\{axis} transition occurs when moving between octants 8~\AM~1, +2~\AM~3, 4~\AM~5, 6~\AM~7. (Such transition information is redundant +but convenient.) Fields $\\{x\_coord}(\|p)$ and $\\{y\_coord}(\|p)$ will +contain +coordinates of the transition point after rotation from third octant +to first octant; i.e., if the true coordinates are $(x,y)$, the +coordinates $(y,-x)$ will appear in node~\|p. Similarly, a fourth-octant +transformation will have been applied after the transition, so +we will have $\\{x\_coord}(\|q)=\hbox{$-x$}$ and $\\{y\_coord}(\|q)=\|y$. + +The cubic between \|p and \|q will contain positive numbers in the +fields $\\{right\_type}(\|p)$ and $\\{left\_type}(\|q)$; this makes cubics +distinguishable from octant boundaries, because $\\{endpoint}=0$. +The value of $\\{right\_type}(\|p)$ will be the current octant code, +during the time that cycle specs are being constructed; it will +refer later to a pen offset position, if the envelope of a cycle is +being computed. A cubic that comes from some subinterval of the $k$th +step in the original cyclic path will have $\\{left\_type}(\|q)=\|k$. + +\Y\P\D \37$\\{right\_octant}\S\\{right\_x}$\C{the octant code before a +transition}\par +\P\D \37$\\{left\_octant}\S\\{left\_x}$\C{the octant after a transition}\par +\P\D \37$\\{right\_transition}\S\\{right\_y}$\C{the type of transition}\par +\P\D \37$\\{left\_transition}\S\\{left\_y}$\C{ditto, either \\{axis} or % +\\{diagonal}}\par +\P\D \37$\\{axis}=0$\C{a transition across the $x'$- or $y'$-axis}\par +\P\D \37$\\{diagonal}=1$\C{a transition where $y'=\pm x'$}\par +\fi + +\M394. Here's a routine that prints a cycle spec in symbolic form, so that it +is possible to see what subdivision has been made. The point coordinates +are converted back from \MF's internal ``rotated'' form to the external +``true'' form. The global variable~\\{cur\_spec} should point to a knot just +after the beginning of an octant boundary, i.e., such that +$\\{left\_type}(\\{cur\_spec})=\\{endpoint}$. + +\Y\P\D \37$\\{print\_two\_true}(\#)\S\\{unskew}(\#,\39\\{octant})$;\5 +$\\{print\_two}(\\{cur\_x},\39\\{cur\_y})$\par +\Y\P\4\&{procedure}\1\ \37$\\{print\_spec}(\|s:\\{str\_number})$;\6 +\4\&{label} \37$\\{not\_found},\39\\{done}$;\6 +\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{for list traversal}\6 +\\{octant}: \37\\{small\_number};\C{the current octant code}\2\6 +\&{begin} \37$\\{print\_diagnostic}(\.{"Cycle\ spec"},\39\|s,\39\\{true})$;\5 +$\|p\K\\{cur\_spec}$;\5 +$\\{octant}\K\\{left\_octant}(\|p)$;\5 +\\{print\_ln};\5 +$\\{print\_two\_true}(\\{x\_coord}(\\{cur\_spec}),\39\\{y\_coord}(\\{cur% +\_spec}))$;\5 +$\\{print}(\.{"\ \%\ beginning\ in\ octant\ \`"})$;\6 +\~ \1\&{loop}\ \&{begin} \37$\\{print}(\\{octant\_dir}[\\{octant}])$;\5 +$\\{print\_char}(\.{"\'"})$;\6 +\~ \1\&{loop}\ \&{begin} \37$\|q\K\\{link}(\|p)$;\6 +\&{if} $\\{right\_type}(\|p)=\\{endpoint}$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +\X397:Print the cubic between \|p and \|q\X;\6 +$\|p\K\|q$;\6 +\&{end};\2\6 +\4\\{not\_found}: \37\&{if} $\|q=\\{cur\_spec}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\|p\K\|q$;\5 +$\\{octant}\K\\{left\_octant}(\|p)$;\5 +$\\{print\_nl}(\.{"\%\ entering\ octant\ \`"})$;\6 +\&{end};\2\6 +\4\\{done}: \37$\\{print\_nl}(\.{"\ \&\ cycle"})$;\5 +$\\{end\_diagnostic}(\\{true})$;\6 +\&{end};\par +\fi + +\M395. Symbolic octant direction names are kept in the \\{octant\_dir} array. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{octant\_dir}: \37\&{array} $[\\{first\_octant}\to\\{sixth\_octant}]$ \1% +\&{of}\5 +\\{str\_number};\2\par +\fi + +\M396. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{octant\_dir}[\\{first\_octant}]\K\.{"ENE"}$;\5 +$\\{octant\_dir}[\\{second\_octant}]\K\.{"NNE"}$;\5 +$\\{octant\_dir}[\\{third\_octant}]\K\.{"NNW"}$;\5 +$\\{octant\_dir}[\\{fourth\_octant}]\K\.{"WNW"}$;\5 +$\\{octant\_dir}[\\{fifth\_octant}]\K\.{"WSW"}$;\5 +$\\{octant\_dir}[\\{sixth\_octant}]\K\.{"SSW"}$;\5 +$\\{octant\_dir}[\\{seventh\_octant}]\K\.{"SSE"}$;\5 +$\\{octant\_dir}[\\{eighth\_octant}]\K\.{"ESE"}$;\par +\fi + +\M397. \P$\X397:Print the cubic between \|p and \|q\X\S$\6 +\&{begin} \37$\\{print\_nl}(\.{"\ \ \ ..controls\ "})$;\5 +$\\{print\_two\_true}(\\{right\_x}(\|p),\39\\{right\_y}(\|p))$;\5 +$\\{print}(\.{"\ and\ "})$;\5 +$\\{print\_two\_true}(\\{left\_x}(\|q),\39\\{left\_y}(\|q))$;\5 +$\\{print\_nl}(\.{"\ .."})$;\5 +$\\{print\_two\_true}(\\{x\_coord}(\|q),\39\\{y\_coord}(\|q))$;\5 +$\\{print}(\.{"\ \%\ segment\ "})$;\5 +$\\{print\_int}(\\{left\_type}(\|q)-1)$;\6 +\&{end}\par +\U394.\fi + +\M398. A much more compact version of a spec is printed to help users identify +``strange paths.'' + +\Y\P\4\&{procedure}\1\ \37$\\{print\_strange}(\|s:\\{str\_number})$;\6 +\4\&{var} \37\|p: \37\\{pointer};\C{for list traversal}\6 +\|f: \37\\{pointer};\C{starting point in the cycle}\6 +\|q: \37\\{pointer};\C{octant boundary to be printed}\6 +\|t: \37\\{integer};\C{segment number, plus 1}\2\6 +\&{begin} \37\&{if} $\\{interaction}=\\{error\_stop\_mode}$ \1\&{then}\5 +\\{wake\_up\_terminal};\2\6 +$\\{print\_nl}(\.{">"})$;\5 +\X399:Find the starting point, \|f\X;\6 +\X400:Determine the octant boundary \|q that precedes \|f\X;\6 +$\|t\K0$;\6 +\1\&{repeat} \37\&{if} $\\{left\_type}(\|p)\I\\{endpoint}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{left\_type}(\|p)\I\|t$ \1\&{then}\6 +\&{begin} \37$\|t\K\\{left\_type}(\|p)$;\5 +$\\{print\_char}(\.{"\ "})$;\5 +$\\{print\_int}(\|t-1)$;\6 +\&{end};\2\6 +\&{if} $\|q\I\\{null}$ \1\&{then}\6 +\&{begin} \37\X401:Print the turns, if any, that start at \|q, and advance \|q% +\X;\6 +$\\{print\_char}(\.{"\ "})$;\5 +$\\{print}(\\{octant\_dir}[\\{left\_octant}(\|q)])$;\5 +$\|q\K\\{null}$;\6 +\&{end};\2\6 +\&{end}\6 +\4\&{else} \&{if} $\|q=\\{null}$ \1\&{then}\5 +$\|q\K\|p$;\2\2\6 +$\|p\K\\{link}(\|p)$;\6 +\4\&{until}\5 +$\|p=\|f$;\2\6 +$\\{print\_char}(\.{"\ "})$;\5 +$\\{print\_int}(\\{left\_type}(\|p)-1)$;\6 +\&{if} $\|q\I\\{null}$ \1\&{then}\5 +\X401:Print the turns, if any, that start at \|q, and advance \|q\X;\2\6 +$\\{print\_err}(\|s)$;\6 +\&{end};\par +\fi + +\M399. If the segment numbers on the cycle are $t_1$, $t_2$, \dots, $t_m$, +we have $t_{k-1}\L t_k$ except for at most one value of~$k$. If there are +no exceptions, $f$ will point to $t_1$; otherwise it will point to the +exceptional~$t_k$. + +There is at least one segment number (i.e., we always have $m>0$), because +\\{print\_strange} is never called upon to display an entirely ``dead'' cycle. + +\Y\P$\4\X399:Find the starting point, \|f\X\S$\6 +$\|p\K\\{cur\_spec}$;\5 +$\|t\K\\{max\_quarterword}+1$;\6 +\1\&{repeat} \37$\|p\K\\{link}(\|p)$;\6 +\&{if} $\\{left\_type}(\|p)\I\\{endpoint}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{left\_type}(\|p)<\|t$ \1\&{then}\5 +$\|f\K\|p$;\2\6 +$\|t\K\\{left\_type}(\|p)$;\6 +\&{end};\2\6 +\4\&{until}\5 +$\|p=\\{cur\_spec}$\2\par +\U398.\fi + +\M400. \P$\X400:Determine the octant boundary \|q that precedes \|f\X\S$\6 +$\|p\K\\{cur\_spec}$;\5 +$\|q\K\|p$;\6 +\1\&{repeat} \37$\|p\K\\{link}(\|p)$;\6 +\&{if} $\\{left\_type}(\|p)=\\{endpoint}$ \1\&{then}\5 +$\|q\K\|p$;\2\6 +\4\&{until}\5 +$\|p=\|f$\2\par +\U398.\fi + +\M401. When two octant boundaries are adjacent, the path is simply changing +direction +without moving. Such octant directions are shown in parentheses. + +\Y\P$\4\X401:Print the turns, if any, that start at \|q, and advance \|q\X\S$\6 +\&{if} $\\{left\_type}(\\{link}(\|q))=\\{endpoint}$ \1\&{then}\6 +\&{begin} \37$\\{print}(\.{"\ ("})$;\5 +$\\{print}(\\{octant\_dir}[\\{left\_octant}(\|q)])$;\5 +$\|q\K\\{link}(\|q)$;\6 +\&{while} $\\{left\_type}(\\{link}(\|q))=\\{endpoint}$ \1\&{do}\6 +\&{begin} \37$\\{print\_char}(\.{"\ "})$;\5 +$\\{print}(\\{octant\_dir}[\\{left\_octant}(\|q)])$;\5 +$\|q\K\\{link}(\|q)$;\6 +\&{end};\2\6 +$\\{print\_char}(\.{")"})$;\6 +\&{end}\2\par +\Us398\ET398.\fi + +\M402. The \\{make\_spec} routine is what subdivides paths into octants: +Given a pointer \\{cur\_spec} to a cyclic path, \\{make\_spec} mungs the path +data +and returns a pointer to the corresponding cyclic spec. +All ``dead'' cubics (i.e., cubics that don't move at all from +their starting points) will have been removed from the result. + +The idea of \\{make\_spec} is fairly simple: Each cubic is first +subdivided, if necessary, into pieces belonging to single octants; +then the octant boundaries are inserted. But some of the details of +this transformation are not quite obvious. + +If $\\{autorounding}>0$, the path will be adjusted so that critical tangent +directions occur at ``good'' points with respect to the pen called \\{cur% +\_pen}. + +The resulting spec will have all \|x and \|y coordinates at most +$2^{28}-\\{half\_unit}-1-\\{safety\_margin}$ in absolute value. The pointer +that is returned will start some octant, as required by \\{print\_spec}. + +\Y\P\hbox{\4}\X405:Declare subroutines needed by \\{make\_spec}\X\6 +\4\&{function}\1\ \37$\\{make\_spec}(\|h:\\{pointer};\,\35\\{safety\_margin}:% +\\{scaled};\,\35\\{tracing}:\\{integer})$: \37\\{pointer};\C{converts a path to +a cycle spec}\6 +\4\&{label} \37$\\{continue},\39\\{done}$;\6 +\4\&{var} \37$\|p,\39\|q,\39\|r,\39\|s$: \37\\{pointer};\C{for traversing the +lists}\6 +\|k: \37\\{integer};\C{serial number of path segment, or octant code}\6 +\\{chopped}: \37\\{integer};\C{positive if data truncated, negative +if data dangerously large}\6 +\X453:Other local variables for \\{make\_spec}\X\2\6 +\&{begin} \37$\\{cur\_spec}\K\|h$;\6 +\&{if} $\\{tracing}>0$ \1\&{then}\5 +$\\{print\_path}(\\{cur\_spec},\39\.{",\ before\ subdivision\ into\ octants"},% +\39\\{true})$;\2\6 +$\\{max\_allowed}\K\\{fraction\_one}-\\{half\_unit}-1-\\{safety\_margin}$;\5 +\X404:Truncate the values of all coordinates that exceed \\{max\_allowed}, and +stamp segment numbers in each \\{left\_type} field\X;\6 +\\{quadrant\_subdivide};\C{subdivide each cubic into pieces belonging to +quadrants}\6 +\&{if} $(\\{internal}[\\{autorounding}]>0)\W(\\{chopped}=0)$ \1\&{then}\5 +\\{xy\_round};\2\6 +\\{octant\_subdivide};\C{complete the subdivision}\6 +\&{if} $(\\{internal}[\\{autorounding}]>\\{unity})\W(\\{chopped}=0)$ \1\&{then}% +\5 +\\{diag\_round};\2\6 +\X447:Remove dead cubics\X;\6 +\X450:Insert octant boundaries and compute the turning number\X;\6 +\&{while} $\\{left\_type}(\\{cur\_spec})\I\\{endpoint}$ \1\&{do}\5 +$\\{cur\_spec}\K\\{link}(\\{cur\_spec})$;\2\6 +\&{if} $\\{tracing}>0$ \1\&{then}\6 +\&{if} $(\\{internal}[\\{autorounding}]\L0)\V(\\{chopped}\I0)$ \1\&{then}\5 +$\\{print\_spec}(\.{",\ after\ subdivision"})$\6 +\4\&{else} \&{if} $\\{internal}[\\{autorounding}]>\\{unity}$ \1\&{then}\5 +$\\{print\_spec}(\.{",\ after\ subdivision\ and\ double\ autorounding"})$\6 +\4\&{else} $\\{print\_spec}(\.{",\ after\ subdivision\ and\ autorounding"})$;\2% +\2\2\6 +$\\{make\_spec}\K\\{cur\_spec}$;\6 +\&{end};\par +\fi + +\M403. The \\{make\_spec} routine has an interesting side effect, namely to set +the global variable \\{turning\_number} to the number of times the tangent +vector of the given cyclic path winds around the origin. + +Another global variable \\{cur\_spec} points to the specification as it is +being made, since several subroutines must go to work on it. + +And there are two global variables that affect the rounding +decisions, as we'll see later; they are called \\{cur\_pen} and \\{cur\_path% +\_type}. +The latter will be \\{double\_path\_code} if \\{make\_spec} is being +applied to a double path. + +\Y\P\D \37$\\{double\_path\_code}=0$\C{command modifier for `\&{doublepath}'}% +\par +\P\D \37$\\{contour\_code}=1$\C{command modifier for `\&{contour}'}\par +\P\D \37$\\{also\_code}=2$\C{command modifier for `\&{also}'}\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{cur\_spec}: \37\\{pointer};\C{the principal output of \\{make\_spec}}\6 +\4\\{turning\_number}: \37\\{integer};\C{another output of \\{make\_spec}}\6 +\4\\{cur\_pen}: \37\\{pointer};\C{an implicit input of \\{make\_spec}, used in +autorounding}\6 +\4\\{cur\_path\_type}: \37$\\{double\_path\_code}\to\\{contour\_code}$;% +\C{likewise}\6 +\4\\{max\_allowed}: \37\\{scaled};\C{coordinates must be at most this big}\par +\fi + +\M404. First we do a simple preprocessing step. The segment numbers inserted +here will propagate to all descendants of cubics that are split into +subintervals. These numbers must be nonzero, but otherwise they are +present merely for diagnostic purposes. The cubic from \|p to~\|q +that represents ``time interval'' $(\|t-1)\to\|t$ usually has $\\{right\_type}(% +\|q)=\|t$, +except when \|t is too large to be stored in a quarterword. + +\Y\P\D \37$\\{procrustes}(\#)\S$\ \&{if} $\\{abs}(\#)\G\\{dmax}$ \1\&{then}\6 +\&{if} $\\{abs}(\#)>\\{max\_allowed}$ \1\&{then}\6 +\&{begin} \37$\\{chopped}\K1$;\6 +\&{if} $\#>0$ \1\&{then}\5 +$\#\K\\{max\_allowed}$\ \&{else} $\#\K-\\{max\_allowed}$;\2\6 +\&{end}\6 +\4\&{else} \&{if} $\\{chopped}=0$ \1\&{then}\5 +$\\{chopped}\K-1$\2\2\2\par +\Y\P$\4\X404:Truncate the values of all coordinates that exceed \\{max% +\_allowed}, and stamp segment numbers in each \\{left\_type} field\X\S$\6 +$\|p\K\\{cur\_spec}$;\5 +$\|k\K1$;\5 +$\\{chopped}\K0$;\5 +$\\{dmax}\K\\{max\_allowed}/2$;\6 +\1\&{repeat} \37$\\{procrustes}(\\{left\_x}(\|p))$;\5 +$\\{procrustes}(\\{left\_y}(\|p))$;\5 +$\\{procrustes}(\\{x\_coord}(\|p))$;\5 +$\\{procrustes}(\\{y\_coord}(\|p))$;\5 +$\\{procrustes}(\\{right\_x}(\|p))$;\5 +$\\{procrustes}(\\{right\_y}(\|p))$;\6 +$\|p\K\\{link}(\|p)$;\5 +$\\{left\_type}(\|p)\K\|k$;\6 +\&{if} $\|k<\\{max\_quarterword}$ \1\&{then}\5 +$\\{incr}(\|k)$\ \&{else} $\|k\K1$;\2\6 +\4\&{until}\5 +$\|p=\\{cur\_spec}$;\2\6 +\&{if} $\\{chopped}>0$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"Curve\ out\ of\ range"})$;\5 +$\\{help4}(\.{"At\ least\ one\ of\ the\ coordinates\ in\ the\ path\ I\'m\ about% +\ to"})$\6 +$(\.{"digitize\ was\ really\ huge\ (potentially\ bigger\ than\ 4095)."})$\6 +$(\.{"So\ I\'ve\ cut\ it\ back\ to\ the\ maximum\ size."})$\6 +$(\.{"The\ results\ will\ probably\ be\ pretty\ wild."})$;\5 +\\{put\_get\_error};\6 +\&{end}\2\par +\U402.\fi + +\M405. We may need to get rid of constant ``dead'' cubics that clutter up +the data structure and interfere with autorounding. + +\Y\P$\4\X405:Declare subroutines needed by \\{make\_spec}\X\S$\6 +\4\&{procedure}\1\ \37$\\{remove\_cubic}(\|p:\\{pointer})$;\C{removes the +cubic following~\|p}\6 +\4\&{var} \37\|q: \37\\{pointer};\C{the node that disappears}\2\6 +\&{begin} \37$\|q\K\\{link}(\|p)$;\5 +$\\{right\_type}(\|p)\K\\{right\_type}(\|q)$;\5 +$\\{link}(\|p)\K\\{link}(\|q)$;\6 +$\\{x\_coord}(\|p)\K\\{x\_coord}(\|q)$;\5 +$\\{y\_coord}(\|p)\K\\{y\_coord}(\|q)$;\6 +$\\{right\_x}(\|p)\K\\{right\_x}(\|q)$;\5 +$\\{right\_y}(\|p)\K\\{right\_y}(\|q)$;\6 +$\\{free\_node}(\|q,\39\\{knot\_node\_size})$;\6 +\&{end};\par +\As406, 419, 426, 429, 431, 432, 433, 440\ETs451. +\U402.\fi + +\M406. The subdivision process proceeds by first swapping $x\swap-x$, if +necessary, to ensure that $x'\G0$; then swapping $y\swap-y$, if necessary, +to ensure that $y'\G0$; and finally swapping $x\swap y$, if necessary, +to ensure that $x'\G y'$. + +Recall that the octant codes have been defined in such a way that, for +example, $\\{third\_octant}=\\{first\_octant}+\\{negate\_x}+\\{switch\_x\_and% +\_y}$. The program +uses the fact that $\\{negate\_x}<\\{negate\_y}<\\{switch\_x\_and\_y}$ to +handle ``double +negation'': If \|c is an octant code that possibly involves \\{negate\_x} +and/or \\{negate\_y}, but not \\{switch\_x\_and\_y}, then negating~\|y changes~% +\|c +either to $\|c+\\{negate\_y}$ or $\|c-\\{negate\_y}$, depending on whether +$\|c\L\\{negate\_y}$ or $\|c>\\{negate\_y}$. Octant codes are always greater +than zero. + +The first step is to subdivide on \|x and \|y only, so that horizontal +and vertical autorounding can be done before we compare $x'$ to $y'$. + +\Y\P$\4\X405:Declare subroutines needed by \\{make\_spec}\X\mathrel{+}\S$\6 +\hbox{\4}\X410:Declare the procedure called \\{split\_cubic}\X\6 +\4\&{procedure}\1\ \37\\{quadrant\_subdivide};\6 +\4\&{label} \37$\\{continue},\39\\{exit}$;\6 +\4\&{var} \37$\|p,\39\|q,\39\|r,\39\|s,\39\\{pp},\39\\{qq}$: \37\\{pointer};% +\C{for traversing the lists}\6 +$\\{first\_x},\39\\{first\_y}$: \37\\{scaled};\C{unnegated coordinates of node % +\\{cur\_spec}}\6 +$\\{del1},\39\\{del2},\39\\{del3},\39\\{del},\39\\{dmax}$: \37\\{scaled};% +\C{proportional to the control points of a quadratic derived from a cubic}\6 +\|t: \37\\{fraction};\C{where a quadratic crosses zero}\6 +$\\{dest\_x},\39\\{dest\_y}$: \37\\{scaled};\C{final values of \|x and \|y in +the current cubic}\6 +\\{constant\_x}: \37\\{boolean};\C{is \|x constant between \|p and \|q?}\2\6 +\&{begin} \37$\|p\K\\{cur\_spec}$;\5 +$\\{first\_x}\K\\{x\_coord}(\\{cur\_spec})$;\5 +$\\{first\_y}\K\\{y\_coord}(\\{cur\_spec})$;\6 +\1\&{repeat} \37\\{continue}: \37$\|q\K\\{link}(\|p)$;\5 +\X407:Subdivide the cubic between \|p and \|q so that the results travel toward +the right halfplane\X;\6 +\X413:Subdivide all cubics between \|p and \|q so that the results travel +toward the first quadrant; but \&{return} or \&{goto} \\{continue} if the cubic +from \|p to \|q was dead\X;\6 +$\|p\K\|q$;\6 +\4\&{until}\5 +$\|p=\\{cur\_spec}$;\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M407. All three subdivision processes are similar, so it's possible to +get the general idea by studying the first one (which is the simplest). +The calculation makes use of the fact that the derivatives of +Bernshte{\u\i}n polynomials satisfy +$B'(z_0,z_1,\ldots,z_n;t)=nB(z_1-z_0,\ldots,z_n-z_{n-1};t)$. + +When this routine begins, $\\{right\_type}(\|p)$ is \\{explicit}; we should +set $\\{right\_type}(\|p)\K\\{first\_octant}$. However, no assignment is made, +because $\\{explicit}=\\{first\_octant}$. The author apologizes for using +such trickery here; it is really hard to do redundant computations +just for the sake of purity. + +\Y\P$\4\X407:Subdivide the cubic between \|p and \|q so that the results travel +toward the right halfplane\X\S$\6 +\&{if} $\|q=\\{cur\_spec}$ \1\&{then}\6 +\&{begin} \37$\\{dest\_x}\K\\{first\_x}$;\5 +$\\{dest\_y}\K\\{first\_y}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{dest\_x}\K\\{x\_coord}(\|q)$;\5 +$\\{dest\_y}\K\\{y\_coord}(\|q)$;\6 +\&{end};\2\6 +$\\{del1}\K\\{right\_x}(\|p)-\\{x\_coord}(\|p)$;\5 +$\\{del2}\K\\{left\_x}(\|q)-\\{right\_x}(\|p)$;\5 +$\\{del3}\K\\{dest\_x}-\\{left\_x}(\|q)$;\5 +\X408:Scale up \\{del1}, \\{del2}, and \\{del3} for greater accuracy; also set % +\\{del} to the first nonzero element of $(\\{del1},\\{del2},\\{del3})$\X;\6 +\&{if} $\\{del}=0$ \1\&{then}\5 +$\\{constant\_x}\K\\{true}$\6 +\4\&{else} \&{begin} \37$\\{constant\_x}\K\\{false}$;\6 +\&{if} $\\{del}<0$ \1\&{then}\5 +\X409:Complement the \|x coordinates of the cubic between \|p and~\|q\X;\2\6 +$\|t\K\\{crossing\_point}(\\{del1},\39\\{del2},\39\\{del3})$;\6 +\&{if} $\|t<\\{fraction\_one}$ \1\&{then}\5 +\X411:Subdivide the cubic with respect to $x'$, possibly twice\X;\2\6 +\&{end}\2\par +\U406.\fi + +\M408. If $\\{del1}=\\{del2}=\\{del3}=0$, it's impossible to obey the title of +this +section. We just set $\\{del}=0$ in that case. + +\Y\P$\4\X408:Scale up \\{del1}, \\{del2}, and \\{del3} for greater accuracy; +also set \\{del} to the first nonzero element of $(\\{del1},\\{del2},\\{del3})$% +\X\S$\6 +\&{if} $\\{del1}\I0$ \1\&{then}\5 +$\\{del}\K\\{del1}$\6 +\4\&{else} \&{if} $\\{del2}\I0$ \1\&{then}\5 +$\\{del}\K\\{del2}$\6 +\4\&{else} $\\{del}\K\\{del3}$;\2\2\6 +\&{if} $\\{del}\I0$ \1\&{then}\6 +\&{begin} \37$\\{dmax}\K\\{abs}(\\{del1})$;\6 +\&{if} $\\{abs}(\\{del2})>\\{dmax}$ \1\&{then}\5 +$\\{dmax}\K\\{abs}(\\{del2})$;\2\6 +\&{if} $\\{abs}(\\{del3})>\\{dmax}$ \1\&{then}\5 +$\\{dmax}\K\\{abs}(\\{del3})$;\2\6 +\&{while} $\\{dmax}<\\{fraction\_half}$ \1\&{do}\6 +\&{begin} \37$\\{double}(\\{dmax})$;\5 +$\\{double}(\\{del1})$;\5 +$\\{double}(\\{del2})$;\5 +$\\{double}(\\{del3})$;\6 +\&{end};\2\6 +\&{end}\2\par +\Us407, 413\ETs420.\fi + +\M409. During the subdivision phases of \\{make\_spec}, the \\{x\_coord} and % +\\{y\_coord} +fields of node~\|q are not transformed to agree with the octant +stated in $\\{right\_type}(\|p)$; they remain consistent with $\\{right\_type}(% +\|q)$. +But $\\{left\_x}(\|q)$ and $\\{left\_y}(\|q)$ are governed by $\\{right\_type}(% +\|p)$. + +\Y\P$\4\X409:Complement the \|x coordinates of the cubic between \|p and~\|q\X% +\S$\6 +\&{begin} \37$\\{negate}(\\{x\_coord}(\|p))$;\5 +$\\{negate}(\\{right\_x}(\|p))$;\5 +$\\{negate}(\\{left\_x}(\|q))$;\6 +$\\{negate}(\\{del1})$;\5 +$\\{negate}(\\{del2})$;\5 +$\\{negate}(\\{del3})$;\6 +$\\{negate}(\\{dest\_x})$;\5 +$\\{right\_type}(\|p)\K\\{first\_octant}+\\{negate\_x}$;\6 +\&{end}\par +\U407.\fi + +\M410. When a cubic is split at a \\{fraction} value \|t, we obtain two cubics +whose B\'ezier control points are obtained by a generalization of the +bisection process: The formula +`$z_k^{(j+1)}={1\over2}(z_k^{(j)}+z\k^{(j)})$' becomes +`$z_k^{(j+1)}=t[z_k^{(j)},z\k^{(j)}]$'. + +It is convenient to define a \.{WEB} macro \\{t\_of\_the\_way} such that +$\\{t\_of\_the\_way}(\|a)(\|b)$ expands to $\|a-(\|a-\|b)\ast\|t$, i.e., to $% +\|t[\|a,\|b]$. + +If $0\L\|t\L1$, the quantity $\|t[\|a,\|b]$ is always between \|a and~\|b, even +in +the presence of rounding errors. Our subroutines +also obey the identity $\|t[\|a,\|b]+\|t[\|b,\|a]=\|a+\|b$. + +\Y\P\D \37$\\{t\_of\_the\_way\_end}(\#)\S\#,\39\|t\={)}$\par +\P\D \37$\\{t\_of\_the\_way}(\#)\S\#-\\{take\_fraction}\={(}\#-\\{t\_of\_the% +\_way\_end}$\par +\Y\P$\4\X410:Declare the procedure called \\{split\_cubic}\X\S$\6 +\4\&{procedure}\1\ \37$\\{split\_cubic}(\|p:\\{pointer};\,\35\|t:\\{fraction};% +\,\35\\{xq},\39\\{yq}:\\{scaled})$;\C{splits the cubic after \|p}\6 +\4\&{var} \37\|v: \37\\{scaled};\C{an intermediate value}\6 +$\|q,\39\|r$: \37\\{pointer};\C{for list manipulation}\2\6 +\&{begin} \37$\|q\K\\{link}(\|p)$;\5 +$\|r\K\\{get\_node}(\\{knot\_node\_size})$;\5 +$\\{link}(\|p)\K\|r$;\5 +$\\{link}(\|r)\K\|q$;\6 +$\\{left\_type}(\|r)\K\\{left\_type}(\|q)$;\5 +$\\{right\_type}(\|r)\K\\{right\_type}(\|p)$;\7 +$\|v\K\\{t\_of\_the\_way}(\\{right\_x}(\|p))(\\{left\_x}(\|q))$;\5 +$\\{right\_x}(\|p)\K\\{t\_of\_the\_way}(\\{x\_coord}(\|p))(\\{right\_x}(\|p))$;% +\5 +$\\{left\_x}(\|q)\K\\{t\_of\_the\_way}(\\{left\_x}(\|q))(\\{xq})$;\5 +$\\{left\_x}(\|r)\K\\{t\_of\_the\_way}(\\{right\_x}(\|p))(\|v)$;\5 +$\\{right\_x}(\|r)\K\\{t\_of\_the\_way}(\|v)(\\{left\_x}(\|q))$;\5 +$\\{x\_coord}(\|r)\K\\{t\_of\_the\_way}(\\{left\_x}(\|r))(\\{right\_x}(\|r))$;\7 +$\|v\K\\{t\_of\_the\_way}(\\{right\_y}(\|p))(\\{left\_y}(\|q))$;\5 +$\\{right\_y}(\|p)\K\\{t\_of\_the\_way}(\\{y\_coord}(\|p))(\\{right\_y}(\|p))$;% +\5 +$\\{left\_y}(\|q)\K\\{t\_of\_the\_way}(\\{left\_y}(\|q))(\\{yq})$;\5 +$\\{left\_y}(\|r)\K\\{t\_of\_the\_way}(\\{right\_y}(\|p))(\|v)$;\5 +$\\{right\_y}(\|r)\K\\{t\_of\_the\_way}(\|v)(\\{left\_y}(\|q))$;\5 +$\\{y\_coord}(\|r)\K\\{t\_of\_the\_way}(\\{left\_y}(\|r))(\\{right\_y}(\|r))$;\6 +\&{end};\par +\U406.\fi + +\M411. Since $x'(t)$ is a quadratic equation, it can cross through zero +at~most twice. When it does cross zero, we make doubly sure that the +derivative is really zero at the splitting point, in case rounding errors +have caused the split cubic to have an apparently nonzero derivative. +We also make sure that the split cubic is monotonic. + +\Y\P$\4\X411:Subdivide the cubic with respect to $x'$, possibly twice\X\S$\6 +\&{begin} \37$\\{split\_cubic}(\|p,\39\|t,\39\\{dest\_x},\39\\{dest\_y})$;\5 +$\|r\K\\{link}(\|p)$;\6 +\&{if} $\\{right\_type}(\|r)>\\{negate\_x}$ \1\&{then}\5 +$\\{right\_type}(\|r)\K\\{first\_octant}$\6 +\4\&{else} $\\{right\_type}(\|r)\K\\{first\_octant}+\\{negate\_x}$;\2\6 +\&{if} $\\{x\_coord}(\|r)<\\{x\_coord}(\|p)$ \1\&{then}\5 +$\\{x\_coord}(\|r)\K\\{x\_coord}(\|p)$;\2\6 +$\\{left\_x}(\|r)\K\\{x\_coord}(\|r)$;\6 +\&{if} $\\{right\_x}(\|p)>\\{x\_coord}(\|r)$ \1\&{then}\5 +$\\{right\_x}(\|p)\K\\{x\_coord}(\|r)$;\C{we always have $\\{x\_coord}(\|p)\L% +\\{right\_x}(\|p)$}\2\6 +$\\{negate}(\\{x\_coord}(\|r))$;\5 +$\\{right\_x}(\|r)\K\\{x\_coord}(\|r)$;\5 +$\\{negate}(\\{left\_x}(\|q))$;\5 +$\\{negate}(\\{dest\_x})$;\6 +$\\{del2}\K\\{t\_of\_the\_way}(\\{del2})(\\{del3})$;\C{now $0,\\{del2},% +\\{del3}$ represent $x'$ on the remaining interval}\6 +\&{if} $\\{del2}>0$ \1\&{then}\5 +$\\{del2}\K0$;\2\6 +$\|t\K\\{crossing\_point}(0,\39-\\{del2},\39-\\{del3})$;\6 +\&{if} $\|t<\\{fraction\_one}$ \1\&{then}\5 +\X412:Subdivide the cubic a second time with respect to $x'$\X\6 +\4\&{else} \&{begin} \37\&{if} $\\{x\_coord}(\|r)>\\{dest\_x}$ \1\&{then}\6 +\&{begin} \37$\\{x\_coord}(\|r)\K\\{dest\_x}$;\5 +$\\{left\_x}(\|r)\K-\\{x\_coord}(\|r)$;\5 +$\\{right\_x}(\|r)\K\\{x\_coord}(\|r)$;\6 +\&{end};\2\6 +\&{if} $\\{left\_x}(\|q)>\\{dest\_x}$ \1\&{then}\5 +$\\{left\_x}(\|q)\K\\{dest\_x}$\6 +\4\&{else} \&{if} $\\{left\_x}(\|q)<\\{x\_coord}(\|r)$ \1\&{then}\5 +$\\{left\_x}(\|q)\K\\{x\_coord}(\|r)$;\2\2\6 +\&{end};\2\6 +\&{end}\par +\U407.\fi + +\M412. \P$\X412:Subdivide the cubic a second time with respect to $x'$\X\S$\6 +\&{begin} \37$\\{split\_cubic}(\|r,\39\|t,\39\\{dest\_x},\39\\{dest\_y})$;\5 +$\|s\K\\{link}(\|r)$;\6 +\&{if} $\\{x\_coord}(\|s)<\\{dest\_x}$ \1\&{then}\5 +$\\{x\_coord}(\|s)\K\\{dest\_x}$;\2\6 +\&{if} $\\{x\_coord}(\|s)<\\{x\_coord}(\|r)$ \1\&{then}\5 +$\\{x\_coord}(\|s)\K\\{x\_coord}(\|r)$;\2\6 +$\\{right\_type}(\|s)\K\\{right\_type}(\|p)$;\5 +$\\{left\_x}(\|s)\K\\{x\_coord}(\|s)$;\C{now $\\{x\_coord}(\|r)=\\{right\_x}(% +\|r)\L\\{left\_x}(\|s)$}\6 +\&{if} $\\{left\_x}(\|q)<\\{dest\_x}$ \1\&{then}\5 +$\\{left\_x}(\|q)\K-\\{dest\_x}$\6 +\4\&{else} \&{if} $\\{left\_x}(\|q)>\\{x\_coord}(\|s)$ \1\&{then}\5 +$\\{left\_x}(\|q)\K-\\{x\_coord}(\|s)$\6 +\4\&{else} $\\{negate}(\\{left\_x}(\|q))$;\2\2\6 +$\\{negate}(\\{x\_coord}(\|s))$;\5 +$\\{right\_x}(\|s)\K\\{x\_coord}(\|s)$;\6 +\&{end}\par +\U411.\fi + +\M413. The process of subdivision with respect to $y'$ is like that with +respect +to~$x'$, with the slight additional complication that two or three cubics +might now appear between \|p and~\|q. + +\Y\P$\4\X413:Subdivide all cubics between \|p and \|q so that the results +travel toward the first quadrant; but \&{return} or \&{goto} \\{continue} if +the cubic from \|p to \|q was dead\X\S$\6 +$\\{pp}\K\|p$;\6 +\1\&{repeat} \37$\\{qq}\K\\{link}(\\{pp})$;\5 +$\\{abnegate}(\\{x\_coord}(\\{qq}),\39\\{y\_coord}(\\{qq}),\39\\{right\_type}(% +\\{qq}),\39\\{right\_type}(\\{pp}))$;\5 +$\\{dest\_x}\K\\{cur\_x}$;\5 +$\\{dest\_y}\K\\{cur\_y}$;\6 +$\\{del1}\K\\{right\_y}(\\{pp})-\\{y\_coord}(\\{pp})$;\5 +$\\{del2}\K\\{left\_y}(\\{qq})-\\{right\_y}(\\{pp})$;\5 +$\\{del3}\K\\{dest\_y}-\\{left\_y}(\\{qq})$;\5 +\X408:Scale up \\{del1}, \\{del2}, and \\{del3} for greater accuracy; also set % +\\{del} to the first nonzero element of $(\\{del1},\\{del2},\\{del3})$\X;\6 +\&{if} $\\{del}\I0$ \1\&{then}\C{they weren't all zero}\6 +\&{begin} \37\&{if} $\\{del}<0$ \1\&{then}\5 +\X414:Complement the \|y coordinates of the cubic between \\{pp} and~\\{qq}\X;% +\2\6 +$\|t\K\\{crossing\_point}(\\{del1},\39\\{del2},\39\\{del3})$;\6 +\&{if} $\|t<\\{fraction\_one}$ \1\&{then}\5 +\X415:Subdivide the cubic with respect to $y'$, possibly twice\X;\2\6 +\&{end}\6 +\4\&{else} \X417:Do any special actions needed when \|y is constant; \&{return} +or \&{goto} \\{continue} if a dead cubic from \|p to \|q is removed\X;\2\6 +$\\{pp}\K\\{qq}$;\6 +\4\&{until}\5 +$\\{pp}=\|q$;\2\6 +\&{if} $\\{constant\_x}$ \1\&{then}\5 +\X418:Correct the octant code in segments with decreasing \|y\X\2\par +\U406.\fi + +\M414. \P$\X414:Complement the \|y coordinates of the cubic between \\{pp} and~% +\\{qq}\X\S$\6 +\&{begin} \37$\\{negate}(\\{y\_coord}(\\{pp}))$;\5 +$\\{negate}(\\{right\_y}(\\{pp}))$;\5 +$\\{negate}(\\{left\_y}(\\{qq}))$;\6 +$\\{negate}(\\{del1})$;\5 +$\\{negate}(\\{del2})$;\5 +$\\{negate}(\\{del3})$;\6 +$\\{negate}(\\{dest\_y})$;\5 +$\\{right\_type}(\\{pp})\K\\{right\_type}(\\{pp})+\\{negate\_y}$;\6 +\&{end}\par +\Us413\ET417.\fi + +\M415. \P$\X415:Subdivide the cubic with respect to $y'$, possibly twice\X\S$\6 +\&{begin} \37$\\{split\_cubic}(\\{pp},\39\|t,\39\\{dest\_x},\39\\{dest\_y})$;\5 +$\|r\K\\{link}(\\{pp})$;\6 +\&{if} $\\{right\_type}(\|r)>\\{negate\_y}$ \1\&{then}\5 +$\\{right\_type}(\|r)\K\\{right\_type}(\|r)-\\{negate\_y}$\6 +\4\&{else} $\\{right\_type}(\|r)\K\\{right\_type}(\|r)+\\{negate\_y}$;\2\6 +\&{if} $\\{y\_coord}(\|r)<\\{y\_coord}(\\{pp})$ \1\&{then}\5 +$\\{y\_coord}(\|r)\K\\{y\_coord}(\\{pp})$;\2\6 +$\\{left\_y}(\|r)\K\\{y\_coord}(\|r)$;\6 +\&{if} $\\{right\_y}(\\{pp})>\\{y\_coord}(\|r)$ \1\&{then}\5 +$\\{right\_y}(\\{pp})\K\\{y\_coord}(\|r)$;\C{we always have $\\{y\_coord}(% +\\{pp})\L\\{right\_y}(\\{pp})$}\2\6 +$\\{negate}(\\{y\_coord}(\|r))$;\5 +$\\{right\_y}(\|r)\K\\{y\_coord}(\|r)$;\5 +$\\{negate}(\\{left\_y}(\\{qq}))$;\5 +$\\{negate}(\\{dest\_y})$;\6 +\&{if} $\\{x\_coord}(\|r)<\\{x\_coord}(\\{pp})$ \1\&{then}\5 +$\\{x\_coord}(\|r)\K\\{x\_coord}(\\{pp})$\6 +\4\&{else} \&{if} $\\{x\_coord}(\|r)>\\{dest\_x}$ \1\&{then}\5 +$\\{x\_coord}(\|r)\K\\{dest\_x}$;\2\2\6 +\&{if} $\\{left\_x}(\|r)>\\{x\_coord}(\|r)$ \1\&{then}\6 +\&{begin} \37$\\{left\_x}(\|r)\K\\{x\_coord}(\|r)$;\6 +\&{if} $\\{right\_x}(\\{pp})>\\{x\_coord}(\|r)$ \1\&{then}\5 +$\\{right\_x}(\\{pp})\K\\{x\_coord}(\|r)$;\2\6 +\&{end};\2\6 +\&{if} $\\{right\_x}(\|r)<\\{x\_coord}(\|r)$ \1\&{then}\6 +\&{begin} \37$\\{right\_x}(\|r)\K\\{x\_coord}(\|r)$;\6 +\&{if} $\\{left\_x}(\\{qq})<\\{x\_coord}(\|r)$ \1\&{then}\5 +$\\{left\_x}(\\{qq})\K\\{x\_coord}(\|r)$;\2\6 +\&{end};\2\6 +$\\{del2}\K\\{t\_of\_the\_way}(\\{del2})(\\{del3})$;\C{now $0,\\{del2},% +\\{del3}$ represent $y'$ on the remaining interval}\6 +\&{if} $\\{del2}>0$ \1\&{then}\5 +$\\{del2}\K0$;\2\6 +$\|t\K\\{crossing\_point}(0,\39-\\{del2},\39-\\{del3})$;\6 +\&{if} $\|t<\\{fraction\_one}$ \1\&{then}\5 +\X416:Subdivide the cubic a second time with respect to $y'$\X\6 +\4\&{else} \&{begin} \37\&{if} $\\{y\_coord}(\|r)>\\{dest\_y}$ \1\&{then}\6 +\&{begin} \37$\\{y\_coord}(\|r)\K\\{dest\_y}$;\5 +$\\{left\_y}(\|r)\K-\\{y\_coord}(\|r)$;\5 +$\\{right\_y}(\|r)\K\\{y\_coord}(\|r)$;\6 +\&{end};\2\6 +\&{if} $\\{left\_y}(\\{qq})>\\{dest\_y}$ \1\&{then}\5 +$\\{left\_y}(\\{qq})\K\\{dest\_y}$\6 +\4\&{else} \&{if} $\\{left\_y}(\\{qq})<\\{y\_coord}(\|r)$ \1\&{then}\5 +$\\{left\_y}(\\{qq})\K\\{y\_coord}(\|r)$;\2\2\6 +\&{end};\2\6 +\&{end}\par +\U413.\fi + +\M416. \P$\X416:Subdivide the cubic a second time with respect to $y'$\X\S$\6 +\&{begin} \37$\\{split\_cubic}(\|r,\39\|t,\39\\{dest\_x},\39\\{dest\_y})$;\5 +$\|s\K\\{link}(\|r)$;\6 +\&{if} $\\{y\_coord}(\|s)<\\{dest\_y}$ \1\&{then}\5 +$\\{y\_coord}(\|s)\K\\{dest\_y}$;\2\6 +\&{if} $\\{y\_coord}(\|s)<\\{y\_coord}(\|r)$ \1\&{then}\5 +$\\{y\_coord}(\|s)\K\\{y\_coord}(\|r)$;\2\6 +$\\{right\_type}(\|s)\K\\{right\_type}(\\{pp})$;\5 +$\\{left\_y}(\|s)\K\\{y\_coord}(\|s)$;\C{now $\\{y\_coord}(\|r)=\\{right\_y}(% +\|r)\L\\{left\_y}(\|s)$}\6 +\&{if} $\\{left\_y}(\\{qq})<\\{dest\_y}$ \1\&{then}\5 +$\\{left\_y}(\\{qq})\K-\\{dest\_y}$\6 +\4\&{else} \&{if} $\\{left\_y}(\\{qq})>\\{y\_coord}(\|s)$ \1\&{then}\5 +$\\{left\_y}(\\{qq})\K-\\{y\_coord}(\|s)$\6 +\4\&{else} $\\{negate}(\\{left\_y}(\\{qq}))$;\2\2\6 +$\\{negate}(\\{y\_coord}(\|s))$;\5 +$\\{right\_y}(\|s)\K\\{y\_coord}(\|s)$;\6 +\&{if} $\\{x\_coord}(\|s)<\\{x\_coord}(\|r)$ \1\&{then}\5 +$\\{x\_coord}(\|s)\K\\{x\_coord}(\|r)$\6 +\4\&{else} \&{if} $\\{x\_coord}(\|s)>\\{dest\_x}$ \1\&{then}\5 +$\\{x\_coord}(\|s)\K\\{dest\_x}$;\2\2\6 +\&{if} $\\{left\_x}(\|s)>\\{x\_coord}(\|s)$ \1\&{then}\6 +\&{begin} \37$\\{left\_x}(\|s)\K\\{x\_coord}(\|s)$;\6 +\&{if} $\\{right\_x}(\|r)>\\{x\_coord}(\|s)$ \1\&{then}\5 +$\\{right\_x}(\|r)\K\\{x\_coord}(\|s)$;\2\6 +\&{end};\2\6 +\&{if} $\\{right\_x}(\|s)<\\{x\_coord}(\|s)$ \1\&{then}\6 +\&{begin} \37$\\{right\_x}(\|s)\K\\{x\_coord}(\|s)$;\6 +\&{if} $\\{left\_x}(\\{qq})<\\{x\_coord}(\|s)$ \1\&{then}\5 +$\\{left\_x}(\\{qq})\K\\{x\_coord}(\|s)$;\2\6 +\&{end};\2\6 +\&{end}\par +\U415.\fi + +\M417. If the cubic is constant in $y$ and increasing in $x$, we have +classified +it as traveling in the first octant. If the cubic is constant +in~$y$ and decreasing in~$x$, it is desirable to classify it as traveling +in the fifth octant (not the fourth), because autorounding will be consistent +with respect to doublepaths only if the octant number changes by four when +the path is reversed. Therefore we negate the $y$~coordinates +when they are constant but the curve is decreasing in~$x$; this gives +the desired result except in pathological paths. + +If the cubic is ``dead,'' i.e., constant in both \|x and \|y, we remove +it unless it is the only cubic in the entire path. We \&{goto} \\{continue} +if it wasn't the final cubic, so that the test $\|p=\\{cur\_spec}$ does not +falsely imply that all cubics have been processed. + +\Y\P$\4\X417:Do any special actions needed when \|y is constant; \&{return} or % +\&{goto} \\{continue} if a dead cubic from \|p to \|q is removed\X\S$\6 +\&{if} $\\{constant\_x}$ \1\&{then}\C{$\|p=\\{pp}$, $\|q=\\{qq}$, and the cubic +is dead}\6 +\&{begin} \37\&{if} $\|q\I\|p$ \1\&{then}\6 +\&{begin} \37$\\{remove\_cubic}(\|p)$;\C{remove the dead cycle and recycle node +\|q}\6 +\&{if} $\\{cur\_spec}\I\|q$ \1\&{then}\5 +\&{goto} \37\\{continue}\6 +\4\&{else} \&{begin} \37$\\{cur\_spec}\K\|p$;\5 +\&{return};\6 +\&{end};\C{the final cubic was dead and is gone}\2\6 +\&{end};\2\6 +\&{end}\6 +\4\&{else} \&{if} $\R\\{odd}(\\{right\_type}(\\{pp}))$ \1\&{then}\C{the $x$ +coordinates were negated}\6 +\X414:Complement the \|y coordinates of the cubic between \\{pp} and~\\{qq}\X\2% +\2\par +\U413.\fi + +\M418. A similar correction to octant codes deserves to be made when \|x is +constant and \|y is decreasing. + +\Y\P$\4\X418:Correct the octant code in segments with decreasing \|y\X\S$\6 +\&{begin} \37$\\{pp}\K\|p$;\6 +\1\&{repeat} \37$\\{qq}\K\\{link}(\\{pp})$;\6 +\&{if} $\\{right\_type}(\\{pp})>\\{negate\_y}$ \1\&{then}\C{the $y$ coordinates +were negated}\6 +\&{begin} \37$\\{right\_type}(\\{pp})\K\\{right\_type}(\\{pp})+\\{negate\_x}$;\5 +$\\{negate}(\\{x\_coord}(\\{pp}))$;\5 +$\\{negate}(\\{right\_x}(\\{pp}))$;\5 +$\\{negate}(\\{left\_x}(\\{qq}))$;\6 +\&{end};\2\6 +$\\{pp}\K\\{qq}$;\6 +\4\&{until}\5 +$\\{pp}=\|q$;\2\6 +\&{end}\par +\U413.\fi + +\M419. Finally, the process of subdividing to make $x'\G y'$ is like the other +two subdivisions, with a few new twists. We skew the coordinates at this time. + +\Y\P$\4\X405:Declare subroutines needed by \\{make\_spec}\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{octant\_subdivide};\6 +\4\&{var} \37$\|p,\39\|q,\39\|r,\39\|s$: \37\\{pointer};\C{for traversing the +lists}\6 +$\\{del1},\39\\{del2},\39\\{del3},\39\\{del},\39\\{dmax}$: \37\\{scaled};% +\C{proportional to the control points of a quadratic derived from a cubic}\6 +\|t: \37\\{fraction};\C{where a quadratic crosses zero}\6 +$\\{dest\_x},\39\\{dest\_y}$: \37\\{scaled};\C{final values of \|x and \|y in +the current cubic}\2\6 +\&{begin} \37$\|p\K\\{cur\_spec}$;\6 +\1\&{repeat} \37$\|q\K\\{link}(\|p)$;\6 +$\\{x\_coord}(\|p)\K\\{x\_coord}(\|p)-\\{y\_coord}(\|p)$;\5 +$\\{right\_x}(\|p)\K\\{right\_x}(\|p)-\\{right\_y}(\|p)$;\5 +$\\{left\_x}(\|q)\K\\{left\_x}(\|q)-\\{left\_y}(\|q)$;\6 +\X420:Subdivide the cubic between \|p and \|q so that the results travel toward +the first octant\X;\6 +$\|p\K\|q$;\6 +\4\&{until}\5 +$\|p=\\{cur\_spec}$;\2\6 +\&{end};\par +\fi + +\M420. \P$\X420:Subdivide the cubic between \|p and \|q so that the results +travel toward the first octant\X\S$\6 +\X421:Set up the variables $(\\{del1},\\{del2},\\{del3})$ to represent $x'-y'$% +\X;\6 +\X408:Scale up \\{del1}, \\{del2}, and \\{del3} for greater accuracy; also set % +\\{del} to the first nonzero element of $(\\{del1},\\{del2},\\{del3})$\X;\6 +\&{if} $\\{del}\I0$ \1\&{then}\C{they weren't all zero}\6 +\&{begin} \37\&{if} $\\{del}<0$ \1\&{then}\5 +\X423:Swap the \|x and \|y coordinates of the cubic between \|p and~\|q\X;\2\6 +$\|t\K\\{crossing\_point}(\\{del1},\39\\{del2},\39\\{del3})$;\6 +\&{if} $\|t<\\{fraction\_one}$ \1\&{then}\5 +\X424:Subdivide the cubic with respect to $x'-y'$, possibly twice\X;\2\6 +\&{end}\2\par +\U419.\fi + +\M421. \P$\X421:Set up the variables $(\\{del1},\\{del2},\\{del3})$ to +represent $x'-y'$\X\S$\6 +\&{if} $\|q=\\{cur\_spec}$ \1\&{then}\6 +\&{begin} \37$\\{unskew}(\\{x\_coord}(\|q),\39\\{y\_coord}(\|q),\39\\{right% +\_type}(\|q))$;\5 +$\\{skew}(\\{cur\_x},\39\\{cur\_y},\39\\{right\_type}(\|p))$;\5 +$\\{dest\_x}\K\\{cur\_x}$;\5 +$\\{dest\_y}\K\\{cur\_y}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{abnegate}(\\{x\_coord}(\|q),\39\\{y\_coord}(\|q),% +\39\\{right\_type}(\|q),\39\\{right\_type}(\|p))$;\5 +$\\{dest\_x}\K\\{cur\_x}-\\{cur\_y}$;\5 +$\\{dest\_y}\K\\{cur\_y}$;\6 +\&{end};\2\6 +$\\{del1}\K\\{right\_x}(\|p)-\\{x\_coord}(\|p)$;\5 +$\\{del2}\K\\{left\_x}(\|q)-\\{right\_x}(\|p)$;\5 +$\\{del3}\K\\{dest\_x}-\\{left\_x}(\|q)$\par +\U420.\fi + +\M422. The swapping here doesn't simply interchange \|x and \|y values, +because the coordinates are skewed. It turns out that this is easier +than ordinary swapping, because it can be done in two assignment statements +rather than three. + +\fi + +\M423. \P$\X423:Swap the \|x and \|y coordinates of the cubic between \|p and~% +\|q\X\S$\6 +\&{begin} \37$\\{y\_coord}(\|p)\K\\{x\_coord}(\|p)+\\{y\_coord}(\|p)$;\5 +$\\{negate}(\\{x\_coord}(\|p))$;\6 +$\\{right\_y}(\|p)\K\\{right\_x}(\|p)+\\{right\_y}(\|p)$;\5 +$\\{negate}(\\{right\_x}(\|p))$;\6 +$\\{left\_y}(\|q)\K\\{left\_x}(\|q)+\\{left\_y}(\|q)$;\5 +$\\{negate}(\\{left\_x}(\|q))$;\6 +$\\{negate}(\\{del1})$;\5 +$\\{negate}(\\{del2})$;\5 +$\\{negate}(\\{del3})$;\6 +$\\{dest\_y}\K\\{dest\_x}+\\{dest\_y}$;\5 +$\\{negate}(\\{dest\_x})$;\6 +$\\{right\_type}(\|p)\K\\{right\_type}(\|p)+\\{switch\_x\_and\_y}$;\6 +\&{end}\par +\U420.\fi + +\M424. A somewhat tedious case analysis is carried out here to make sure that +nasty rounding errors don't destroy our assumptions of monotonicity. + +\Y\P$\4\X424:Subdivide the cubic with respect to $x'-y'$, possibly twice\X\S$\6 +\&{begin} \37$\\{split\_cubic}(\|p,\39\|t,\39\\{dest\_x},\39\\{dest\_y})$;\5 +$\|r\K\\{link}(\|p)$;\6 +\&{if} $\\{right\_type}(\|r)>\\{switch\_x\_and\_y}$ \1\&{then}\5 +$\\{right\_type}(\|r)\K\\{right\_type}(\|r)-\\{switch\_x\_and\_y}$\6 +\4\&{else} $\\{right\_type}(\|r)\K\\{right\_type}(\|r)+\\{switch\_x\_and\_y}$;% +\2\6 +\&{if} $\\{y\_coord}(\|r)<\\{y\_coord}(\|p)$ \1\&{then}\5 +$\\{y\_coord}(\|r)\K\\{y\_coord}(\|p)$\6 +\4\&{else} \&{if} $\\{y\_coord}(\|r)>\\{dest\_y}$ \1\&{then}\5 +$\\{y\_coord}(\|r)\K\\{dest\_y}$;\2\2\6 +\&{if} $\\{x\_coord}(\|p)+\\{y\_coord}(\|r)>\\{dest\_x}+\\{dest\_y}$ \1\&{then}% +\5 +$\\{y\_coord}(\|r)\K\\{dest\_x}+\\{dest\_y}-\\{x\_coord}(\|p)$;\2\6 +\&{if} $\\{left\_y}(\|r)>\\{y\_coord}(\|r)$ \1\&{then}\6 +\&{begin} \37$\\{left\_y}(\|r)\K\\{y\_coord}(\|r)$;\6 +\&{if} $\\{right\_y}(\|p)>\\{y\_coord}(\|r)$ \1\&{then}\5 +$\\{right\_y}(\|p)\K\\{y\_coord}(\|r)$;\2\6 +\&{end};\2\6 +\&{if} $\\{right\_y}(\|r)<\\{y\_coord}(\|r)$ \1\&{then}\6 +\&{begin} \37$\\{right\_y}(\|r)\K\\{y\_coord}(\|r)$;\6 +\&{if} $\\{left\_y}(\|q)<\\{y\_coord}(\|r)$ \1\&{then}\5 +$\\{left\_y}(\|q)\K\\{y\_coord}(\|r)$;\2\6 +\&{end};\2\6 +\&{if} $\\{x\_coord}(\|r)<\\{x\_coord}(\|p)$ \1\&{then}\5 +$\\{x\_coord}(\|r)\K\\{x\_coord}(\|p)$\6 +\4\&{else} \&{if} $\\{x\_coord}(\|r)+\\{y\_coord}(\|r)>\\{dest\_x}+\\{dest\_y}$ +\1\&{then}\5 +$\\{x\_coord}(\|r)\K\\{dest\_x}+\\{dest\_y}-\\{y\_coord}(\|r)$;\2\2\6 +$\\{left\_x}(\|r)\K\\{x\_coord}(\|r)$;\6 +\&{if} $\\{right\_x}(\|p)>\\{x\_coord}(\|r)$ \1\&{then}\5 +$\\{right\_x}(\|p)\K\\{x\_coord}(\|r)$;\C{we always have $\\{x\_coord}(\|p)\L% +\\{right\_x}(\|p)$}\2\6 +$\\{y\_coord}(\|r)\K\\{y\_coord}(\|r)+\\{x\_coord}(\|r)$;\5 +$\\{right\_y}(\|r)\K\\{right\_y}(\|r)+\\{x\_coord}(\|r)$;\6 +$\\{negate}(\\{x\_coord}(\|r))$;\5 +$\\{right\_x}(\|r)\K\\{x\_coord}(\|r)$;\6 +$\\{left\_y}(\|q)\K\\{left\_y}(\|q)+\\{left\_x}(\|q)$;\5 +$\\{negate}(\\{left\_x}(\|q))$;\6 +$\\{dest\_y}\K\\{dest\_y}+\\{dest\_x}$;\5 +$\\{negate}(\\{dest\_x})$;\6 +\&{if} $\\{right\_y}(\|r)<\\{y\_coord}(\|r)$ \1\&{then}\6 +\&{begin} \37$\\{right\_y}(\|r)\K\\{y\_coord}(\|r)$;\6 +\&{if} $\\{left\_y}(\|q)<\\{y\_coord}(\|r)$ \1\&{then}\5 +$\\{left\_y}(\|q)\K\\{y\_coord}(\|r)$;\2\6 +\&{end};\2\6 +$\\{del2}\K\\{t\_of\_the\_way}(\\{del2})(\\{del3})$;\C{now $0,\\{del2},% +\\{del3}$ represent $x'-y'$ on the remaining interval}\6 +\&{if} $\\{del2}>0$ \1\&{then}\5 +$\\{del2}\K0$;\2\6 +$\|t\K\\{crossing\_point}(0,\39-\\{del2},\39-\\{del3})$;\6 +\&{if} $\|t<\\{fraction\_one}$ \1\&{then}\5 +\X425:Subdivide the cubic a second time with respect to $x'-y'$\X\6 +\4\&{else} \&{begin} \37\&{if} $\\{x\_coord}(\|r)>\\{dest\_x}$ \1\&{then}\6 +\&{begin} \37$\\{x\_coord}(\|r)\K\\{dest\_x}$;\5 +$\\{left\_x}(\|r)\K-\\{x\_coord}(\|r)$;\5 +$\\{right\_x}(\|r)\K\\{x\_coord}(\|r)$;\6 +\&{end};\2\6 +\&{if} $\\{left\_x}(\|q)>\\{dest\_x}$ \1\&{then}\5 +$\\{left\_x}(\|q)\K\\{dest\_x}$\6 +\4\&{else} \&{if} $\\{left\_x}(\|q)<\\{x\_coord}(\|r)$ \1\&{then}\5 +$\\{left\_x}(\|q)\K\\{x\_coord}(\|r)$;\2\2\6 +\&{end};\2\6 +\&{end}\par +\U420.\fi + +\M425. \P$\X425:Subdivide the cubic a second time with respect to $x'-y'$\X\S$\6 +\&{begin} \37$\\{split\_cubic}(\|r,\39\|t,\39\\{dest\_x},\39\\{dest\_y})$;\5 +$\|s\K\\{link}(\|r)$;\6 +\&{if} $\\{y\_coord}(\|s)<\\{y\_coord}(\|r)$ \1\&{then}\5 +$\\{y\_coord}(\|s)\K\\{y\_coord}(\|r)$\6 +\4\&{else} \&{if} $\\{y\_coord}(\|s)>\\{dest\_y}$ \1\&{then}\5 +$\\{y\_coord}(\|s)\K\\{dest\_y}$;\2\2\6 +\&{if} $\\{x\_coord}(\|r)+\\{y\_coord}(\|s)>\\{dest\_x}+\\{dest\_y}$ \1\&{then}% +\5 +$\\{y\_coord}(\|s)\K\\{dest\_x}+\\{dest\_y}-\\{x\_coord}(\|r)$;\2\6 +\&{if} $\\{left\_y}(\|s)>\\{y\_coord}(\|s)$ \1\&{then}\6 +\&{begin} \37$\\{left\_y}(\|s)\K\\{y\_coord}(\|s)$;\6 +\&{if} $\\{right\_y}(\|r)>\\{y\_coord}(\|s)$ \1\&{then}\5 +$\\{right\_y}(\|r)\K\\{y\_coord}(\|s)$;\2\6 +\&{end};\2\6 +\&{if} $\\{right\_y}(\|s)<\\{y\_coord}(\|s)$ \1\&{then}\6 +\&{begin} \37$\\{right\_y}(\|s)\K\\{y\_coord}(\|s)$;\6 +\&{if} $\\{left\_y}(\|q)<\\{y\_coord}(\|s)$ \1\&{then}\5 +$\\{left\_y}(\|q)\K\\{y\_coord}(\|s)$;\2\6 +\&{end};\2\6 +\&{if} $\\{x\_coord}(\|s)+\\{y\_coord}(\|s)>\\{dest\_x}+\\{dest\_y}$ \1\&{then}% +\5 +$\\{x\_coord}(\|s)\K\\{dest\_x}+\\{dest\_y}-\\{y\_coord}(\|s)$\6 +\4\&{else} \&{begin} \37\&{if} $\\{x\_coord}(\|s)<\\{dest\_x}$ \1\&{then}\5 +$\\{x\_coord}(\|s)\K\\{dest\_x}$;\2\6 +\&{if} $\\{x\_coord}(\|s)<\\{x\_coord}(\|r)$ \1\&{then}\5 +$\\{x\_coord}(\|s)\K\\{x\_coord}(\|r)$;\2\6 +\&{end};\2\6 +$\\{right\_type}(\|s)\K\\{right\_type}(\|p)$;\5 +$\\{left\_x}(\|s)\K\\{x\_coord}(\|s)$;\C{now $\\{x\_coord}(\|r)=\\{right\_x}(% +\|r)\L\\{left\_x}(\|s)$}\6 +\&{if} $\\{left\_x}(\|q)<\\{dest\_x}$ \1\&{then}\6 +\&{begin} \37$\\{left\_y}(\|q)\K\\{left\_y}(\|q)+\\{dest\_x}$;\5 +$\\{left\_x}(\|q)\K-\\{dest\_x}$;\ \&{end}\6 +\4\&{else} \&{if} $\\{left\_x}(\|q)>\\{x\_coord}(\|s)$ \1\&{then}\6 +\&{begin} \37$\\{left\_y}(\|q)\K\\{left\_y}(\|q)+\\{x\_coord}(\|s)$;\5 +$\\{left\_x}(\|q)\K-\\{x\_coord}(\|s)$;\ \&{end}\6 +\4\&{else} \&{begin} \37$\\{left\_y}(\|q)\K\\{left\_y}(\|q)+\\{left\_x}(\|q)$;\5 +$\\{negate}(\\{left\_x}(\|q))$;\ \&{end};\2\2\6 +$\\{y\_coord}(\|s)\K\\{y\_coord}(\|s)+\\{x\_coord}(\|s)$;\5 +$\\{right\_y}(\|s)\K\\{right\_y}(\|s)+\\{x\_coord}(\|s)$;\6 +$\\{negate}(\\{x\_coord}(\|s))$;\5 +$\\{right\_x}(\|s)\K\\{x\_coord}(\|s)$;\6 +\&{if} $\\{right\_y}(\|s)<\\{y\_coord}(\|s)$ \1\&{then}\6 +\&{begin} \37$\\{right\_y}(\|s)\K\\{y\_coord}(\|s)$;\6 +\&{if} $\\{left\_y}(\|q)<\\{y\_coord}(\|s)$ \1\&{then}\5 +$\\{left\_y}(\|q)\K\\{y\_coord}(\|s)$;\2\6 +\&{end};\2\6 +\&{end}\par +\U424.\fi + +\M426. It's time now to consider ``autorounding,'' which tries to make +horizontal, +vertical, and diagonal tangents occur at places that will produce appropriate +images after the curve is digitized. + +The first job is to fix things so that $\|x(\|t)$ is an integer multiple of the +current ``granularity'' when the derivative $x'(t)$ crosses through zero. +The given cyclic path contains regions where $x'(t)\G0$ and regions +where $x'(t)\L0$. The \\{quadrant\_subdivide} routine is called into action +before any of the path coordinates have been skewed, but some of them +may have been negated. In regions where $x'(t)\G0$ we have $\\{right\_type}=% +\\{first\_octant}$ or $\\{right\_type}=\\{eighth\_octant}$; in regions where +$x'(t)\L0$, +we have $\\{right\_type}=\\{fifth\_octant}$ or $\\{right\_type}=\\{fourth% +\_octant}$. + +Within any such region the transformed $x$ values increase monotonically +from, say, $x_0$ to~$x_1$. We want to modify things by applying a linear +transformation to all $x$ coordinates in the region, after which +the $x$ values will increase monotonically from round$(x_0)$ to round$(x_1)$. + +This rounding scheme sounds quite simple, and it usually is. But several +complications can arise that might make the task more difficult. In the +first place, autorounding is inappropriate at cusps where $x'$ jumps +discontinuously past zero without ever being zero. In the second place, +the current pen might be unsymmetric in such a way that $x$ coordinates +should round differently when $x'$ becomes positive than when it becomes +negative. These considerations imply that round$(x_0)$ might be greater +than round$(x_1)$, even though $x_0\L x_1$; in such cases we do not want +to carry out the linear transformation. Furthermore, it's possible to have +round$(x_1)-\hbox{round} (x_0)$ positive but much greater than $x_1-x_0$; +then the transformation might distort the curve drastically, and again we +want to avoid it. Finally, the rounded points must be consistent between +adjacent regions, hence we can't transform one region without knowing +about its neighbors. + +To handle all these complications, we must first look at the whole +cycle and choose rounded $x$ values that are ``safe.'' The following +procedure does this: Given $m$~values $(b_0,b_1,\ldots,b_{m-1})$ before +rounding and $m$~corresponding values $(a_0,a_1,\ldots,a_{m-1})$ that would +be desirable after rounding, the \\{make\_safe} routine sets $a$'s to $b$'s +if necessary so that $0\L(a\k-a_k)/(b\k-b_k)\L2$ afterwards. It is +symmetric under cyclic permutation, reversal, and/or negation of the inputs. +(Instead of \|a, \|b, and~\|m, the program uses the names \\{after}, +\\{before}, and \\{cur\_rounding\_ptr}.) + +\Y\P$\4\X405:Declare subroutines needed by \\{make\_spec}\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{make\_safe};\6 +\4\&{var} \37\|k: \37$0\to\\{max\_wiggle}$;\C{runs through the list of inputs}\6 +\\{all\_safe}: \37\\{boolean};\C{does everything look OK so far?}\6 +\\{next\_a}: \37\\{scaled};\C{$\\{after}[\|k]$ before it might have changed}\6 +$\\{delta\_a},\39\\{delta\_b}$: \37\\{scaled};\C{$\\{after}[\|k+1]-\\{after}[% +\|k]$ and $\\{before}[\|k+1]-\\{before}[\|k]$}\2\6 +\&{begin} \37$\\{before}[\\{cur\_rounding\_ptr}]\K\\{before}[0]$;\C{wrap +around}\6 +$\\{node\_to\_round}[\\{cur\_rounding\_ptr}]\K\\{node\_to\_round}[0]$;\6 +\1\&{repeat} \37$\\{after}[\\{cur\_rounding\_ptr}]\K\\{after}[0]$;\5 +$\\{all\_safe}\K\\{true}$;\5 +$\\{next\_a}\K\\{after}[0]$;\6 +\&{for} $\|k\K0\mathrel{\&{to}}\\{cur\_rounding\_ptr}-1$ \1\&{do}\6 +\&{begin} \37$\\{delta\_b}\K\\{before}[\|k+1]-\\{before}[\|k]$;\6 +\&{if} $\\{delta\_b}\G0$ \1\&{then}\5 +$\\{delta\_a}\K\\{after}[\|k+1]-\\{next\_a}$\6 +\4\&{else} $\\{delta\_a}\K\\{next\_a}-\\{after}[\|k+1]$;\2\6 +$\\{next\_a}\K\\{after}[\|k+1]$;\6 +\&{if} $(\\{delta\_a}<0)\V(\\{delta\_a}>\\{abs}(\\{delta\_b}+\\{delta\_b}))$ \1% +\&{then}\6 +\&{begin} \37$\\{all\_safe}\K\\{false}$;\5 +$\\{after}[\|k]\K\\{before}[\|k]$;\6 +\&{if} $\|k=\\{cur\_rounding\_ptr}-1$ \1\&{then}\5 +$\\{after}[0]\K\\{before}[0]$\6 +\4\&{else} $\\{after}[\|k+1]\K\\{before}[\|k+1]$;\2\6 +\&{end};\2\6 +\&{end};\2\6 +\4\&{until}\5 +\\{all\_safe};\2\6 +\&{end};\par +\fi + +\M427. The global arrays used by \\{make\_safe} are accompanied by an array of +pointers into the current knot list. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4$\\{before},\39\\{after}$: \37\&{array} $[0\to\\{max\_wiggle}]$ \1\&{of}\5 +\\{scaled};\C{data for \\{make\_safe}}\2\6 +\4\\{node\_to\_round}: \37\&{array} $[0\to\\{max\_wiggle}]$ \1\&{of}\5 +\\{pointer};\C{reference back to the path}\2\6 +\4\\{cur\_rounding\_ptr}: \37$0\to\\{max\_wiggle}$;\C{how many are being used}\6 +\4\\{max\_rounding\_ptr}: \37$0\to\\{max\_wiggle}$;\C{how many have been used}% +\par +\fi + +\M428. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{max\_rounding\_ptr}\K0$;\par +\fi + +\M429. New entries go into the tables via the \\{before\_and\_after} routine: + +\Y\P$\4\X405:Declare subroutines needed by \\{make\_spec}\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{before\_and\_after}(\|b,\39\|a:\\{scaled};\,\35\|p:% +\\{pointer})$;\2\6 +\&{begin} \37\&{if} $\\{cur\_rounding\_ptr}=\\{max\_rounding\_ptr}$ \1\&{then}\6 +\&{if} $\\{max\_rounding\_ptr}<\\{max\_wiggle}$ \1\&{then}\5 +$\\{incr}(\\{max\_rounding\_ptr})$\6 +\4\&{else} $\\{overflow}(\.{"rounding\ table\ size"},\39\\{max\_wiggle})$;\2\2\6 +$\\{after}[\\{cur\_rounding\_ptr}]\K\|a$;\5 +$\\{before}[\\{cur\_rounding\_ptr}]\K\|b$;\5 +$\\{node\_to\_round}[\\{cur\_rounding\_ptr}]\K\|p$;\5 +$\\{incr}(\\{cur\_rounding\_ptr})$;\6 +\&{end};\par +\fi + +\M430. A global variable called \\{cur\_gran} is used instead of $\\{internal}[% +\\{granularity}]$, because we want to work with a number that's guaranteed to +be positive. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{cur\_gran}: \37\\{scaled};\C{the current granularity (which normally is % +\\{unity})}\par +\fi + +\M431. The \\{good\_val} function computes a number \|a that's as close as +possible to~\|b, with the property that $\|a+\|o$ is a multiple of +\\{cur\_gran}. + +If we assume that \\{cur\_gran} is even (since it will in fact be a multiple +of \\{unity} in all reasonable applications), we have the identity +$\\{good\_val}(-\|b-1,-\|o)=-\\{good\_val}(\|b,\|o)$. + +\Y\P$\4\X405:Declare subroutines needed by \\{make\_spec}\X\mathrel{+}\S$\6 +\4\&{function}\1\ \37$\\{good\_val}(\|b,\39\|o:\\{scaled})$: \37\\{scaled};\6 +\4\&{var} \37\|a: \37\\{scaled};\C{accumulator}\2\6 +\&{begin} \37$\|a\K\|b+\|o$;\6 +\&{if} $\|a\G0$ \1\&{then}\5 +$\|a\K\|a-(\|a\mathbin{\&{mod}}\\{cur\_gran})-\|o$\6 +\4\&{else} $\|a\K\|a+((-(\|a+1))\mathbin{\&{mod}}\\{cur\_gran})-\\{cur% +\_gran}+1-\|o$;\2\6 +\&{if} $\|b-\|a<\|a+\\{cur\_gran}-\|b$ \1\&{then}\5 +$\\{good\_val}\K\|a$\6 +\4\&{else} $\\{good\_val}\K\|a+\\{cur\_gran}$;\2\6 +\&{end};\par +\fi + +\M432. When we're rounding a doublepath, we might need to compromise between +two opposing tendencies, if the pen thickness is not a multiple of the +granularity. The following ``compromise'' adjustment, suggested by +John Hobby, finds the best way out of the dilemma. (Only the value +modulo \\{cur\_gran} is relevant in our applications, so the result turns +out to be essentially symmetric in \|u and~\|v.) + +\Y\P$\4\X405:Declare subroutines needed by \\{make\_spec}\X\mathrel{+}\S$\6 +\4\&{function}\1\ \37$\\{compromise}(\|u,\39\|v:\\{scaled})$: \37\\{scaled};\2% +\6 +\&{begin} \37$\\{compromise}\K\\{half}(\\{good\_val}(\|u+\|u,\39-\|u-\|v))$;\6 +\&{end};\par +\fi + +\M433. Here, then, is the procedure that rounds $x$ coordinates as described; +it does the same for $y$ coordinates too, independently. + +\Y\P$\4\X405:Declare subroutines needed by \\{make\_spec}\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{xy\_round};\6 +\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{list manipulation registers}\6 +$\|b,\39\|a$: \37\\{scaled};\C{before and after values}\6 +\\{pen\_edge}: \37\\{scaled};\C{offset that governs rounding}\6 +\\{alpha}: \37\\{fraction};\C{coefficient of linear transformation}\2\6 +\&{begin} \37$\\{cur\_gran}\K\\{abs}(\\{internal}[\\{granularity}])$;\6 +\&{if} $\\{cur\_gran}=0$ \1\&{then}\5 +$\\{cur\_gran}\K\\{unity}$;\2\6 +$\|p\K\\{cur\_spec}$;\5 +$\\{cur\_rounding\_ptr}\K0$;\6 +\1\&{repeat} \37$\|q\K\\{link}(\|p)$;\5 +\X434:If node \|q is a transition point for \|x coordinates, compute and save +its before-and-after coordinates\X;\6 +$\|p\K\|q$;\6 +\4\&{until}\5 +$\|p=\\{cur\_spec}$;\2\6 +\&{if} $\\{cur\_rounding\_ptr}>0$ \1\&{then}\5 +\X436:Transform the \|x coordinates\X;\2\6 +$\|p\K\\{cur\_spec}$;\5 +$\\{cur\_rounding\_ptr}\K0$;\6 +\1\&{repeat} \37$\|q\K\\{link}(\|p)$;\5 +\X437:If node \|q is a transition point for \|y coordinates, compute and save +its before-and-after coordinates\X;\6 +$\|p\K\|q$;\6 +\4\&{until}\5 +$\|p=\\{cur\_spec}$;\2\6 +\&{if} $\\{cur\_rounding\_ptr}>0$ \1\&{then}\5 +\X439:Transform the \|y coordinates\X;\2\6 +\&{end};\par +\fi + +\M434. When \|x has been negated, the \\{octant} codes are even. We allow +for an error of up to .01 pixel (i.e., 655 \\{scaled} units) in the +derivative calculations at transition nodes. + +\Y\P$\4\X434:If node \|q is a transition point for \|x coordinates, compute and +save its before-and-after coordinates\X\S$\6 +\&{if} $\\{odd}(\\{right\_type}(\|p))\I\\{odd}(\\{right\_type}(\|q))$ \1% +\&{then}\6 +\&{begin} \37\&{if} $\\{odd}(\\{right\_type}(\|q))$ \1\&{then}\5 +$\|b\K\\{x\_coord}(\|q)$\ \&{else} $\|b\K-\\{x\_coord}(\|q)$;\2\6 +\&{if} $(\\{abs}(\\{x\_coord}(\|q)-\\{right\_x}(\|q))<655)\V\30(\\{abs}(\\{x% +\_coord}(\|q)+\\{left\_x}(\|q))<655)$ \1\&{then}\5 +\X435:Compute before-and-after \|x values based on the current pen\X\6 +\4\&{else} $\|a\K\|b$;\2\6 +\&{if} $\\{abs}(\|a)>\\{max\_allowed}$ \1\&{then}\6 +\&{if} $\|a>0$ \1\&{then}\5 +$\|a\K\\{max\_allowed}$\ \&{else} $\|a\K-\\{max\_allowed}$;\2\2\6 +$\\{before\_and\_after}(\|b,\39\|a,\39\|q)$;\6 +\&{end}\2\par +\U433.\fi + +\M435. When we study the data representation for pens, we'll learn that the +\|x~coordinate of the current pen's west edge is +$$\hbox{$\\{y\_coord}(\\{link}(\\{cur\_pen}+\\{seventh\_octant}))$},$$ +and that there are similar ways to address other important offsets. +An ``\\{east\_west\_edge}'' is computed as a compromise between east and +west, for use in doublepaths, in case the two edges have conflicting +tendencies. + +\Y\P\D \37$\\{north\_edge}(\#)\S\\{y\_coord}(\\{link}(\#+\\{fourth\_octant}))$% +\par +\P\D \37$\\{south\_edge}(\#)\S\\{y\_coord}(\\{link}(\#+\\{first\_octant}))$\par +\P\D \37$\\{east\_edge}(\#)\S\\{y\_coord}(\\{link}(\#+\\{second\_octant}))$\par +\P\D \37$\\{west\_edge}(\#)\S\\{y\_coord}(\\{link}(\#+\\{seventh\_octant}))$\par +\P\D \37$\\{north\_south\_edge}(\#)\S\\{mem}[\#+10].\\{int}$\C{compromise +between north and south}\par +\P\D \37$\\{east\_west\_edge}(\#)\S\\{mem}[\#+11].\\{int}$\C{compromise between +east and west}\par +\P\D \37$\\{NE\_SW\_edge}(\#)\S\\{mem}[\#+12].\\{int}$\C{compromise between +northeast and southwest}\par +\P\D \37$\\{NW\_SE\_edge}(\#)\S\\{mem}[\#+13].\\{int}$\C{compromise between +northwest and southeast}\par +\Y\P$\4\X435:Compute before-and-after \|x values based on the current pen\X\S$\6 +\&{begin} \37\&{if} $\\{cur\_pen}=\\{null\_pen}$ \1\&{then}\5 +$\\{pen\_edge}\K0$\6 +\4\&{else} \&{if} $\\{cur\_path\_type}=\\{double\_path\_code}$ \1\&{then}\5 +$\\{pen\_edge}\K\\{compromise}(\\{east\_edge}(\\{cur\_pen}),\39\\{west\_edge}(% +\\{cur\_pen}))$\6 +\4\&{else} \&{if} $\\{odd}(\\{right\_type}(\|q))$ \1\&{then}\5 +$\\{pen\_edge}\K\\{west\_edge}(\\{cur\_pen})$\6 +\4\&{else} $\\{pen\_edge}\K\\{east\_edge}(\\{cur\_pen})$;\2\2\2\6 +$\|a\K\\{good\_val}(\|b,\39\\{pen\_edge})$;\6 +\&{end}\par +\U434.\fi + +\M436. The monotone transformation computed here with fixed-point arithmetic +is +guaranteed to take consecutive \\{before} values $(b,b')$ into consecutive +\\{after} values $(a,a')$, even in the presence of rounding errors, +as long as $\vert b-b'\vert<2^{28}$. + +\Y\P$\4\X436:Transform the \|x coordinates\X\S$\6 +\&{begin} \37\\{make\_safe};\6 +\1\&{repeat} \37$\\{decr}(\\{cur\_rounding\_ptr})$;\6 +\&{if} $(\\{after}[\\{cur\_rounding\_ptr}]\I\\{before}[\\{cur\_rounding\_ptr}])% +\V\30(\\{after}[\\{cur\_rounding\_ptr}+1]\I\\{before}[\\{cur\_rounding% +\_ptr}+1])$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{node\_to\_round}[\\{cur\_rounding\_ptr}]$;\6 +\&{if} $\\{odd}(\\{right\_type}(\|p))$ \1\&{then}\6 +\&{begin} \37$\|b\K\\{before}[\\{cur\_rounding\_ptr}]$;\5 +$\|a\K\\{after}[\\{cur\_rounding\_ptr}]$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|b\K-\\{before}[\\{cur\_rounding\_ptr}]$;\5 +$\|a\K-\\{after}[\\{cur\_rounding\_ptr}]$;\6 +\&{end};\2\6 +\&{if} $\\{before}[\\{cur\_rounding\_ptr}]=\\{before}[\\{cur\_rounding% +\_ptr}+1]$ \1\&{then}\5 +$\\{alpha}\K\\{fraction\_one}$\6 +\4\&{else} $\\{alpha}\K\\{make\_fraction}(\\{after}[\\{cur\_rounding\_ptr}+1]-% +\\{after}[\\{cur\_rounding\_ptr}],\39\30\\{before}[\\{cur\_rounding\_ptr}+1]-% +\\{before}[\\{cur\_rounding\_ptr}])$;\2\6 +\1\&{repeat} \37$\\{x\_coord}(\|p)\K\\{take\_fraction}(\\{alpha},\39\\{x% +\_coord}(\|p)-\|b)+\|a$;\5 +$\\{right\_x}(\|p)\K\\{take\_fraction}(\\{alpha},\39\\{right\_x}(\|p)-\|b)+% +\|a$;\5 +$\|p\K\\{link}(\|p)$;\5 +$\\{left\_x}(\|p)\K\\{take\_fraction}(\\{alpha},\39\\{left\_x}(\|p)-\|b)+\|a$;\6 +\4\&{until}\5 +$\|p=\\{node\_to\_round}[\\{cur\_rounding\_ptr}+1]$;\2\6 +\&{end};\2\6 +\4\&{until}\5 +$\\{cur\_rounding\_ptr}=0$;\2\6 +\&{end}\par +\U433.\fi + +\M437. When \|y has been negated, the \\{octant} codes are $>\\{negate\_y}$. +Otherwise +these routines are essentially identical to the routines for \|x coordinates +that we have just seen. + +\Y\P$\4\X437:If node \|q is a transition point for \|y coordinates, compute and +save its before-and-after coordinates\X\S$\6 +\&{if} $(\\{right\_type}(\|p)>\\{negate\_y})\I(\\{right\_type}(\|q)>\\{negate% +\_y})$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{right\_type}(\|q)\L\\{negate\_y}$ \1\&{then}\5 +$\|b\K\\{y\_coord}(\|q)$\ \&{else} $\|b\K-\\{y\_coord}(\|q)$;\2\6 +\&{if} $(\\{abs}(\\{y\_coord}(\|q)-\\{right\_y}(\|q))<655)\V\30(\\{abs}(\\{y% +\_coord}(\|q)+\\{left\_y}(\|q))<655)$ \1\&{then}\5 +\X438:Compute before-and-after \|y values based on the current pen\X\6 +\4\&{else} $\|a\K\|b$;\2\6 +\&{if} $\\{abs}(\|a)>\\{max\_allowed}$ \1\&{then}\6 +\&{if} $\|a>0$ \1\&{then}\5 +$\|a\K\\{max\_allowed}$\ \&{else} $\|a\K-\\{max\_allowed}$;\2\2\6 +$\\{before\_and\_after}(\|b,\39\|a,\39\|q)$;\6 +\&{end}\2\par +\U433.\fi + +\M438. \P$\X438:Compute before-and-after \|y values based on the current pen\X% +\S$\6 +\&{begin} \37\&{if} $\\{cur\_pen}=\\{null\_pen}$ \1\&{then}\5 +$\\{pen\_edge}\K0$\6 +\4\&{else} \&{if} $\\{cur\_path\_type}=\\{double\_path\_code}$ \1\&{then}\5 +$\\{pen\_edge}\K\\{compromise}(\\{north\_edge}(\\{cur\_pen}),\39\\{south% +\_edge}(\\{cur\_pen}))$\6 +\4\&{else} \&{if} $\\{right\_type}(\|q)\L\\{negate\_y}$ \1\&{then}\5 +$\\{pen\_edge}\K\\{south\_edge}(\\{cur\_pen})$\6 +\4\&{else} $\\{pen\_edge}\K\\{north\_edge}(\\{cur\_pen})$;\2\2\2\6 +$\|a\K\\{good\_val}(\|b,\39\\{pen\_edge})$;\6 +\&{end}\par +\U437.\fi + +\M439. \P$\X439:Transform the \|y coordinates\X\S$\6 +\&{begin} \37\\{make\_safe};\6 +\1\&{repeat} \37$\\{decr}(\\{cur\_rounding\_ptr})$;\6 +\&{if} $(\\{after}[\\{cur\_rounding\_ptr}]\I\\{before}[\\{cur\_rounding\_ptr}])% +\V\30(\\{after}[\\{cur\_rounding\_ptr}+1]\I\\{before}[\\{cur\_rounding% +\_ptr}+1])$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{node\_to\_round}[\\{cur\_rounding\_ptr}]$;\6 +\&{if} $\\{right\_type}(\|p)\L\\{negate\_y}$ \1\&{then}\6 +\&{begin} \37$\|b\K\\{before}[\\{cur\_rounding\_ptr}]$;\5 +$\|a\K\\{after}[\\{cur\_rounding\_ptr}]$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|b\K-\\{before}[\\{cur\_rounding\_ptr}]$;\5 +$\|a\K-\\{after}[\\{cur\_rounding\_ptr}]$;\6 +\&{end};\2\6 +\&{if} $\\{before}[\\{cur\_rounding\_ptr}]=\\{before}[\\{cur\_rounding% +\_ptr}+1]$ \1\&{then}\5 +$\\{alpha}\K\\{fraction\_one}$\6 +\4\&{else} $\\{alpha}\K\\{make\_fraction}(\\{after}[\\{cur\_rounding\_ptr}+1]-% +\\{after}[\\{cur\_rounding\_ptr}],\39\30\\{before}[\\{cur\_rounding\_ptr}+1]-% +\\{before}[\\{cur\_rounding\_ptr}])$;\2\6 +\1\&{repeat} \37$\\{y\_coord}(\|p)\K\\{take\_fraction}(\\{alpha},\39\\{y% +\_coord}(\|p)-\|b)+\|a$;\5 +$\\{right\_y}(\|p)\K\\{take\_fraction}(\\{alpha},\39\\{right\_y}(\|p)-\|b)+% +\|a$;\5 +$\|p\K\\{link}(\|p)$;\5 +$\\{left\_y}(\|p)\K\\{take\_fraction}(\\{alpha},\39\\{left\_y}(\|p)-\|b)+\|a$;\6 +\4\&{until}\5 +$\|p=\\{node\_to\_round}[\\{cur\_rounding\_ptr}+1]$;\2\6 +\&{end};\2\6 +\4\&{until}\5 +$\\{cur\_rounding\_ptr}=0$;\2\6 +\&{end}\par +\U433.\fi + +\M440. Rounding at diagonal tangents takes place after the subdivision into +octants is complete, hence after the coordinates have been skewed. +The details are somewhat tricky, because we want to round to points +whose skewed coordinates are halfway between integer multiples of +the granularity. Furthermore, both coordinates change when they are +rounded; this means we need a generalization of the \\{make\_safe} routine, +ensuring safety in both \|x and \|y. + +In spite of these extra complications, we can take comfort in the fact +that the basic structure of the routine is the same as before. + +\Y\P$\4\X405:Declare subroutines needed by \\{make\_spec}\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{diag\_round};\6 +\4\&{var} \37$\|p,\39\|q,\39\\{pp}$: \37\\{pointer};\C{list manipulation +registers}\6 +$\|b,\39\|a,\39\\{bb},\39\\{aa},\39\|d,\39\|c,\39\\{dd},\39\\{cc}$: \37% +\\{scaled};\C{before and after values}\6 +\\{pen\_edge}: \37\\{scaled};\C{offset that governs rounding}\6 +$\\{alpha},\39\\{beta}$: \37\\{fraction};\C{coefficients of linear +transformation}\6 +\\{next\_a}: \37\\{scaled};\C{$\\{after}[\|k]$ before it might have changed}\6 +\\{all\_safe}: \37\\{boolean};\C{does everything look OK so far?}\6 +\|k: \37$0\to\\{max\_wiggle}$;\C{runs through before-and-after values}\6 +$\\{first\_x},\39\\{first\_y}$: \37\\{scaled};\C{coordinates before rounding}\2% +\6 +\&{begin} \37$\|p\K\\{cur\_spec}$;\5 +$\\{cur\_rounding\_ptr}\K0$;\6 +\1\&{repeat} \37$\|q\K\\{link}(\|p)$;\5 +\X441:If node \|q is a transition point between octants, compute and save its +before-and-after coordinates\X;\6 +$\|p\K\|q$;\6 +\4\&{until}\5 +$\|p=\\{cur\_spec}$;\2\6 +\&{if} $\\{cur\_rounding\_ptr}>0$ \1\&{then}\5 +\X444:Transform the skewed coordinates\X;\2\6 +\&{end};\par +\fi + +\M441. We negate the skewed \|x coordinates in the before-and-after table when +the octant code is greater than \\{switch\_x\_and\_y}. + +\Y\P$\4\X441:If node \|q is a transition point between octants, compute and +save its before-and-after coordinates\X\S$\6 +\&{if} $\\{right\_type}(\|p)\I\\{right\_type}(\|q)$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{right\_type}(\|q)>\\{switch\_x\_and\_y}$ \1\&{then}\5 +$\|b\K-\\{x\_coord}(\|q)$\6 +\4\&{else} $\|b\K\\{x\_coord}(\|q)$;\2\6 +\&{if} $\\{abs}(\\{right\_type}(\|q)-\\{right\_type}(\|p))=\\{switch\_x\_and% +\_y}$ \1\&{then}\6 +\&{if} $(\\{abs}(\\{x\_coord}(\|q)-\\{right\_x}(\|q))<655)\V(\\{abs}(\\{x% +\_coord}(\|q)+\\{left\_x}(\|q))<655)$ \1\&{then}\5 +\X442:Compute a good coordinate at a diagonal transition\X\6 +\4\&{else} $\|a\K\|b$\2\6 +\4\&{else} $\|a\K\|b$;\2\6 +$\\{before\_and\_after}(\|b,\39\|a,\39\|q)$;\6 +\&{end}\2\par +\U440.\fi + +\M442. In octants whose code number is even, $x$~has been +negated; we want to round ambiguous cases downward instead of upward, +so that the rounding will be consistent with octants whose code +number is odd. This downward bias can be achieved by +subtracting~1 from the first argument of \\{good\_val}. + +\Y\P\D \37$\\{diag\_offset}(\#)\S\\{x\_coord}(\\{knil}(\\{link}(\\{cur\_pen}+% +\#)))$\par +\Y\P$\4\X442:Compute a good coordinate at a diagonal transition\X\S$\6 +\&{begin} \37\&{if} $\\{cur\_pen}=\\{null\_pen}$ \1\&{then}\5 +$\\{pen\_edge}\K0$\6 +\4\&{else} \&{if} $\\{cur\_path\_type}=\\{double\_path\_code}$ \1\&{then}\5 +\X443:Compute a compromise \\{pen\_edge}\X\6 +\4\&{else} \&{if} $\\{right\_type}(\|q)\L\\{switch\_x\_and\_y}$ \1\&{then}\5 +$\\{pen\_edge}\K\\{diag\_offset}(\\{right\_type}(\|q))$\6 +\4\&{else} $\\{pen\_edge}\K-\\{diag\_offset}(\\{right\_type}(\|q))$;\2\2\2\6 +\&{if} $\\{odd}(\\{right\_type}(\|q))$ \1\&{then}\5 +$\|a\K\\{good\_val}(\|b,\39\\{pen\_edge}+\\{half}(\\{cur\_gran}))$\6 +\4\&{else} $\|a\K\\{good\_val}(\|b-1,\39\\{pen\_edge}+\\{half}(\\{cur% +\_gran}))$;\2\6 +\&{end}\par +\U441.\fi + +\M443. (It seems a shame to compute these compromise offsets repeatedly. The +author would have stored them directly in the pen data structure, if the +granularity had been constant.) + +\Y\P$\4\X443:Compute a compromise \\{pen\_edge}\X\S$\6 +\&{case} $\\{right\_type}(\|q)$ \1\&{of}\6 +\4$\\{first\_octant},\39\\{second\_octant}$: \37$\\{pen\_edge}\K\\{compromise}(% +\\{diag\_offset}(\\{first\_octant}),\39\30-\\{diag\_offset}(\\{fifth% +\_octant}))$;\6 +\4$\\{fifth\_octant},\39\\{sixth\_octant}$: \37$\\{pen\_edge}\K-\\{compromise}(% +\\{diag\_offset}(\\{first\_octant}),\39\30-\\{diag\_offset}(\\{fifth% +\_octant}))$;\6 +\4$\\{third\_octant},\39\\{fourth\_octant}$: \37$\\{pen\_edge}\K\\{compromise}(% +\\{diag\_offset}(\\{fourth\_octant}),\39\30-\\{diag\_offset}(\\{eighth% +\_octant}))$;\6 +\4$\\{seventh\_octant},\39\\{eighth\_octant}$: \37$\\{pen\_edge}\K-% +\\{compromise}(\\{diag\_offset}(\\{fourth\_octant}),\39\30-\\{diag\_offset}(% +\\{eighth\_octant}))$;\2\6 +\&{end}\C{there are no other cases}\par +\U442.\fi + +\M444. \P$\X444:Transform the skewed coordinates\X\S$\6 +\&{begin} \37$\|p\K\\{node\_to\_round}[0]$;\5 +$\\{first\_x}\K\\{x\_coord}(\|p)$;\5 +$\\{first\_y}\K\\{y\_coord}(\|p)$;\5 +\X446:Make sure that all the diagonal roundings are safe\X;\6 +\&{for} $\|k\K0\mathrel{\&{to}}\\{cur\_rounding\_ptr}-1$ \1\&{do}\6 +\&{begin} \37$\|a\K\\{after}[\|k]$;\5 +$\|b\K\\{before}[\|k]$;\5 +$\\{aa}\K\\{after}[\|k+1]$;\5 +$\\{bb}\K\\{before}[\|k+1]$;\6 +\&{if} $(\|a\I\|b)\V(\\{aa}\I\\{bb})$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{node\_to\_round}[\|k]$;\5 +$\\{pp}\K\\{node\_to\_round}[\|k+1]$;\5 +\X445:Determine the before-and-after values of both coordinates\X;\6 +\&{if} $\|b=\\{bb}$ \1\&{then}\5 +$\\{alpha}\K\\{fraction\_one}$\6 +\4\&{else} $\\{alpha}\K\\{make\_fraction}(\\{aa}-\|a,\39\\{bb}-\|b)$;\2\6 +\&{if} $\|d=\\{dd}$ \1\&{then}\5 +$\\{beta}\K\\{fraction\_one}$\6 +\4\&{else} $\\{beta}\K\\{make\_fraction}(\\{cc}-\|c,\39\\{dd}-\|d)$;\2\6 +\1\&{repeat} \37$\\{x\_coord}(\|p)\K\\{take\_fraction}(\\{alpha},\39\\{x% +\_coord}(\|p)-\|b)+\|a$;\5 +$\\{y\_coord}(\|p)\K\\{take\_fraction}(\\{beta},\39\\{y\_coord}(\|p)-\|d)+\|c$;% +\5 +$\\{right\_x}(\|p)\K\\{take\_fraction}(\\{alpha},\39\\{right\_x}(\|p)-\|b)+% +\|a$;\5 +$\\{right\_y}(\|p)\K\\{take\_fraction}(\\{beta},\39\\{right\_y}(\|p)-\|d)+\|c$;% +\5 +$\|p\K\\{link}(\|p)$;\5 +$\\{left\_x}(\|p)\K\\{take\_fraction}(\\{alpha},\39\\{left\_x}(\|p)-\|b)+\|a$;\5 +$\\{left\_y}(\|p)\K\\{take\_fraction}(\\{beta},\39\\{left\_y}(\|p)-\|d)+\|c$;\6 +\4\&{until}\5 +$\|p=\\{pp}$;\2\6 +\&{end};\2\6 +\&{end};\2\6 +\&{end}\par +\U440.\fi + +\M445. In node \|p, the coordinates $(\|b,\|d)$ will be rounded to $(\|a,\|c)$; +in node \\{pp}, the coordinates $(\\{bb},\\{dd})$ will be rounded to $(\\{aa},% +\\{cc})$. +(We transform the values from node \\{pp} so that they agree with the +conventions of node \|p.) + +If $\\{aa}\I\\{bb}$, we know that $\\{abs}(\\{right\_type}(\|p)-\\{right% +\_type}(\\{pp}))=\\{switch\_x\_and\_y}$. + +\Y\P$\4\X445:Determine the before-and-after values of both coordinates\X\S$\6 +\&{if} $\\{aa}=\\{bb}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{pp}=\\{node\_to\_round}[0]$ \1\&{then}\5 +$\\{unskew}(\\{first\_x},\39\\{first\_y},\39\\{right\_type}(\\{pp}))$\6 +\4\&{else} $\\{unskew}(\\{x\_coord}(\\{pp}),\39\\{y\_coord}(\\{pp}),\39\\{right% +\_type}(\\{pp}))$;\2\6 +$\\{skew}(\\{cur\_x},\39\\{cur\_y},\39\\{right\_type}(\|p))$;\5 +$\\{bb}\K\\{cur\_x}$;\5 +$\\{aa}\K\\{bb}$;\5 +$\\{dd}\K\\{cur\_y}$;\5 +$\\{cc}\K\\{dd}$;\6 +\&{if} $\\{right\_type}(\|p)>\\{switch\_x\_and\_y}$ \1\&{then}\6 +\&{begin} \37$\|b\K-\|b$;\5 +$\|a\K-\|a$;\6 +\&{end};\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37\&{if} $\\{right\_type}(\|p)>\\{switch\_x\_and\_y}$ \1% +\&{then}\6 +\&{begin} \37$\\{bb}\K-\\{bb}$;\5 +$\\{aa}\K-\\{aa}$;\5 +$\|b\K-\|b$;\5 +$\|a\K-\|a$;\6 +\&{end};\2\6 +\&{if} $\\{pp}=\\{node\_to\_round}[0]$ \1\&{then}\5 +$\\{dd}\K\\{first\_y}-\\{bb}$\ \&{else} $\\{dd}\K\\{y\_coord}(\\{pp})-\\{bb}$;% +\2\6 +\&{if} $\\{odd}(\\{aa}-\\{bb})$ \1\&{then}\6 +\&{if} $\\{right\_type}(\|p)>\\{switch\_x\_and\_y}$ \1\&{then}\5 +$\\{cc}\K\\{dd}-\\{half}(\\{aa}-\\{bb}+1)$\6 +\4\&{else} $\\{cc}\K\\{dd}-\\{half}(\\{aa}-\\{bb}-1)$\2\6 +\4\&{else} $\\{cc}\K\\{dd}-\\{half}(\\{aa}-\\{bb})$;\2\6 +\&{end};\2\6 +$\|d\K\\{y\_coord}(\|p)$;\6 +\&{if} $\\{odd}(\|a-\|b)$ \1\&{then}\6 +\&{if} $\\{right\_type}(\|p)>\\{switch\_x\_and\_y}$ \1\&{then}\5 +$\|c\K\|d-\\{half}(\|a-\|b-1)$\6 +\4\&{else} $\|c\K\|d-\\{half}(\|a-\|b+1)$\2\6 +\4\&{else} $\|c\K\|d-\\{half}(\|a-\|b)$\2\par +\Us444\ET446.\fi + +\M446. \P$\X446:Make sure that all the diagonal roundings are safe\X\S$\6 +$\\{before}[\\{cur\_rounding\_ptr}]\K\\{before}[0]$;\C{cf.~\\{make\_safe}}\6 +$\\{node\_to\_round}[\\{cur\_rounding\_ptr}]\K\\{node\_to\_round}[0]$;\6 +\1\&{repeat} \37$\\{after}[\\{cur\_rounding\_ptr}]\K\\{after}[0]$;\5 +$\\{all\_safe}\K\\{true}$;\5 +$\\{next\_a}\K\\{after}[0]$;\6 +\&{for} $\|k\K0\mathrel{\&{to}}\\{cur\_rounding\_ptr}-1$ \1\&{do}\6 +\&{begin} \37$\|a\K\\{next\_a}$;\5 +$\|b\K\\{before}[\|k]$;\5 +$\\{next\_a}\K\\{after}[\|k+1]$;\5 +$\\{aa}\K\\{next\_a}$;\5 +$\\{bb}\K\\{before}[\|k+1]$;\6 +\&{if} $(\|a\I\|b)\V(\\{aa}\I\\{bb})$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{node\_to\_round}[\|k]$;\5 +$\\{pp}\K\\{node\_to\_round}[\|k+1]$;\5 +\X445:Determine the before-and-after values of both coordinates\X;\6 +\&{if} $(\\{aa}<\|a)\V(\\{cc}<\|c)\V(\\{aa}-\|a>2\ast(\\{bb}-\|b))\V(\\{cc}-% +\|c>2\ast(\\{dd}-\|d))$ \1\&{then}\6 +\&{begin} \37$\\{all\_safe}\K\\{false}$;\5 +$\\{after}[\|k]\K\\{before}[\|k]$;\6 +\&{if} $\|k=\\{cur\_rounding\_ptr}-1$ \1\&{then}\5 +$\\{after}[0]\K\\{before}[0]$\6 +\4\&{else} $\\{after}[\|k+1]\K\\{before}[\|k+1]$;\2\6 +\&{end};\2\6 +\&{end};\2\6 +\&{end};\2\6 +\4\&{until}\5 +\\{all\_safe}\2\par +\U444.\fi + +\M447. Here we get rid of ``dead'' cubics, i.e., polynomials that don't move at +all when \|t~changes, since the subdivision process might have introduced +such things. If the cycle reduces to a single point, however, we are left +with a single dead cubic that will not be removed until later. + +\Y\P$\4\X447:Remove dead cubics\X\S$\6 +$\|p\K\\{cur\_spec}$;\6 +\1\&{repeat} \37\\{continue}: \37$\|q\K\\{link}(\|p)$;\6 +\&{if} $\|p\I\|q$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{x\_coord}(\|p)=\\{right\_x}(\|p)$ \1\&{then}\6 +\&{if} $\\{y\_coord}(\|p)=\\{right\_y}(\|p)$ \1\&{then}\6 +\&{if} $\\{x\_coord}(\|p)=\\{left\_x}(\|q)$ \1\&{then}\6 +\&{if} $\\{y\_coord}(\|p)=\\{left\_y}(\|q)$ \1\&{then}\6 +\&{begin} \37$\\{unskew}(\\{x\_coord}(\|q),\39\\{y\_coord}(\|q),\39\\{right% +\_type}(\|q))$;\5 +$\\{skew}(\\{cur\_x},\39\\{cur\_y},\39\\{right\_type}(\|p))$;\6 +\&{if} $\\{x\_coord}(\|p)=\\{cur\_x}$ \1\&{then}\6 +\&{if} $\\{y\_coord}(\|p)=\\{cur\_y}$ \1\&{then}\6 +\&{begin} \37$\\{remove\_cubic}(\|p)$;\C{remove the cubic following \|p}\6 +\&{if} $\|q\I\\{cur\_spec}$ \1\&{then}\5 +\&{goto} \37\\{continue};\2\6 +$\\{cur\_spec}\K\|p$;\5 +$\|q\K\|p$;\6 +\&{end};\2\2\6 +\&{end};\2\2\2\2\6 +\&{end};\2\6 +$\|p\K\|q$;\6 +\4\&{until}\5 +$\|p=\\{cur\_spec}$;\2\par +\U402.\fi + +\M448. Finally we come to the last steps of \\{make\_spec}, when boundary nodes +are inserted between cubics that move in different octants. The main +complication remaining arises from consecutive cubics whose octants +are not adjacent; we should insert more than one octant boundary +at such sharp turns, so that the envelope-forming routine will work. + +For this purpose, conversion tables between numeric and Gray codes for +octants are desirable. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{octant\_number}: \37\&{array} $[\\{first\_octant}\to\\{sixth\_octant}]$ \1% +\&{of}\5 +$1\to8$;\2\6 +\4\\{octant\_code}: \37\&{array} $[1\to8]$ \1\&{of}\5 +$\\{first\_octant}\to\\{sixth\_octant}$;\2\par +\fi + +\M449. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{octant\_code}[1]\K\\{first\_octant}$;\5 +$\\{octant\_code}[2]\K\\{second\_octant}$;\5 +$\\{octant\_code}[3]\K\\{third\_octant}$;\5 +$\\{octant\_code}[4]\K\\{fourth\_octant}$;\5 +$\\{octant\_code}[5]\K\\{fifth\_octant}$;\5 +$\\{octant\_code}[6]\K\\{sixth\_octant}$;\5 +$\\{octant\_code}[7]\K\\{seventh\_octant}$;\5 +$\\{octant\_code}[8]\K\\{eighth\_octant}$;\6 +\&{for} $\|k\K1\mathrel{\&{to}}8$ \1\&{do}\5 +$\\{octant\_number}[\\{octant\_code}[\|k]]\K\|k$;\2\par +\fi + +\M450. The main loop for boundary insertion deals with three consecutive +nodes $\|p,\|q,\|r$. + +\Y\P$\4\X450:Insert octant boundaries and compute the turning number\X\S$\6 +$\\{turning\_number}\K0$;\5 +$\|p\K\\{cur\_spec}$;\5 +$\|q\K\\{link}(\|p)$;\6 +\1\&{repeat} \37$\|r\K\\{link}(\|q)$;\6 +\&{if} $(\\{right\_type}(\|p)\I\\{right\_type}(\|q))\V(\|q=\|r)$ \1\&{then}\5 +\X452:Insert one or more octant boundary nodes just before~\|q\X;\2\6 +$\|p\K\|q$;\5 +$\|q\K\|r$;\6 +\4\&{until}\5 +$\|p=\\{cur\_spec}$;\2\par +\U402.\fi + +\M451. The \\{new\_boundary} subroutine comes in handy at this point. It +inserts +a new boundary node just after a given node \|p, using a given octant code +to transform the new node's coordinates. The ``transition'' fields are +not computed here. + +\Y\P$\4\X405:Declare subroutines needed by \\{make\_spec}\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{new\_boundary}(\|p:\\{pointer};\,\35\\{octant}:% +\\{small\_number})$;\6 +\4\&{var} \37$\|q,\39\|r$: \37\\{pointer};\C{for list manipulation}\2\6 +\&{begin} \37$\|q\K\\{link}(\|p)$;\C{we assume that $\\{right\_type}(\|q)\I% +\\{endpoint}$}\6 +$\|r\K\\{get\_node}(\\{knot\_node\_size})$;\5 +$\\{link}(\|r)\K\|q$;\5 +$\\{link}(\|p)\K\|r$;\5 +$\\{left\_type}(\|r)\K\\{left\_type}(\|q)$;\C{but possibly $\\{left\_type}(% +\|q)=\\{endpoint}$}\6 +$\\{left\_x}(\|r)\K\\{left\_x}(\|q)$;\5 +$\\{left\_y}(\|r)\K\\{left\_y}(\|q)$;\5 +$\\{right\_type}(\|r)\K\\{endpoint}$;\5 +$\\{left\_type}(\|q)\K\\{endpoint}$;\5 +$\\{right\_octant}(\|r)\K\\{octant}$;\5 +$\\{left\_octant}(\|q)\K\\{right\_type}(\|q)$;\5 +$\\{unskew}(\\{x\_coord}(\|q),\39\\{y\_coord}(\|q),\39\\{right\_type}(\|q))$;\5 +$\\{skew}(\\{cur\_x},\39\\{cur\_y},\39\\{octant})$;\5 +$\\{x\_coord}(\|r)\K\\{cur\_x}$;\5 +$\\{y\_coord}(\|r)\K\\{cur\_y}$;\6 +\&{end};\par +\fi + +\M452. The case $\|q=\|r$ occurs if and only if $\|p=\|q=\|r=\\{cur\_spec}$, +when we want to turn +$360^\circ$ in eight steps and then remove a solitary dead cubic. +The program below happens to work in that case, but the reader isn't +expected to understand why. + +\Y\P$\4\X452:Insert one or more octant boundary nodes just before~\|q\X\S$\6 +\&{begin} \37$\\{new\_boundary}(\|p,\39\\{right\_type}(\|p))$;\5 +$\|s\K\\{link}(\|p)$;\5 +$\\{o1}\K\\{octant\_number}[\\{right\_type}(\|p)]$;\5 +$\\{o2}\K\\{octant\_number}[\\{right\_type}(\|q)]$;\6 +\&{case} $\\{o2}-\\{o1}$ \1\&{of}\6 +\4$1,\39-7,\397,\39-1$: \37\&{goto} \37\\{done};\6 +\4$2,\39-6$: \37$\\{clockwise}\K\\{false}$;\6 +\4$3,\39-5,\394,\39-4,\395,\39-3$: \37\X454:Decide whether or not to go +clockwise\X;\6 +\4$6,\39-2$: \37$\\{clockwise}\K\\{true}$;\6 +\40: \37$\\{clockwise}\K\\{rev\_turns}$;\2\6 +\&{end};\C{there are no other cases}\6 +\X458:Insert additional boundary nodes, then \&{goto} \\{done}\X;\6 +\4\\{done}: \37\&{if} $\|q=\|r$ \1\&{then}\6 +\&{begin} \37$\|q\K\\{link}(\|q)$;\5 +$\|r\K\|q$;\5 +$\|p\K\|s$;\5 +$\\{link}(\|s)\K\|q$;\5 +$\\{left\_octant}(\|q)\K\\{right\_octant}(\|q)$;\5 +$\\{left\_type}(\|q)\K\\{endpoint}$;\5 +$\\{free\_node}(\\{cur\_spec},\39\\{knot\_node\_size})$;\5 +$\\{cur\_spec}\K\|q$;\6 +\&{end};\2\6 +\X459:Fix up the transition fields and adjust the turning number\X;\6 +\&{end}\par +\U450.\fi + +\M453. \P$\X453:Other local variables for \\{make\_spec}\X\S$\6 +\4$\\{o1},\39\\{o2}$: \37\\{small\_number};\C{octant numbers}\6 +\4\\{clockwise}: \37\\{boolean};\C{should we turn clockwise?}\6 +\4$\\{dx1},\39\\{dy1},\39\\{dx2},\39\\{dy2}$: \37\\{integer};\C{directions of +travel at a cusp}\6 +\4$\\{dmax},\39\\{del}$: \37\\{integer};\C{temporary registers}\par +\U402.\fi + +\M454. A tricky question arises when a path jumps four octants. We want the +direction of turning to be counterclockwise if the curve has changed +direction by $180^\circ$, or by something so close to $180^\circ$ that +the difference is probably due to rounding errors; otherwise we want to +turn through an angle of less than $180^\circ$. This decision needs to +be made even when a curve seems to have jumped only three octants, since +a curve may approach direction $(-1,0)$ from the fourth octant, then +it might leave from direction $(+1,0)$ into the first. + +The following code solves the problem by analyzing the incoming +direction $(\\{dx1},\\{dy1})$ and the outgoing direction $(\\{dx2},\\{dy2})$. + +\Y\P$\4\X454:Decide whether or not to go clockwise\X\S$\6 +\&{begin} \37\X457:Compute the incoming and outgoing directions\X;\6 +$\\{unskew}(\\{dx1},\39\\{dy1},\39\\{right\_type}(\|p))$;\5 +$\\{del}\K\\{pyth\_add}(\\{cur\_x},\39\\{cur\_y})$;\6 +$\\{dx1}\K\\{make\_fraction}(\\{cur\_x},\39\\{del})$;\5 +$\\{dy1}\K\\{make\_fraction}(\\{cur\_y},\39\\{del})$;\C{$\cos\theta_1$ and $% +\sin\theta_1$}\6 +$\\{unskew}(\\{dx2},\39\\{dy2},\39\\{right\_type}(\|q))$;\5 +$\\{del}\K\\{pyth\_add}(\\{cur\_x},\39\\{cur\_y})$;\6 +$\\{dx2}\K\\{make\_fraction}(\\{cur\_x},\39\\{del})$;\5 +$\\{dy2}\K\\{make\_fraction}(\\{cur\_y},\39\\{del})$;\C{$\cos\theta_2$ and $% +\sin\theta_2$}\6 +$\\{del}\K\\{take\_fraction}(\\{dx1},\39\\{dy2})-\\{take\_fraction}(\\{dx2},\39% +\\{dy1})$;\C{$\sin(\theta_2-\theta_1)$}\6 +\&{if} $\\{del}>4684844$ \1\&{then}\5 +$\\{clockwise}\K\\{false}$\6 +\4\&{else} \&{if} $\\{del}<-4684844$ \1\&{then}\5 +$\\{clockwise}\K\\{true}$\C{$2^{28}\cdot\sin 1^\circ\approx4684844.68$}\6 +\4\&{else} $\\{clockwise}\K\\{rev\_turns}$;\2\2\6 +\&{end}\par +\U452.\fi + +\M455. Actually the turnarounds just computed will be clockwise, +not counterclockwise, if +the global variable \\{rev\_turns} is \\{true}; it is usually \\{false}. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{rev\_turns}: \37\\{boolean};\C{should we make U-turns in the English +manner?}\par +\fi + +\M456. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{rev\_turns}\K\\{false}$;\par +\fi + +\M457. \P$\X457:Compute the incoming and outgoing directions\X\S$\6 +$\\{dx1}\K\\{x\_coord}(\|s)-\\{left\_x}(\|s)$;\5 +$\\{dy1}\K\\{y\_coord}(\|s)-\\{left\_y}(\|s)$;\6 +\&{if} $\\{dx1}=0$ \1\&{then}\6 +\&{if} $\\{dy1}=0$ \1\&{then}\6 +\&{begin} \37$\\{dx1}\K\\{x\_coord}(\|s)-\\{right\_x}(\|p)$;\5 +$\\{dy1}\K\\{y\_coord}(\|s)-\\{right\_y}(\|p)$;\6 +\&{if} $\\{dx1}=0$ \1\&{then}\6 +\&{if} $\\{dy1}=0$ \1\&{then}\6 +\&{begin} \37$\\{dx1}\K\\{x\_coord}(\|s)-\\{x\_coord}(\|p)$;\5 +$\\{dy1}\K\\{y\_coord}(\|s)-\\{y\_coord}(\|p)$;\6 +\&{end};\C{and they {\sl can't} both be zero}\2\2\6 +\&{end};\2\2\6 +$\\{dmax}\K\\{abs}(\\{dx1})$;\ \&{if} $\\{abs}(\\{dy1})>\\{dmax}$ \1\&{then}\5 +$\\{dmax}\K\\{abs}(\\{dy1})$;\2\6 +\&{while} $\\{dmax}<\\{fraction\_one}$ \1\&{do}\6 +\&{begin} \37$\\{double}(\\{dmax})$;\5 +$\\{double}(\\{dx1})$;\5 +$\\{double}(\\{dy1})$;\6 +\&{end};\2\6 +$\\{dx2}\K\\{right\_x}(\|q)-\\{x\_coord}(\|q)$;\5 +$\\{dy2}\K\\{right\_y}(\|q)-\\{y\_coord}(\|q)$;\6 +\&{if} $\\{dx2}=0$ \1\&{then}\6 +\&{if} $\\{dy2}=0$ \1\&{then}\6 +\&{begin} \37$\\{dx2}\K\\{left\_x}(\|r)-\\{x\_coord}(\|q)$;\5 +$\\{dy2}\K\\{left\_y}(\|r)-\\{y\_coord}(\|q)$;\6 +\&{if} $\\{dx2}=0$ \1\&{then}\6 +\&{if} $\\{dy2}=0$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{right\_type}(\|r)=\\{endpoint}$ \1\&{then}\6 +\&{begin} \37$\\{cur\_x}\K\\{x\_coord}(\|r)$;\5 +$\\{cur\_y}\K\\{y\_coord}(\|r)$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{unskew}(\\{x\_coord}(\|r),\39\\{y\_coord}(\|r),\39% +\\{right\_type}(\|r))$;\5 +$\\{skew}(\\{cur\_x},\39\\{cur\_y},\39\\{right\_type}(\|q))$;\6 +\&{end};\2\6 +$\\{dx2}\K\\{cur\_x}-\\{x\_coord}(\|q)$;\5 +$\\{dy2}\K\\{cur\_y}-\\{y\_coord}(\|q)$;\6 +\&{end};\C{and they {\sl can't} both be zero}\2\2\6 +\&{end};\2\2\6 +$\\{dmax}\K\\{abs}(\\{dx2})$;\ \&{if} $\\{abs}(\\{dy2})>\\{dmax}$ \1\&{then}\5 +$\\{dmax}\K\\{abs}(\\{dy2})$;\2\6 +\&{while} $\\{dmax}<\\{fraction\_one}$ \1\&{do}\6 +\&{begin} \37$\\{double}(\\{dmax})$;\5 +$\\{double}(\\{dx2})$;\5 +$\\{double}(\\{dy2})$;\6 +\&{end}\2\par +\U454.\fi + +\M458. \P$\X458:Insert additional boundary nodes, then \&{goto} \\{done}\X\S$\6 +\~ \1\&{loop}\ \&{begin} \37\&{if} $\\{clockwise}$ \1\&{then}\6 +\&{if} $\\{o1}=1$ \1\&{then}\5 +$\\{o1}\K8$\ \&{else} $\\{decr}(\\{o1})$\2\6 +\4\&{else} \&{if} $\\{o1}=8$ \1\&{then}\5 +$\\{o1}\K1$\ \&{else} $\\{incr}(\\{o1})$;\2\2\6 +\&{if} $\\{o1}=\\{o2}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\\{new\_boundary}(\|s,\39\\{octant\_code}[\\{o1}])$;\5 +$\|s\K\\{link}(\|s)$;\5 +$\\{left\_octant}(\|s)\K\\{right\_octant}(\|s)$;\6 +\&{end}\2\par +\U452.\fi + +\M459. Now it remains to insert the redundant +transition information into the \\{left\_transition} +and \\{right\_transition} fields between adjacent octants, in the octant +boundary nodes that have just been inserted between $\\{link}(\|p)$ and~\|q. +The turning number is easily computed from these transitions. + +\Y\P$\4\X459:Fix up the transition fields and adjust the turning number\X\S$\6 +$\|p\K\\{link}(\|p)$;\6 +\1\&{repeat} \37$\|s\K\\{link}(\|p)$;\5 +$\\{o1}\K\\{octant\_number}[\\{right\_octant}(\|p)]$;\5 +$\\{o2}\K\\{octant\_number}[\\{left\_octant}(\|s)]$;\6 +\&{if} $\\{abs}(\\{o1}-\\{o2})=1$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{o2}<\\{o1}$ \1\&{then}\5 +$\\{o2}\K\\{o1}$;\2\6 +\&{if} $\\{odd}(\\{o2})$ \1\&{then}\5 +$\\{right\_transition}(\|p)\K\\{axis}$\6 +\4\&{else} $\\{right\_transition}(\|p)\K\\{diagonal}$;\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37\&{if} $\\{o1}=8$ \1\&{then}\5 +$\\{incr}(\\{turning\_number})$\ \&{else} $\\{decr}(\\{turning\_number})$;\2\6 +$\\{right\_transition}(\|p)\K\\{axis}$;\6 +\&{end};\2\6 +$\\{left\_transition}(\|s)\K\\{right\_transition}(\|p)$;\5 +$\|p\K\|s$;\6 +\4\&{until}\5 +$\|p=\|q$\2\par +\U452.\fi + +\N460. \[22] Filling a contour. +Given the low-level machinery for making moves and for transforming a +cyclic path into a cycle spec, we're almost able to fill a digitized path. +All we need is a high-level routine that walks through the cycle spec and +controls the overall process. + +Our overall goal is to plot the integer points $\bigl(\round(x(t)), +\round(y(t))\bigr)$ and to connect them by rook moves, assuming that +$\round(x(t))$ and $\round(y(t))$ don't both jump simultaneously from +one integer to another as $t$~varies; these rook moves will be the edge +of the contour that will be filled. We have reduced this problem to the +case of curves that travel in first octant directions, i.e., curves +such that $0\L y'(t)\L x'(t)$, by transforming the original coordinates. + +\def\xtilde{{\tilde x}} \def\ytilde{{\tilde y}} +Another transformation makes the problem still simpler. We shall say that +we are working with {\sl biased coordinates\/} when $(x,y)$ has been +replaced by $(\xtilde,\ytilde)=(x-y,y+{1\over2})$. When a curve travels +in first octant directions, the corresponding curve with biased +coordinates travels in first {\sl quadrant\/} directions; the latter +condition is symmetric in $x$ and~$y$, so it has advantages for the +design of algorithms. The \\{make\_spec} routine gives us skewed coordinates +$(x-y,y)$, hence we obtain biased coordinates by simply adding $1\over2$ +to the second component. + +The most important fact about biased coordinates is that we can determine the +rounded unbiased path $\bigl(\round(x(t)),\round(y(t))\bigr)$ from the +truncated biased path $\bigl(\lfloor\xtilde(t)\rfloor,\lfloor\ytilde(t)\rfloor +\bigr)$ and information about the initial and final endpoints. If the +unrounded and unbiased +path begins at $(x_0,y_0)$ and ends at $(x_1,y_1)$, it's possible to +prove (by induction on the length of truncated biased path) that the +rounded unbiased path is obtained by the following construction: + +\yskip\textindent{1)} Start at $\bigl(\round(x_0),\round(y_0)\bigr)$. + +\yskip\textindent{2)} If $(x_0+{1\over2})\bmod1\G(y_0+{1\over2})\bmod1$, +move one step right. + +\yskip\textindent{3)} Whenever the path +$\bigl(\lfloor\xtilde(t)\rfloor,\lfloor\ytilde(t)\rfloor\bigr)$ +takes an upward step (i.e., when +$\lfloor\xtilde(t+\epsilon)\rfloor=\lfloor\xtilde(t)\rfloor$ and +$\lfloor\ytilde(t+\epsilon)\rfloor=\lfloor\ytilde(t)\rfloor+1$), +move one step up and then one step right. + +\yskip\textindent{4)} Whenever the path +$\bigl(\lfloor\xtilde(t)\rfloor,\lfloor\ytilde(t)\rfloor\bigr)$ +takes a rightward step (i.e., when +$\lfloor\xtilde(t+\epsilon)\rfloor=\lfloor\xtilde(t)\rfloor+1$ and +$\lfloor\ytilde(t+\epsilon)\rfloor=\lfloor\ytilde(t)\rfloor$), +move one step right. + +\yskip\textindent{5)} Finally, if +$(x_1+{1\over2})\bmod1\G(y_1+{1\over2})\bmod1$, move one step left (thereby +cancelling the previous move, which was one step right). You will now be +at the point $\bigl(\round(x_1),\round(y_1)\bigr)$. + +\fi + +\M461. In order to validate the assumption that $\round(x(t))$ and $% +\round(y(t))$ +don't both jump simultaneously, we shall consider that a coordinate pair +$(x,y)$ actually represents $(x+\epsilon,y+\epsilon\delta)$, where +$\epsilon$ and $\delta$ are extremely small positive numbers---so small +that their precise values never matter. This convention makes rounding +unambiguous, since there is always a unique integer point nearest to any +given scaled numbers~$(x,y)$. + +When coordinates are transformed so that \MF\ needs to work only in ``first +octant'' directions, the transformations involve negating~$x$, negating~$y$, +and/or interchanging $x$ with~$y$. Corresponding adjustments to the +rounding conventions must be made so that consistent values will be +obtained. For example, suppose that we're working with coordinates that +have been transformed so that a third-octant curve travels in first-octant +directions. The skewed coordinates $(x,y)$ in our data structure represent +unskewed coordinates $(-y,x+y)$, which are actually $(-y+\epsilon, +x+y+\epsilon\delta)$. We should therefore round as if our skewed coordinates +were $(x+\epsilon+\epsilon\delta,y-\epsilon)$ instead of $(x,y)$. The following +table shows how the skewed coordinates should be perturbed when rounding +decisions are made: +$$\vcenter{\halign{#\hfil&&\quad$#$\hfil&\hskip4em#\hfil\cr +\\{first\_octant}&(x+\epsilon-\epsilon\delta,y+\epsilon\delta)& +\\{fifth\_octant}&(x-\epsilon+\epsilon\delta,y-\epsilon\delta)\cr +\\{second\_octant}&(x-\epsilon+\epsilon\delta,y+\epsilon)& +\\{sixth\_octant}&(x+\epsilon-\epsilon\delta,y-\epsilon)\cr +\\{third\_octant}&(x+\epsilon+\epsilon\delta,y-\epsilon)& +\\{seventh\_octant}&(x-\epsilon-\epsilon\delta,y+\epsilon)\cr +\\{fourth\_octant}&(x-\epsilon-\epsilon\delta,y+\epsilon\delta)& +\\{eighth\_octant}&(x+\epsilon+\epsilon\delta,y-\epsilon\delta)\cr}}$$ + +Four small arrays are set up so that the rounding operations will be +fairly easy in any given octant. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4$\\{y\_corr},\39\\{xy\_corr},\39\\{z\_corr}$: \37\&{array} $[\\{first% +\_octant}\to\\{sixth\_octant}]$ \1\&{of}\5 +$0\to1$;\2\6 +\4\\{x\_corr}: \37\&{array} $[\\{first\_octant}\to\\{sixth\_octant}]$ \1\&{of}\5 +$-1\to1$;\2\par +\fi + +\M462. Here \\{xy\_corr} is 1 if and only if the $x$ component of a skewed +coordinate +is to be decreased by an infinitesimal amount; \\{y\_corr} is similar, but for +the $y$ components. The other tables are set up so that the condition +$$(x+y+\\{half\_unit})\bmod\\{unity}\G(y+\\{half\_unit})\bmod\\{unity}$$ +is properly perturbed to the condition +$$(x+y+\\{half\_unit}-\\{x\_corr}-\\{y\_corr})\bmod\\{unity}\G +(y+\\{half\_unit}-\\{y\_corr})\bmod\\{unity}+\\{z\_corr}.$$ + +\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{x\_corr}[\\{first\_octant}]\K0$;\5 +$\\{y\_corr}[\\{first\_octant}]\K0$;\5 +$\\{xy\_corr}[\\{first\_octant}]\K0$;\6 +$\\{x\_corr}[\\{second\_octant}]\K0$;\5 +$\\{y\_corr}[\\{second\_octant}]\K0$;\5 +$\\{xy\_corr}[\\{second\_octant}]\K1$;\6 +$\\{x\_corr}[\\{third\_octant}]\K-1$;\5 +$\\{y\_corr}[\\{third\_octant}]\K1$;\5 +$\\{xy\_corr}[\\{third\_octant}]\K0$;\6 +$\\{x\_corr}[\\{fourth\_octant}]\K1$;\5 +$\\{y\_corr}[\\{fourth\_octant}]\K0$;\5 +$\\{xy\_corr}[\\{fourth\_octant}]\K1$;\6 +$\\{x\_corr}[\\{fifth\_octant}]\K0$;\5 +$\\{y\_corr}[\\{fifth\_octant}]\K1$;\5 +$\\{xy\_corr}[\\{fifth\_octant}]\K1$;\6 +$\\{x\_corr}[\\{sixth\_octant}]\K0$;\5 +$\\{y\_corr}[\\{sixth\_octant}]\K1$;\5 +$\\{xy\_corr}[\\{sixth\_octant}]\K0$;\6 +$\\{x\_corr}[\\{seventh\_octant}]\K1$;\5 +$\\{y\_corr}[\\{seventh\_octant}]\K0$;\5 +$\\{xy\_corr}[\\{seventh\_octant}]\K1$;\6 +$\\{x\_corr}[\\{eighth\_octant}]\K-1$;\5 +$\\{y\_corr}[\\{eighth\_octant}]\K1$;\5 +$\\{xy\_corr}[\\{eighth\_octant}]\K0$;\6 +\&{for} $\|k\K1\mathrel{\&{to}}8$ \1\&{do}\5 +$\\{z\_corr}[\|k]\K\\{xy\_corr}[\|k]-\\{x\_corr}[\|k]$;\2\par +\fi + +\M463. Here's a procedure that handles the details of rounding at the +endpoints: Given skewed coordinates $(\|x,\|y)$, it sets $(\\{m1},\\{n1})$ +to the corresponding rounded lattice points, taking the current +\\{octant} into account. Global variable \\{d1} is also set to 1 if +$(x+y+{1\over2})\bmod1\G(y+{1\over2})\bmod1$. + +\Y\P\4\&{procedure}\1\ \37$\\{end\_round}(\|x,\39\|y:\\{scaled})$;\2\6 +\&{begin} \37$\|y\K\|y+\\{half\_unit}-\\{y\_corr}[\\{octant}]$;\5 +$\|x\K\|x+\|y-\\{x\_corr}[\\{octant}]$;\5 +$\\{m1}\K\\{floor\_unscaled}(\|x)$;\5 +$\\{n1}\K\\{floor\_unscaled}(\|y)$;\6 +\&{if} $\|x-\\{unity}\ast\\{m1}\G\|y-\\{unity}\ast\\{n1}+\\{z\_corr}[% +\\{octant}]$ \1\&{then}\5 +$\\{d1}\K1$\ \&{else} $\\{d1}\K0$;\2\6 +\&{end};\par +\fi + +\M464. The outputs $(\\{m1},\\{n1},\\{d1})$ of \\{end\_round} will sometimes be +moved +to $(\\{m0},\\{n0},\\{d0})$. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4$\\{m0},\39\\{n0},\39\\{m1},\39\\{n1}$: \37\\{integer};\C{lattice point +coordinates}\6 +\4$\\{d0},\39\\{d1}$: \37$0\to1$;\C{displacement corrections}\par +\fi + +\M465. We're ready now to fill the pixels enclosed by a given cycle spec~\|h; +the knot list that represents the cycle is destroyed in the process. +The edge structure that gets all the resulting data is \\{cur\_edges}, +and the edges are weighted by \\{cur\_wt}. + +\Y\P\4\&{procedure}\1\ \37$\\{fill\_spec}(\|h:\\{pointer})$;\6 +\4\&{var} \37$\|p,\39\|q,\39\|r,\39\|s$: \37\\{pointer};\C{for list traversal}% +\2\6 +\&{begin} \37\&{if} $\\{internal}[\\{tracing\_edges}]>0$ \1\&{then}\5 +\\{begin\_edge\_tracing};\2\6 +$\|p\K\|h$;\C{we assume that $\\{left\_type}(\|h)=\\{endpoint}$}\6 +\1\&{repeat} \37$\\{octant}\K\\{left\_octant}(\|p)$;\5 +\X466:Set variable \|q to the node at the end of the current octant\X;\6 +\&{if} $\|q\I\|p$ \1\&{then}\6 +\&{begin} \37\X467:Determine the starting and ending lattice points $(\\{m0},% +\\{n0})$ and $(\\{m1},\\{n1})$\X;\6 +\X468:Make the moves for the current octant\X;\6 +$\\{move\_to\_edges}(\\{m0},\39\\{n0},\39\\{m1},\39\\{n1})$;\6 +\&{end};\2\6 +$\|p\K\\{link}(\|q)$;\6 +\4\&{until}\5 +$\|p=\|h$;\2\6 +$\\{toss\_knot\_list}(\|h)$;\6 +\&{if} $\\{internal}[\\{tracing\_edges}]>0$ \1\&{then}\5 +\\{end\_edge\_tracing};\2\6 +\&{end};\par +\fi + +\M466. \P$\X466:Set variable \|q to the node at the end of the current octant\X% +\S$\6 +$\|q\K\|p$;\6 +\&{while} $\\{right\_type}(\|q)\I\\{endpoint}$ \1\&{do}\5 +$\|q\K\\{link}(\|q)$\2\par +\Us465, 506\ETs506.\fi + +\M467. \P$\X467:Determine the starting and ending lattice points $(\\{m0},% +\\{n0})$ and $(\\{m1},\\{n1})$\X\S$\6 +$\\{end\_round}(\\{x\_coord}(\|p),\39\\{y\_coord}(\|p))$;\5 +$\\{m0}\K\\{m1}$;\5 +$\\{n0}\K\\{n1}$;\5 +$\\{d0}\K\\{d1}$;\6 +$\\{end\_round}(\\{x\_coord}(\|q),\39\\{y\_coord}(\|q))$\par +\U465.\fi + +\M468. Finally we perform the five-step process that was explained at +the very beginning of this part of the program. + +\Y\P$\4\X468:Make the moves for the current octant\X\S$\6 +\&{if} $\\{n1}-\\{n0}\G\\{move\_size}$ \1\&{then}\5 +$\\{overflow}(\.{"move\ table\ size"},\39\\{move\_size})$;\2\6 +$\\{move}[0]\K\\{d0}$;\5 +$\\{move\_ptr}\K0$;\5 +$\|r\K\|p$;\6 +\1\&{repeat} \37$\|s\K\\{link}(\|r)$;\6 +$\\{make\_moves}(\\{x\_coord}(\|r),\39\\{right\_x}(\|r),\39\\{left\_x}(\|s),\39% +\\{x\_coord}(\|s),\39\30\\{y\_coord}(\|r)+\\{half\_unit},\39\\{right\_y}(\|r)+% +\\{half\_unit},\39\\{left\_y}(\|s)+\\{half\_unit},\39\\{y\_coord}(\|s)+\\{half% +\_unit},\39\30\\{xy\_corr}[\\{octant}],\39\\{y\_corr}[\\{octant}])$;\5 +$\|r\K\|s$;\6 +\4\&{until}\5 +$\|r=\|q$;\2\6 +$\\{move}[\\{move\_ptr}]\K\\{move}[\\{move\_ptr}]-\\{d1}$;\6 +\&{if} $\\{internal}[\\{smoothing}]>0$ \1\&{then}\5 +$\\{smooth\_moves}(0,\39\\{move\_ptr})$\2\par +\U465.\fi + +\N469. \[23] Polygonal pens. +The next few parts of the program deal with the additional complications +associated with ``envelopes,'' leading up to an algorithm that fills a +contour with respect to a pen whose boundary is a convex polygon. The +mathematics underlying this algorithm is based on simple aspects of the +theory of tracings developed by Leo Guibas, Lyle Ramshaw, and Jorge +Stolfi [``A kinetic framework for computational geometry,'' +{\sl Proc.\ IEEE Symp.\ Foundations of Computer Science\/ \bf24} (1983), +100--111]. + +If the vertices of the polygon are $w_0$, $w_1$, \dots, $w_{n-1}$, $w_n=w_0$, +in counterclockwise order, the convexity condition requires that ``left +turns'' are made at each vertex when a person proceeds from $w_0$ to +$w_1$ to $\cdots$ to~$w_n$. The envelope is obtained if we offset a given +curve $z(t)$ by $w_k$ when that curve is traveling in a direction +$z'(t)$ lying between the directions $w_k-w_{k-1}$ and $w\k-w_k$. +At times~$t$ when the curve direction $z'(t)$ increases past +$w\k-w_k$, we temporarily stop plotting the offset curve and we insert +a straight line from $z(t)+w_k$ to $z(t)+w\k$; notice that this straight +line is tangent to the offset curve. Similarly, when the curve direction +decreases past $w_k-w_{k-1}$, we stop plotting and insert a straight +line from $z(t)+w_k$ to $z(t)+w_{k-1}$; the latter line is actually a +``retrograde'' step, which won't be part of the final envelope under +\MF's assumptions. The result of this construction is a continuous path +that consists of alternating curves and straight line segments. The +segments are usually so short, in practice, that they blend with the +curves; after all, it's possible to represent any digitized path as +a sequence of digitized straight lines. + +The nicest feature of this approach to envelopes is that it blends +perfectly with the octant subdivision process we have already developed. +The envelope travels in the same direction as the curve itself, as we +plot it, and we need merely be careful what offset is being added. +Retrograde motion presents a problem, but we will see that there is +a decent way to handle it. + +\fi + +\M470. We shall represent pens by maintaining eight lists of offsets, +one for each octant direction. The offsets at the boundary points +where a curve turns into a new octant will appear in the lists for +both octants. This means that we can restrict consideration to +segments of the original polygon whose directions aim in the first +octant, as we have done in the simpler case when envelopes were not +required. + +An example should help to clarify this situation: Consider the +quadrilateral whose vertices are $w_0=(0,-1)$, $w_1=(3,-1)$, +$w_2=(6,1)$, and $w_3=(1,2)$. A curve that travels in the first octant +will be offset by $w_1$ or $w_2$, unless its slope drops to zero +en route to the eighth octant; in the latter case we should switch to $w_0$ as +we cross the octant boundary. Our list for the first octant will +contain the three offsets $w_0$, $w_1$,~$w_2$. By convention we will +duplicate a boundary offset if the angle between octants doesn't +explicitly appear; in this case there is no explicit line of slope~1 +at the end of the list, so the full list is +$$w_0\;w_1\;w_2\;w_2\;=\;(0,-1)\;(3,-1)\;(6,1)\;(6,1).$$ +With skewed coordinates $(u-v,v)$ instead of $(u,v)$ we obtain the list +$$w_0\;w_1\;w_2\;w_2\;\mapsto\;(1,-1)\;(4,-1)\;(5,1)\;(5,1),$$ +which is what actually appears in the data structure. In the second +octant there's only one offset; we list it three times (with coordinates +interchanged, so as to make the second octant look like the first), +and skew those coordinates, obtaining +$$\tabskip\centering +\halign to\hsize{$\hfil#\;\mapsto\;{}$\tabskip=0pt& +$#\hfil$&\quad in the #\hfil\tabskip\centering\cr +w_2\;w_2\;w_2&(-5,6)\;(-5,6)\;(-5,6)\cr +\noalign{\vskip\belowdisplayskip +\vbox{\noindent\strut as the list of transformed and skewed offsets to use +when curves that travel in the second octant. Similarly, we will have\strut} +\vskip\abovedisplayskip} +w_2\;w_2\;w_2&(7,-6)\;(7,-6)\;(7,-6)&third;\cr +w_2\;w_2\;w_3\;w_3&(-7,1)\;(-7,1)\;(-3,2)\;(-3,2)&fourth;\cr +w_3\;w_3\;w_3&(3,-2)\;(3,-2)\;(3,-2)&fifth;\cr +w_3\;w_3\;w_0\;w_0&(-3,1)\;(-3,1)\;(1,0)\;(1,0)&sixth;\cr +w_0\;w_0\;w_0&(1,0)\;(1,0)\;(1,0)&seventh;\cr +w_0\;w_0\;w_0&(-1,1)\;(-1,1)\;(-1,1)&eighth.\cr}$$ +Notice that $w_1$ is considered here to be internal to the first octant; +it's not part of the eighth. We could equally well have taken $w_0$ out +of the first octant list and put it into the eighth; then the first octant +list would have been +$$w_1\;w_1\;w_2\;w_2\;\mapsto\;(4,-1)\;(4,-1)\;(5,1)\;(5,1)$$ +and the eighth octant list would have been +$$w_0\;w_0\;w_1\;\mapsto\;(-1,1)\;(-1,1)\;(2,1).$$ + +Actually, there's one more complication: The order of offsets is reversed +in even-numbered octants, because the transformation of coordinates has +reversed counterclockwise and clockwise orientations in those octants. +The offsets in the fourth octant, for example, are really $w_3$, $w_3$, +$w_2$,~$w_2$, not $w_2$, $w_2$, $w_3$,~$w_3$. + +\fi + +\M471. In general, the list of offsets for an octant will have the form +$$w_0\;\;w_1\;\;\ldots\;\;w_n\;\;w_{n+1}$$ +(if we renumber the subscripts in each list), where $w_0$ and $w_{n+1}$ +are offsets common to the neighboring lists. We'll often have $w_0=w_1$ +and/or $w_n=w_{n+1}$, but the other $w$'s will be distinct. Curves +that travel between slope~0 and direction $w_2-w_1$ will use offset~$w_1$; +curves that travel between directions $w_k-w_{k-1}$ and $w\k-w_k$ will +use offset~$w_k$, for $1<k<n$; curves between direction $w_n-w_{n-1}$ +and slope~1 (actually slope~$\infty$ after skewing) will use offset~$w_n$. +In even-numbered octants, the directions are actually $w_k-w\k$ instead +of $w\k-w_k$, because the offsets have been listed in reverse order. + +Each offset $w_k$ is represented by skewed coordinates $(u_k-v_k,v_k)$, +where $(u_k,v_k)$ is the representation of $w_k$ after it has been rotated +into a first-octant disguise. + +\fi + +\M472. The top-level data structure of a pen polygon is a 10-word node +containing +a reference count followed by pointers to the eight pen lists, followed +by an indication of the pen's range of values. + +If \|p~points to such a node, and if the +offset list for, say, the fourth octant has entries $w_0$, $w_1$, \dots, +$w_n$,~$w_{n+1}$, then $\\{info}(\|p+\\{fourth\_octant})$ will equal~$n$, and +$\\{link}(\|p+\\{fourth\_octant})$ will point to the offset node +containing~$w_0$. +Memory location $\|p+\\{fourth\_octant}$ is said to be the {\sl header\/} of +the pen-offset list for the fourth octant. Since this is an even-numbered +octant, $w_0$ is the offset that goes with the fifth octant, and +$w_{n+1}$ goes with the third. + +The elements of the offset list themselves are doubly linked 3-word nodes, +containing coordinates in their \\{x\_coord} and \\{y\_coord} fields. +The two link fields are called \\{link} and \\{knil}; if \|w~points to +the node for~$w_k$, then $\\{link}(\|w)$ and $\\{knil}(\|w)$ point respectively +to the nodes for $w\k$ and~$w_{k-1}$. If \|h is the list header, +$\\{link}(\|h)$ points to the node for~$w_0$ and $\\{knil}(\\{link}(\|h))$ to +the +node for~$w_{n+1}$. + +The tenth word of a pen header node contains the maximum absolute value of +an $x$ or $y$ coordinate among all of the unskewed pen offsets. + +The \\{link} field of a pen header node should be \\{null} if and only if +the pen has no offsets. + +\Y\P\D \37$\\{pen\_node\_size}=10$\par +\P\D \37$\\{coord\_node\_size}=3$\par +\P\D \37$\\{max\_offset}(\#)\S\\{mem}[\#+9].\\{sc}$\par +\fi + +\M473. The \\{print\_pen} subroutine illustrates these conventions by +reconstructing the vertices of a polygon from \MF's complicated +internal offset representation. + +\Y\P$\4\X257:Declare subroutines for printing expressions\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{print\_pen}(\|p:\\{pointer};\,\35\|s:\\{str% +\_number};\,\35\\{nuline}:\\{boolean})$;\6 +\4\&{var} \37\\{nothing\_printed}: \37\\{boolean};\C{has there been any action +yet?}\6 +\|k: \37$1\to8$;\C{octant number}\6 +\|h: \37\\{pointer};\C{offset list head}\6 +$\|m,\39\|n$: \37\\{integer};\C{offset indices}\6 +$\|w,\39\\{ww}$: \37\\{pointer};\C{pointers that traverse the offset list}\2\6 +\&{begin} \37$\\{print\_diagnostic}(\.{"Pen\ polygon"},\39\|s,\39\\{nuline})$;\5 +$\\{nothing\_printed}\K\\{true}$;\5 +\\{print\_ln};\6 +\&{for} $\|k\K1\mathrel{\&{to}}8$ \1\&{do}\6 +\&{begin} \37$\\{octant}\K\\{octant\_code}[\|k]$;\5 +$\|h\K\|p+\\{octant}$;\5 +$\|n\K\\{info}(\|h)$;\5 +$\|w\K\\{link}(\|h)$;\6 +\&{if} $\R\\{odd}(\|k)$ \1\&{then}\5 +$\|w\K\\{knil}(\|w)$;\C{in even octants, start at $w_{n+1}$}\2\6 +\&{for} $\|m\K1\mathrel{\&{to}}\|n+1$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{odd}(\|k)$ \1\&{then}\5 +$\\{ww}\K\\{link}(\|w)$\ \&{else} $\\{ww}\K\\{knil}(\|w)$;\2\6 +\&{if} $(\\{x\_coord}(\\{ww})\I\\{x\_coord}(\|w))\V(\\{y\_coord}(\\{ww})\I\\{y% +\_coord}(\|w))$ \1\&{then}\5 +\X474:Print the unskewed and unrotated coordinates of node \\{ww}\X;\2\6 +$\|w\K\\{ww}$;\6 +\&{end};\2\6 +\&{end};\2\6 +\&{if} $\\{nothing\_printed}$ \1\&{then}\6 +\&{begin} \37$\|w\K\\{link}(\|p+\\{first\_octant})$;\5 +$\\{print\_two}(\\{x\_coord}(\|w)+\\{y\_coord}(\|w),\39\\{y\_coord}(\|w))$;\6 +\&{end};\2\6 +$\\{print\_nl}(\.{"\ ..\ cycle"})$;\5 +$\\{end\_diagnostic}(\\{true})$;\6 +\&{end};\par +\fi + +\M474. \P$\X474:Print the unskewed and unrotated coordinates of node \\{ww}\X% +\S$\6 +\&{begin} \37\&{if} $\\{nothing\_printed}$ \1\&{then}\5 +$\\{nothing\_printed}\K\\{false}$\6 +\4\&{else} $\\{print\_nl}(\.{"\ ..\ "})$;\2\6 +$\\{print\_two\_true}(\\{x\_coord}(\\{ww}),\39\\{y\_coord}(\\{ww}))$;\6 +\&{end}\par +\U473.\fi + +\M475. A null pen polygon, which has just one vertex $(0,0)$, is +predeclared for error recovery. It doesn't need a proper +reference count, because the \\{toss\_pen} procedure below +will never delete it from memory. + +\Y\P$\4\X176:Initialize table entries (done by \.{INIMF} only)\X\mathrel{+}\S$\6 +$\\{ref\_count}(\\{null\_pen})\K\\{null}$;\5 +$\\{link}(\\{null\_pen})\K\\{null}$;\6 +$\\{info}(\\{null\_pen}+1)\K1$;\5 +$\\{link}(\\{null\_pen}+1)\K\\{null\_coords}$;\6 +\&{for} $\|k\K\\{null\_pen}+2\mathrel{\&{to}}\\{null\_pen}+8$ \1\&{do}\5 +$\\{mem}[\|k]\K\\{mem}[\\{null\_pen}+1]$;\2\6 +$\\{max\_offset}(\\{null\_pen})\K0$;\6 +$\\{link}(\\{null\_coords})\K\\{null\_coords}$;\5 +$\\{knil}(\\{null\_coords})\K\\{null\_coords}$;\6 +$\\{x\_coord}(\\{null\_coords})\K0$;\5 +$\\{y\_coord}(\\{null\_coords})\K0$;\par +\fi + +\M476. Here's a trivial subroutine that inserts a copy of an offset +on the \\{link} side of its clone in the doubly linked list. + +\Y\P\4\&{procedure}\1\ \37$\\{dup\_offset}(\|w:\\{pointer})$;\6 +\4\&{var} \37\|r: \37\\{pointer};\C{the new node}\2\6 +\&{begin} \37$\|r\K\\{get\_node}(\\{coord\_node\_size})$;\5 +$\\{x\_coord}(\|r)\K\\{x\_coord}(\|w)$;\5 +$\\{y\_coord}(\|r)\K\\{y\_coord}(\|w)$;\5 +$\\{link}(\|r)\K\\{link}(\|w)$;\5 +$\\{knil}(\\{link}(\|w))\K\|r$;\5 +$\\{knil}(\|r)\K\|w$;\5 +$\\{link}(\|w)\K\|r$;\6 +\&{end};\par +\fi + +\M477. The following algorithm is somewhat more interesting: It converts a +knot list for a cyclic path into a pen polygon, ignoring everything +but the \\{x\_coord}, \\{y\_coord}, and \\{link} fields. If the given path +vertices do not define a convex polygon, an error message is issued +and the null pen is returned. + +\Y\P\4\&{function}\1\ \37$\\{make\_pen}(\|h:\\{pointer})$: \37\\{pointer};\6 +\4\&{label} \37$\\{done},\39\\{done1},\39\\{not\_found},\39\\{found}$;\6 +\4\&{var} \37$\|o,\39\\{oo},\39\|k$: \37\\{small\_number};\C{octant +numbers---old, new, and current}\6 +\|p: \37\\{pointer};\C{top-level node for the new pen}\6 +$\|q,\39\|r,\39\|s,\39\|w,\39\\{hh}$: \37\\{pointer};\C{for list manipulation}\6 +\|n: \37\\{integer};\C{offset counter}\6 +$\\{dx},\39\\{dy}$: \37\\{scaled};\C{polygon direction}\6 +\\{mc}: \37\\{scaled};\C{the largest coordinate}\2\6 +\&{begin} \37\X479:Stamp all nodes with an octant code, compute the maximum +offset, and set \\{hh} to the node that begins the first octant; \&{goto} % +\\{not\_found} if there's a problem\X;\6 +\&{if} $\\{mc}\G\\{fraction\_one}-\\{half\_unit}$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +$\|p\K\\{get\_node}(\\{pen\_node\_size})$;\5 +$\|q\K\\{hh}$;\5 +$\\{max\_offset}(\|p)\K\\{mc}$;\5 +$\\{ref\_count}(\|p)\K\\{null}$;\6 +\&{if} $\\{link}(\|q)\I\|q$ \1\&{then}\5 +$\\{link}(\|p)\K\\{null}+1$;\2\6 +\&{for} $\|k\K1\mathrel{\&{to}}8$ \1\&{do}\5 +\X481:Construct the offset list for the \|kth octant\X;\2\6 +\&{goto} \37\\{found};\6 +\4\\{not\_found}: \37$\|p\K\\{null\_pen}$;\5 +\X478:Complain about a bad pen path\X;\6 +\4\\{found}: \37\&{if} $\\{internal}[\\{tracing\_pens}]>0$ \1\&{then}\5 +$\\{print\_pen}(\|p,\39\.{"\ (newly\ created)"},\39\\{true})$;\2\6 +$\\{make\_pen}\K\|p$;\6 +\&{end};\par +\fi + +\M478. \P$\X478:Complain about a bad pen path\X\S$\6 +\&{if} $\\{mc}\G\\{fraction\_one}-\\{half\_unit}$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"Pen\ too\ large"})$;\5 +$\\{help2}(\.{"The\ cycle\ you\ specified\ has\ a\ coordinate\ of\ 4095.5\ or\ +more."})$\6 +$(\.{"So\ I\'ve\ replaced\ it\ by\ the\ trivial\ path\ \`(0,0)..cycle\'."})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Pen\ cycle\ must\ be\ convex"})$;\5 +$\\{help3}(\.{"The\ cycle\ you\ specified\ either\ has\ consecutive\ equal\ +points"})$\6 +$(\.{"or\ turns\ right\ or\ turns\ through\ more\ than\ 360\ degrees."})$\6 +$(\.{"So\ I\'ve\ replaced\ it\ by\ the\ trivial\ path\ \`(0,0)..cycle\'."})$;\6 +\&{end};\2\6 +\\{put\_get\_error}\par +\U477.\fi + +\M479. There should be exactly one node whose octant number is less than its +predecessor in the cycle; that is node~\\{hh}. + +The loop here will terminate in all cases, but the proof is somewhat tricky: +If there are at least two distinct $y$~coordinates in the cycle, we will have +$\|o>4$ and $\|o\L4$ at different points of the cycle. Otherwise there are +at least two distinct $x$~coordinates, and we will have $\|o>2$ somewhere, +$\|o\L2$ somewhere. + +\Y\P$\4\X479:Stamp all nodes with an octant code, compute the maximum offset, +and set \\{hh} to the node that begins the first octant; \&{goto} \\{not% +\_found} if there's a problem\X\S$\6 +$\|q\K\|h$;\5 +$\|r\K\\{link}(\|q)$;\5 +$\\{mc}\K\\{abs}(\\{x\_coord}(\|h))$;\6 +\&{if} $\|q=\|r$ \1\&{then}\6 +\&{begin} \37$\\{hh}\K\|h$;\5 +$\\{right\_type}(\|h)\K0$;\C{this trick is explained below}\6 +\&{if} $\\{mc}<\\{abs}(\\{y\_coord}(\|h))$ \1\&{then}\5 +$\\{mc}\K\\{abs}(\\{y\_coord}(\|h))$;\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|o\K0$;\5 +$\\{hh}\K\\{null}$;\6 +\~ \1\&{loop}\ \&{begin} \37$\|s\K\\{link}(\|r)$;\6 +\&{if} $\\{mc}<\\{abs}(\\{x\_coord}(\|r))$ \1\&{then}\5 +$\\{mc}\K\\{abs}(\\{x\_coord}(\|r))$;\2\6 +\&{if} $\\{mc}<\\{abs}(\\{y\_coord}(\|r))$ \1\&{then}\5 +$\\{mc}\K\\{abs}(\\{y\_coord}(\|r))$;\2\6 +$\\{dx}\K\\{x\_coord}(\|r)-\\{x\_coord}(\|q)$;\5 +$\\{dy}\K\\{y\_coord}(\|r)-\\{y\_coord}(\|q)$;\6 +\&{if} $\\{dx}=0$ \1\&{then}\6 +\&{if} $\\{dy}=0$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\C{double point}\2\2\6 +\&{if} $\\{ab\_vs\_cd}(\\{dx},\39\\{y\_coord}(\|s)-\\{y\_coord}(\|r),\39\\{dy},% +\39\\{x\_coord}(\|s)-\\{x\_coord}(\|r))<0$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\C{right turn}\2\6 +\X480:Determine the octant code for direction $(\\{dx},\\{dy})$\X;\6 +$\\{right\_type}(\|q)\K\\{octant}$;\5 +$\\{oo}\K\\{octant\_number}[\\{octant}]$;\6 +\&{if} $\|o>\\{oo}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{hh}\I\\{null}$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\C{$>360^\circ$}\2\6 +$\\{hh}\K\|q$;\6 +\&{end};\2\6 +$\|o\K\\{oo}$;\6 +\&{if} $(\|q=\|h)\W(\\{hh}\I\\{null})$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\|q\K\|r$;\5 +$\|r\K\|s$;\6 +\&{end};\2\6 +\4\\{done}: \37\&{end}\2\par +\U477.\fi + +\M480. We want the octant for $(-\\{dx},-\\{dy})$ to be +exactly opposite the octant for $(\\{dx},\\{dy})$. + +\Y\P$\4\X480:Determine the octant code for direction $(\\{dx},\\{dy})$\X\S$\6 +\&{if} $\\{dx}>0$ \1\&{then}\5 +$\\{octant}\K\\{first\_octant}$\6 +\4\&{else} \&{if} $\\{dx}=0$ \1\&{then}\6 +\&{if} $\\{dy}>0$ \1\&{then}\5 +$\\{octant}\K\\{first\_octant}$\ \&{else} $\\{octant}\K\\{first\_octant}+% +\\{negate\_x}$\2\6 +\4\&{else} \&{begin} \37$\\{negate}(\\{dx})$;\5 +$\\{octant}\K\\{first\_octant}+\\{negate\_x}$;\6 +\&{end};\2\2\6 +\&{if} $\\{dy}<0$ \1\&{then}\6 +\&{begin} \37$\\{negate}(\\{dy})$;\5 +$\\{octant}\K\\{octant}+\\{negate\_y}$;\6 +\&{end}\6 +\4\&{else} \&{if} $\\{dy}=0$ \1\&{then}\6 +\&{if} $\\{octant}>\\{first\_octant}$ \1\&{then}\5 +$\\{octant}\K\\{first\_octant}+\\{negate\_x}+\\{negate\_y}$;\2\2\2\6 +\&{if} $\\{dx}<\\{dy}$ \1\&{then}\5 +$\\{octant}\K\\{octant}+\\{switch\_x\_and\_y}$\2\par +\U479.\fi + +\M481. Now \|q points to the node that the present octant shares with the +previous +octant, and $\\{right\_type}(\|q)$ is the octant code during which \|q~should +advance. +We have set $\\{right\_type}(\|q)=0$ in the special case that \|q should never +advance +(because the pen is degenerate). + +The number of offsets \|n must be smaller than \\{max\_quarterword}, because +the \\{fill\_envelope} routine stores $\|n+1$ in the \\{right\_type} field +of a knot node. + +\Y\P$\4\X481:Construct the offset list for the \|kth octant\X\S$\6 +\&{begin} \37$\\{octant}\K\\{octant\_code}[\|k]$;\5 +$\|n\K0$;\5 +$\|h\K\|p+\\{octant}$;\6 +\~ \1\&{loop}\ \&{begin} \37$\|r\K\\{get\_node}(\\{coord\_node\_size})$;\5 +$\\{skew}(\\{x\_coord}(\|q),\39\\{y\_coord}(\|q),\39\\{octant})$;\5 +$\\{x\_coord}(\|r)\K\\{cur\_x}$;\5 +$\\{y\_coord}(\|r)\K\\{cur\_y}$;\6 +\&{if} $\|n=0$ \1\&{then}\5 +$\\{link}(\|h)\K\|r$\6 +\4\&{else} \X482:Link node \|r to the previous node\X;\2\6 +$\|w\K\|r$;\6 +\&{if} $\\{right\_type}(\|q)\I\\{octant}$ \1\&{then}\5 +\&{goto} \37\\{done1};\2\6 +$\|q\K\\{link}(\|q)$;\5 +$\\{incr}(\|n)$;\6 +\&{end};\2\6 +\4\\{done1}: \37\X483:Finish linking the offset nodes, and duplicate the +borderline offset nodes if necessary\X;\6 +\&{if} $\|n\G\\{max\_quarterword}$ \1\&{then}\5 +$\\{overflow}(\.{"pen\ polygon\ size"},\39\\{max\_quarterword})$;\2\6 +$\\{info}(\|h)\K\|n$;\6 +\&{end}\par +\U477.\fi + +\M482. Now \|w points to the node that was inserted most recently, and +\|k is the current octant number. + +\Y\P$\4\X482:Link node \|r to the previous node\X\S$\6 +\&{if} $\\{odd}(\|k)$ \1\&{then}\6 +\&{begin} \37$\\{link}(\|w)\K\|r$;\5 +$\\{knil}(\|r)\K\|w$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{knil}(\|w)\K\|r$;\5 +$\\{link}(\|r)\K\|w$;\6 +\&{end}\2\par +\U481.\fi + +\M483. We have inserted $\|n+1$ nodes; it remains to duplicate the nodes at the +ends, if slopes 0 and~$\infty$ aren't already represented. At the end of +this section the total number of offset nodes should be $\|n+2$ +(since we call them $w_0$, $w_1$, \dots,~$w_{n+1}$). + +\Y\P$\4\X483:Finish linking the offset nodes, and duplicate the borderline +offset nodes if necessary\X\S$\6 +$\|r\K\\{link}(\|h)$;\6 +\&{if} $\\{odd}(\|k)$ \1\&{then}\6 +\&{begin} \37$\\{link}(\|w)\K\|r$;\5 +$\\{knil}(\|r)\K\|w$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{knil}(\|w)\K\|r$;\5 +$\\{link}(\|r)\K\|w$;\5 +$\\{link}(\|h)\K\|w$;\5 +$\|r\K\|w$;\6 +\&{end};\2\6 +\&{if} $(\\{y\_coord}(\|r)\I\\{y\_coord}(\\{link}(\|r)))\V(\|n=0)$ \1\&{then}\6 +\&{begin} \37$\\{dup\_offset}(\|r)$;\5 +$\\{incr}(\|n)$;\6 +\&{end};\2\6 +$\|r\K\\{knil}(\|r)$;\6 +\&{if} $\\{x\_coord}(\|r)\I\\{x\_coord}(\\{knil}(\|r))$ \1\&{then}\5 +$\\{dup\_offset}(\|r)$\6 +\4\&{else} $\\{decr}(\|n)$\2\par +\U481.\fi + +\M484. Conversely, \\{make\_path} goes back from a pen to a cyclic path that +might have generated it. The structure of this subroutine is essentially +the same as \\{print\_pen}. + +\Y\P\hbox{\4}\X486:Declare the function called \\{trivial\_knot}\X\6 +\4\&{function}\1\ \37$\\{make\_path}(\\{pen\_head}:\\{pointer})$: \37% +\\{pointer};\6 +\4\&{var} \37\|p: \37\\{pointer};\C{the most recently copied knot}\6 +\|k: \37$1\to8$;\C{octant number}\6 +\|h: \37\\{pointer};\C{offset list head}\6 +$\|m,\39\|n$: \37\\{integer};\C{offset indices}\6 +$\|w,\39\\{ww}$: \37\\{pointer};\C{pointers that traverse the offset list}\2\6 +\&{begin} \37$\|p\K\\{temp\_head}$;\6 +\&{for} $\|k\K1\mathrel{\&{to}}8$ \1\&{do}\6 +\&{begin} \37$\\{octant}\K\\{octant\_code}[\|k]$;\5 +$\|h\K\\{pen\_head}+\\{octant}$;\5 +$\|n\K\\{info}(\|h)$;\5 +$\|w\K\\{link}(\|h)$;\6 +\&{if} $\R\\{odd}(\|k)$ \1\&{then}\5 +$\|w\K\\{knil}(\|w)$;\C{in even octants, start at $w_{n+1}$}\2\6 +\&{for} $\|m\K1\mathrel{\&{to}}\|n+1$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{odd}(\|k)$ \1\&{then}\5 +$\\{ww}\K\\{link}(\|w)$\ \&{else} $\\{ww}\K\\{knil}(\|w)$;\2\6 +\&{if} $(\\{x\_coord}(\\{ww})\I\\{x\_coord}(\|w))\V(\\{y\_coord}(\\{ww})\I\\{y% +\_coord}(\|w))$ \1\&{then}\5 +\X485:Copy the unskewed and unrotated coordinates of node \\{ww}\X;\2\6 +$\|w\K\\{ww}$;\6 +\&{end};\2\6 +\&{end};\2\6 +\&{if} $\|p=\\{temp\_head}$ \1\&{then}\6 +\&{begin} \37$\|w\K\\{link}(\\{pen\_head}+\\{first\_octant})$;\5 +$\|p\K\\{trivial\_knot}(\\{x\_coord}(\|w)+\\{y\_coord}(\|w),\39\\{y\_coord}(% +\|w))$;\5 +$\\{link}(\\{temp\_head})\K\|p$;\6 +\&{end};\2\6 +$\\{link}(\|p)\K\\{link}(\\{temp\_head})$;\5 +$\\{make\_path}\K\\{link}(\\{temp\_head})$;\6 +\&{end};\par +\fi + +\M485. \P$\X485:Copy the unskewed and unrotated coordinates of node \\{ww}\X\S$% +\6 +\&{begin} \37$\\{unskew}(\\{x\_coord}(\\{ww}),\39\\{y\_coord}(\\{ww}),\39% +\\{octant})$;\5 +$\\{link}(\|p)\K\\{trivial\_knot}(\\{cur\_x},\39\\{cur\_y})$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{end}\par +\U484.\fi + +\M486. \P$\X486:Declare the function called \\{trivial\_knot}\X\S$\6 +\4\&{function}\1\ \37$\\{trivial\_knot}(\|x,\39\|y:\\{scaled})$: \37% +\\{pointer};\6 +\4\&{var} \37\|p: \37\\{pointer};\C{a new knot for explicit coordinates \|x and +\|y}\2\6 +\&{begin} \37$\|p\K\\{get\_node}(\\{knot\_node\_size})$;\5 +$\\{left\_type}(\|p)\K\\{explicit}$;\5 +$\\{right\_type}(\|p)\K\\{explicit}$;\6 +$\\{x\_coord}(\|p)\K\|x$;\5 +$\\{left\_x}(\|p)\K\|x$;\5 +$\\{right\_x}(\|p)\K\|x$;\6 +$\\{y\_coord}(\|p)\K\|y$;\5 +$\\{left\_y}(\|p)\K\|y$;\5 +$\\{right\_y}(\|p)\K\|y$;\6 +$\\{trivial\_knot}\K\|p$;\6 +\&{end};\par +\U484.\fi + +\M487. That which can be created can be destroyed. + +\Y\P\D \37$\\{add\_pen\_ref}(\#)\S\\{incr}(\\{ref\_count}(\#))$\par +\P\D \37$\\{delete\_pen\_ref}(\#)\S$\1\6 +\&{if} $\\{ref\_count}(\#)=\\{null}$ \1\&{then}\5 +$\\{toss\_pen}(\#)$\6 +\4\&{else} $\\{decr}(\\{ref\_count}(\#))$\2\2\par +\Y\P$\4\X268:Declare the recycling subroutines\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{toss\_pen}(\|p:\\{pointer})$;\6 +\4\&{var} \37\|k: \37$1\to8$;\C{relative header locations}\6 +$\|w,\39\\{ww}$: \37\\{pointer};\C{pointers to offset nodes}\2\6 +\&{begin} \37\&{if} $\|p\I\\{null\_pen}$ \1\&{then}\6 +\&{begin} \37\&{for} $\|k\K1\mathrel{\&{to}}8$ \1\&{do}\6 +\&{begin} \37$\|w\K\\{link}(\|p+\|k)$;\6 +\1\&{repeat} \37$\\{ww}\K\\{link}(\|w)$;\5 +$\\{free\_node}(\|w,\39\\{coord\_node\_size})$;\5 +$\|w\K\\{ww}$;\6 +\4\&{until}\5 +$\|w=\\{link}(\|p+\|k)$;\2\6 +\&{end};\2\6 +$\\{free\_node}(\|p,\39\\{pen\_node\_size})$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M488. The \\{find\_offset} procedure sets $(\\{cur\_x},\\{cur\_y})$ to the +offset associated +with a given direction~$(\|x,\|y)$ and a given pen~\|p. If $\|x=\|y=0$, the +result is $(0,0)$. If two different offsets apply, one of them is +chosen arbitrarily. + +\Y\P\4\&{procedure}\1\ \37$\\{find\_offset}(\|x,\39\|y:\\{scaled};\,\35\|p:% +\\{pointer})$;\6 +\4\&{label} \37$\\{done},\39\\{exit}$;\6 +\4\&{var} \37\\{octant}: \37$\\{first\_octant}\to\\{sixth\_octant}$;\C{octant +code for $(\|x,\|y)$}\6 +\|s: \37$-1\to+1$;\C{sign of the octant}\6 +\|n: \37\\{integer};\C{number of offsets remaining}\6 +$\|h,\39\|w,\39\\{ww}$: \37\\{pointer};\C{list traversal registers}\2\6 +\&{begin} \37\X489:Compute the octant code; skew and rotate the coordinates $(% +\|x,\|y)$\X;\6 +\&{if} $\\{odd}(\\{octant\_number}[\\{octant}])$ \1\&{then}\5 +$\|s\K-1$\ \&{else} $\|s\K+1$;\2\6 +$\|h\K\|p+\\{octant}$;\5 +$\|w\K\\{link}(\\{link}(\|h))$;\5 +$\\{ww}\K\\{link}(\|w)$;\5 +$\|n\K\\{info}(\|h)$;\6 +\&{while} $\|n>1$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{ab\_vs\_cd}(\|x,\39\\{y\_coord}(\\{ww})-\\{y\_coord}(% +\|w),\39\30\|y,\39\\{x\_coord}(\\{ww})-\\{x\_coord}(\|w))\I\|s$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\|w\K\\{ww}$;\5 +$\\{ww}\K\\{link}(\|w)$;\5 +$\\{decr}(\|n)$;\6 +\&{end};\2\6 +\4\\{done}: \37$\\{unskew}(\\{x\_coord}(\|w),\39\\{y\_coord}(\|w),\39% +\\{octant})$;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M489. \P$\X489:Compute the octant code; skew and rotate the coordinates $(\|x,% +\|y)$\X\S$\6 +\&{if} $\|x>0$ \1\&{then}\5 +$\\{octant}\K\\{first\_octant}$\6 +\4\&{else} \&{if} $\|x=0$ \1\&{then}\6 +\&{if} $\|y\L0$ \1\&{then}\6 +\&{if} $\|y=0$ \1\&{then}\6 +\&{begin} \37$\\{cur\_x}\K0$;\5 +$\\{cur\_y}\K0$;\5 +\&{return};\6 +\&{end}\6 +\4\&{else} $\\{octant}\K\\{first\_octant}+\\{negate\_x}$\2\6 +\4\&{else} $\\{octant}\K\\{first\_octant}$\2\6 +\4\&{else} \&{begin} \37$\|x\K-\|x$;\6 +\&{if} $\|y=0$ \1\&{then}\5 +$\\{octant}\K\\{first\_octant}+\\{negate\_x}+\\{negate\_y}$\6 +\4\&{else} $\\{octant}\K\\{first\_octant}+\\{negate\_x}$;\2\6 +\&{end};\2\2\6 +\&{if} $\|y<0$ \1\&{then}\6 +\&{begin} \37$\\{octant}\K\\{octant}+\\{negate\_y}$;\5 +$\|y\K-\|y$;\6 +\&{end};\2\6 +\&{if} $\|x\G\|y$ \1\&{then}\5 +$\|x\K\|x-\|y$\6 +\4\&{else} \&{begin} \37$\\{octant}\K\\{octant}+\\{switch\_x\_and\_y}$;\5 +$\|x\K\|y-\|x$;\5 +$\|y\K\|y-\|x$;\6 +\&{end}\2\par +\U488.\fi + +\N490. \[24] Filling an envelope. +We are about to reach the culmination of \MF's digital plotting routines: +Almost all of the previous algorithms will be brought to bear on \MF's +most difficult task, which is to fill the envelope of a given cyclic path +with respect to a given pen polygon. + +But we still must complete some of the preparatory work before taking such +a big plunge. + +\fi + +\M491. Given a pointer \|c to a nonempty list of cubics, +and a pointer~\|h to the header information of a pen polygon segment, +the \\{offset\_prep} routine changes the list into cubics that are +associated with particular pen offsets. Namely, the cubic between \|p +and~\|q should be associated with the \|kth offset when $\\{right\_type}(\|p)=% +\|k$. + +List \|c is actually part of a cycle spec, so it terminates at the +first node whose \\{right\_type} is \\{endpoint}. The cubics all have +monotone-nondecreasing $x'(t)$ and $y'(t)$. + +\Y\P\hbox{\4}\X493:Declare subroutines needed by \\{offset\_prep}\X\6 +\4\&{procedure}\1\ \37$\\{offset\_prep}(\|c,\39\|h:\\{pointer})$;\6 +\4\&{label} \37$\\{done},\39\\{not\_found}$;\6 +\4\&{var} \37\|n: \37\\{halfword};\C{the number of pen offsets}\6 +$\|p,\39\|q,\39\|r,\39\\{lh},\39\\{ww}$: \37\\{pointer};\C{for list +manipulation}\6 +\|k: \37\\{halfword};\C{the current offset index}\6 +\|w: \37\\{pointer};\C{a pointer to offset $w_k$}\6 +\X495:Other local variables for \\{offset\_prep}\X\2\6 +\&{begin} \37$\|p\K\|c$;\5 +$\|n\K\\{info}(\|h)$;\5 +$\\{lh}\K\\{link}(\|h)$;\C{now \\{lh} points to $w_0$}\6 +\&{while} $\\{right\_type}(\|p)\I\\{endpoint}$ \1\&{do}\6 +\&{begin} \37$\|q\K\\{link}(\|p)$;\5 +\X494:Split the cubic between \|p and \|q, if necessary, into cubics associated +with single offsets, after which \|q should point to the end of the final such +cubic\X;\6 +\X492:Advance \|p to node \|q, removing any ``dead'' cubics that might have +been introduced by the splitting process\X;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M492. \P$\X492:Advance \|p to node \|q, removing any ``dead'' cubics that +might have been introduced by the splitting process\X\S$\6 +\1\&{repeat} \37$\|r\K\\{link}(\|p)$;\6 +\&{if} $\\{x\_coord}(\|p)=\\{right\_x}(\|p)$ \1\&{then}\6 +\&{if} $\\{y\_coord}(\|p)=\\{right\_y}(\|p)$ \1\&{then}\6 +\&{if} $\\{x\_coord}(\|p)=\\{left\_x}(\|r)$ \1\&{then}\6 +\&{if} $\\{y\_coord}(\|p)=\\{left\_y}(\|r)$ \1\&{then}\6 +\&{if} $\\{x\_coord}(\|p)=\\{x\_coord}(\|r)$ \1\&{then}\6 +\&{if} $\\{y\_coord}(\|p)=\\{y\_coord}(\|r)$ \1\&{then}\6 +\&{begin} \37$\\{remove\_cubic}(\|p)$;\6 +\&{if} $\|r=\|q$ \1\&{then}\5 +$\|q\K\|p$;\2\6 +$\|r\K\|p$;\6 +\&{end};\2\2\2\2\2\2\6 +$\|p\K\|r$;\6 +\4\&{until}\5 +$\|p=\|q$\2\par +\U491.\fi + +\M493. The splitting process uses a subroutine like \\{split\_cubic}, but +(for ``bulletproof'' operation) we check to make sure that the +resulting (skewed) coordinates satisfy $\Delta x\G0$ and $\Delta y\G0$ +after splitting; \\{make\_spec} has made sure that these relations hold +before splitting. (This precaution is surely unnecessary, now that +\\{make\_spec} is so much more careful than it used to be. But who +wants to take a chance? Maybe the hardware will fail or something.) + +\Y\P$\4\X493:Declare subroutines needed by \\{offset\_prep}\X\S$\6 +\4\&{procedure}\1\ \37$\\{split\_for\_offset}(\|p:\\{pointer};\,\35\|t:% +\\{fraction})$;\6 +\4\&{var} \37\|q: \37\\{pointer};\C{the successor of \|p}\6 +\|r: \37\\{pointer};\C{the new node}\2\6 +\&{begin} \37$\|q\K\\{link}(\|p)$;\5 +$\\{split\_cubic}(\|p,\39\|t,\39\\{x\_coord}(\|q),\39\\{y\_coord}(\|q))$;\5 +$\|r\K\\{link}(\|p)$;\6 +\&{if} $\\{y\_coord}(\|r)<\\{y\_coord}(\|p)$ \1\&{then}\5 +$\\{y\_coord}(\|r)\K\\{y\_coord}(\|p)$\6 +\4\&{else} \&{if} $\\{y\_coord}(\|r)>\\{y\_coord}(\|q)$ \1\&{then}\5 +$\\{y\_coord}(\|r)\K\\{y\_coord}(\|q)$;\2\2\6 +\&{if} $\\{x\_coord}(\|r)<\\{x\_coord}(\|p)$ \1\&{then}\5 +$\\{x\_coord}(\|r)\K\\{x\_coord}(\|p)$\6 +\4\&{else} \&{if} $\\{x\_coord}(\|r)>\\{x\_coord}(\|q)$ \1\&{then}\5 +$\\{x\_coord}(\|r)\K\\{x\_coord}(\|q)$;\2\2\6 +\&{end};\par +\A497. +\U491.\fi + +\M494. If the pen polygon has \|n offsets, and if $w_k=(u_k,v_k)$ is the $k$th +of these, the $k$th pen slope is defined by the formula +$$s_k={v\k-v_k\over u\k-u_k},\qquad\hbox{for $0<k<n$}.$$ +In odd-numbered octants, the numerator and denominator of this fraction +will be positive; in even-numbered octants they will both be negative. +Furthermore we always have $0=s_0<s_1<\cdots<s_n=\infty$. The goal of +\\{offset\_prep} is to find an offset index~\|k to associate with +each cubic, such that the slope $s(t)$ of the cubic satisfies +$$s_{k-1}\le s(t)\le s_k\qquad\hbox{for $0\le t\le 1$.}\eqno(*)$$ +We may have to split a cubic into as many as $2n-1$ pieces before each +piece corresponds to a unique offset. + +\Y\P$\4\X494:Split the cubic between \|p and \|q, if necessary, into cubics +associated with single offsets, after which \|q should point to the end of the +final such cubic\X\S$\6 +\&{if} $\|n\L1$ \1\&{then}\5 +$\\{right\_type}(\|p)\K1$\C{this case is easy}\6 +\4\&{else} \&{begin} \37\X496:Prepare for derivative computations; \&{goto} % +\\{not\_found} if the current cubic is dead\X;\6 +\X501:Find the initial slope, $\\{dy}/\\{dx}$\X;\6 +\&{if} $\\{dx}=0$ \1\&{then}\5 +\X505:Handle the special case of infinite slope\X\6 +\4\&{else} \&{begin} \37\X502:Find the index \|k such that $s_{k-1}\L\\{dy}/% +\\{dx}<s_k$\X;\6 +\X503:Complete the offset splitting process\X;\6 +\&{end};\2\6 +\4\\{not\_found}: \37\&{end}\2\par +\U491.\fi + +\M495. The slope of a cubic $B(z_0,z_1,z_2,z_3;t)=\bigl(x(t),y(t)\bigr)$ can be +calculated from the quadratic polynomials +${1\over3}x'(t)=B(x_1-x_0,x_2-x_1,x_3-x_2;t)$ and +${1\over3}y'(t)=B(y_1-y_0,y_2-y_1,y_3-y_2;t)$. +Since we may be calculating slopes from several cubics +split from the current one, it is desirable to do these calculations +without losing too much precision. ``Scaled up'' values of the +derivatives, which will be less tainted by accumulated errors than +derivatives found from the cubics themselves, are maintained in +local variables \\{x0}, \\{x1}, and \\{x2}, representing $X_0=2^l(x_1-x_0)$, +$X_1=2^l(x_2-x_1)$, and $X_2=2^l(x_3-x_2)$; similarly \\{y0}, \\{y1}, and~% +\\{y2} +represent $Y_0=2^l(y_1-y_0)$, $Y_1=2^l(y_2-y_1)$, and $Y_2=2^l(y_3-y_2)$. +To test whether the slope of the cubic is $\ge s$ or $\le s$, we will test +the sign of the quadratic ${1\over3}2^l\bigl(y'(t)-sx'(t)\bigr)$ if $s\le1$, +or ${1\over3}2^l\bigl(y'(t)/s-x'(t)\bigr)$ if $s>1$. + +\Y\P$\4\X495:Other local variables for \\{offset\_prep}\X\S$\6 +\4$\\{x0},\39\\{x1},\39\\{x2},\39\\{y0},\39\\{y1},\39\\{y2}$: \37\\{integer};% +\C{representatives of derivatives}\6 +\4$\\{t0},\39\\{t1},\39\\{t2}$: \37\\{integer};\C{coefficients of polynomial +for slope testing}\6 +\4$\\{du},\39\\{dv},\39\\{dx},\39\\{dy}$: \37\\{integer};\C{for slopes of the +pen and the curve}\6 +\4\\{max\_coef}: \37\\{integer};\C{used while scaling}\6 +\4$\\{x0a},\39\\{x1a},\39\\{x2a},\39\\{y0a},\39\\{y1a},\39\\{y2a}$: \37% +\\{integer};\C{intermediate values}\6 +\4\|t: \37\\{fraction};\C{where the derivative passes through zero}\6 +\4\|s: \37\\{fraction};\C{slope or reciprocal slope}\par +\U491.\fi + +\M496. \P$\X496:Prepare for derivative computations; \&{goto} \\{not\_found} if +the current cubic is dead\X\S$\6 +$\\{x0}\K\\{right\_x}(\|p)-\\{x\_coord}(\|p)$;\C{should be $\G0$}\6 +$\\{x2}\K\\{x\_coord}(\|q)-\\{left\_x}(\|q)$;\C{likewise}\6 +$\\{x1}\K\\{left\_x}(\|q)-\\{right\_x}(\|p)$;\C{but this might be negative}\6 +$\\{y0}\K\\{right\_y}(\|p)-\\{y\_coord}(\|p)$;\5 +$\\{y2}\K\\{y\_coord}(\|q)-\\{left\_y}(\|q)$;\5 +$\\{y1}\K\\{left\_y}(\|q)-\\{right\_y}(\|p)$;\5 +$\\{max\_coef}\K\\{abs}(\\{x0})$;\C{we take \\{abs} just to make sure}\6 +\&{if} $\\{abs}(\\{x1})>\\{max\_coef}$ \1\&{then}\5 +$\\{max\_coef}\K\\{abs}(\\{x1})$;\2\6 +\&{if} $\\{abs}(\\{x2})>\\{max\_coef}$ \1\&{then}\5 +$\\{max\_coef}\K\\{abs}(\\{x2})$;\2\6 +\&{if} $\\{abs}(\\{y0})>\\{max\_coef}$ \1\&{then}\5 +$\\{max\_coef}\K\\{abs}(\\{y0})$;\2\6 +\&{if} $\\{abs}(\\{y1})>\\{max\_coef}$ \1\&{then}\5 +$\\{max\_coef}\K\\{abs}(\\{y1})$;\2\6 +\&{if} $\\{abs}(\\{y2})>\\{max\_coef}$ \1\&{then}\5 +$\\{max\_coef}\K\\{abs}(\\{y2})$;\2\6 +\&{if} $\\{max\_coef}=0$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +\&{while} $\\{max\_coef}<\\{fraction\_half}$ \1\&{do}\6 +\&{begin} \37$\\{double}(\\{max\_coef})$;\5 +$\\{double}(\\{x0})$;\5 +$\\{double}(\\{x1})$;\5 +$\\{double}(\\{x2})$;\5 +$\\{double}(\\{y0})$;\5 +$\\{double}(\\{y1})$;\5 +$\\{double}(\\{y2})$;\6 +\&{end}\2\par +\U494.\fi + +\M497. Let us first solve a special case of the problem: Suppose we +know an index~$k$ such that either (i)~$s(t)\G s_{k-1}$ for all~$t$ +and $s(0)<s_k$, or (ii)~$s(t)\L s_k$ for all~$t$ and $s(0)>s_{k-1}$. +Then, in a sense, we're halfway done, since one of the two inequalities +in $(*)$ is satisfied, and the other couldn't be satisfied for +any other value of~\|k. + +The \\{fin\_offset\_prep} subroutine solves the stated subproblem. +It has a boolean parameter called \\{rising} that is \\{true} in +case~(i), \\{false} in case~(ii). When $\\{rising}=\\{false}$, parameters +\\{x0} through \\{y2} represent the negative of the derivative of +the cubic following \|p; otherwise they represent the actual derivative. +The \|w parameter should point to offset~$w_k$. + +\Y\P$\4\X493:Declare subroutines needed by \\{offset\_prep}\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{fin\_offset\_prep}(\|p:\\{pointer};\,\35\|k:% +\\{halfword};\,\35\|w:\\{pointer};\,\35\\{x0},\39\\{x1},\39\\{x2},\39\\{y0},\39% +\\{y1},\39\\{y2}:\\{integer};\,\35\\{rising}:\\{boolean};\,\35\|n:% +\\{integer})$;\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37\\{ww}: \37\\{pointer};\C{for list manipulation}\6 +$\\{du},\39\\{dv}$: \37\\{scaled};\C{for slope calculation}\6 +$\\{t0},\39\\{t1},\39\\{t2}$: \37\\{integer};\C{test coefficients}\6 +\|t: \37\\{fraction};\C{place where the derivative passes a critical slope}\6 +\|s: \37\\{fraction};\C{slope or reciprocal slope}\6 +\|v: \37\\{integer};\C{intermediate value for updating $\\{x0}\to\\{y2}$}\2\6 +\&{begin} \37\~ \1\&{loop}\6 +\&{begin} \37$\\{right\_type}(\|p)\K\|k$;\6 +\&{if} $\\{rising}$ \1\&{then}\6 +\&{if} $\|k=\|n$ \1\&{then}\5 +\&{return}\6 +\4\&{else} $\\{ww}\K\\{link}(\|w)$\C{a pointer to $w\k$}\2\6 +\4\&{else} \&{if} $\|k=1$ \1\&{then}\5 +\&{return}\6 +\4\&{else} $\\{ww}\K\\{knil}(\|w)$;\C{a pointer to $w_{k-1}$}\2\2\6 +\X498:Compute test coefficients $(\\{t0},\\{t1},\\{t2})$ for $s(t)$ versus +$s_k$ or $s_{k-1}$\X;\6 +$\|t\K\\{crossing\_point}(\\{t0},\39\\{t1},\39\\{t2})$;\6 +\&{if} $\|t\G\\{fraction\_one}$ \1\&{then}\5 +\&{return};\2\6 +\X499:Split the cubic at $t$, and split off another cubic if the derivative +crosses back\X;\6 +\&{if} $\\{rising}$ \1\&{then}\5 +$\\{incr}(\|k)$\ \&{else} $\\{decr}(\|k)$;\2\6 +$\|w\K\\{ww}$;\6 +\&{end};\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M498. \P$\X498:Compute test coefficients $(\\{t0},\\{t1},\\{t2})$ for $s(t)$ +versus $s_k$ or $s_{k-1}$\X\S$\6 +$\\{du}\K\\{x\_coord}(\\{ww})-\\{x\_coord}(\|w)$;\5 +$\\{dv}\K\\{y\_coord}(\\{ww})-\\{y\_coord}(\|w)$;\6 +\&{if} $\\{abs}(\\{du})\G\\{abs}(\\{dv})$ \1\&{then}\C{$s_{k\pm1}\le1$}\6 +\&{begin} \37$\|s\K\\{make\_fraction}(\\{dv},\39\\{du})$;\5 +$\\{t0}\K\\{take\_fraction}(\\{x0},\39\|s)-\\{y0}$;\5 +$\\{t1}\K\\{take\_fraction}(\\{x1},\39\|s)-\\{y1}$;\5 +$\\{t2}\K\\{take\_fraction}(\\{x2},\39\|s)-\\{y2}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|s\K\\{make\_fraction}(\\{du},\39\\{dv})$;\5 +$\\{t0}\K\\{x0}-\\{take\_fraction}(\\{y0},\39\|s)$;\5 +$\\{t1}\K\\{x1}-\\{take\_fraction}(\\{y1},\39\|s)$;\5 +$\\{t2}\K\\{x2}-\\{take\_fraction}(\\{y2},\39\|s)$;\6 +\&{end}\2\par +\Us497\ET503.\fi + +\M499. The curve has crossed $s_k$ or $s_{k-1}$; its initial segment satisfies +$(*)$, and it might cross again and return towards $s_k$, yielding another +solution of $(*)$. + +\Y\P$\4\X499:Split the cubic at $t$, and split off another cubic if the +derivative crosses back\X\S$\6 +\&{begin} \37$\\{split\_for\_offset}(\|p,\39\|t)$;\5 +$\\{right\_type}(\|p)\K\|k$;\5 +$\|p\K\\{link}(\|p)$;\6 +$\|v\K\\{t\_of\_the\_way}(\\{x0})(\\{x1})$;\5 +$\\{x1}\K\\{t\_of\_the\_way}(\\{x1})(\\{x2})$;\5 +$\\{x0}\K\\{t\_of\_the\_way}(\|v)(\\{x1})$;\6 +$\|v\K\\{t\_of\_the\_way}(\\{y0})(\\{y1})$;\5 +$\\{y1}\K\\{t\_of\_the\_way}(\\{y1})(\\{y2})$;\5 +$\\{y0}\K\\{t\_of\_the\_way}(\|v)(\\{y1})$;\6 +$\\{t1}\K\\{t\_of\_the\_way}(\\{t1})(\\{t2})$;\6 +\&{if} $\\{t1}>0$ \1\&{then}\5 +$\\{t1}\K0$;\C{without rounding error, \\{t1} would be $\L0$}\2\6 +$\|t\K\\{crossing\_point}(0,\39-\\{t1},\39-\\{t2})$;\6 +\&{if} $\|t<\\{fraction\_one}$ \1\&{then}\6 +\&{begin} \37$\\{split\_for\_offset}(\|p,\39\|t)$;\5 +$\\{right\_type}(\\{link}(\|p))\K\|k$;\6 +$\|v\K\\{t\_of\_the\_way}(\\{x1})(\\{x2})$;\5 +$\\{x1}\K\\{t\_of\_the\_way}(\\{x0})(\\{x1})$;\5 +$\\{x2}\K\\{t\_of\_the\_way}(\\{x1})(\|v)$;\6 +$\|v\K\\{t\_of\_the\_way}(\\{y1})(\\{y2})$;\5 +$\\{y1}\K\\{t\_of\_the\_way}(\\{y0})(\\{y1})$;\5 +$\\{y2}\K\\{t\_of\_the\_way}(\\{y1})(\|v)$;\6 +\&{end};\2\6 +\&{end}\par +\U497.\fi + +\M500. Now we must consider the general problem of \\{offset\_prep}, when +nothing is known about a given cubic. We start by finding its +slope $s(0)$ in the vicinity of $\|t=0$. + +If $z'(t)=0$, the given cubic is numerically unstable, since the +slope direction is probably being influenced primarily by rounding +errors. A user who specifies such cuspy curves should expect to generate +rather wild results. The present code tries its best to believe the +existing data, as if no rounding errors were present. + +\fi + +\M501. \P$\X501:Find the initial slope, $\\{dy}/\\{dx}$\X\S$\6 +$\\{dx}\K\\{x0}$;\5 +$\\{dy}\K\\{y0}$;\6 +\&{if} $\\{dx}=0$ \1\&{then}\6 +\&{if} $\\{dy}=0$ \1\&{then}\6 +\&{begin} \37$\\{dx}\K\\{x1}$;\5 +$\\{dy}\K\\{y1}$;\6 +\&{if} $\\{dx}=0$ \1\&{then}\6 +\&{if} $\\{dy}=0$ \1\&{then}\6 +\&{begin} \37$\\{dx}\K\\{x2}$;\5 +$\\{dy}\K\\{y2}$;\6 +\&{end};\2\2\6 +\&{end}\2\2\par +\U494.\fi + +\M502. The next step is to bracket the initial slope between consecutive +slopes of the pen polygon. The most important invariant relation in the +following loop is that $\\{dy}/\\{dx}\G\hbox{$s_{k-1}$}$. + +\Y\P$\4\X502:Find the index \|k such that $s_{k-1}\L\\{dy}/\\{dx}<s_k$\X\S$\6 +$\|k\K1$;\5 +$\|w\K\\{link}(\\{lh})$;\6 +\~ \1\&{loop}\ \&{begin} \37\&{if} $\|k=\|n$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\\{ww}\K\\{link}(\|w)$;\6 +\&{if} $\\{ab\_vs\_cd}(\\{dy},\39\\{abs}(\\{x\_coord}(\\{ww})-\\{x\_coord}(% +\|w)),\39\30\\{dx},\39\\{abs}(\\{y\_coord}(\\{ww})-\\{y\_coord}(\|w)))\G0$ \1% +\&{then}\6 +\&{begin} \37$\\{incr}(\|k)$;\5 +$\|w\K\\{ww}$;\6 +\&{end}\6 +\4\&{else} \&{goto} \37\\{done};\2\6 +\&{end};\2\6 +\4\\{done}: \37\par +\U494.\fi + +\M503. Finally we want to reduce the general problem to situations that +\\{fin\_offset\_prep} can handle. If $\|k=1$, we already are in the desired +situation. Otherwise we can split the cubic into at most three parts +with respect to $s_{k-1}$, and apply \\{fin\_offset\_prep} to each part. + +\Y\P$\4\X503:Complete the offset splitting process\X\S$\6 +\&{if} $\|k=1$ \1\&{then}\5 +$\|t\K\\{fraction\_one}+1$\6 +\4\&{else} \&{begin} \37$\\{ww}\K\\{knil}(\|w)$;\5 +\X498:Compute test coefficients $(\\{t0},\\{t1},\\{t2})$ for $s(t)$ versus +$s_k$ or $s_{k-1}$\X;\6 +$\|t\K\\{crossing\_point}(-\\{t0},\39-\\{t1},\39-\\{t2})$;\6 +\&{end};\2\6 +\&{if} $\|t\G\\{fraction\_one}$ \1\&{then}\5 +$\\{fin\_offset\_prep}(\|p,\39\|k,\39\|w,\39\\{x0},\39\\{x1},\39\\{x2},\39% +\\{y0},\39\\{y1},\39\\{y2},\39\\{true},\39\|n)$\6 +\4\&{else} \&{begin} \37$\\{split\_for\_offset}(\|p,\39\|t)$;\5 +$\|r\K\\{link}(\|p)$;\6 +$\\{x1a}\K\\{t\_of\_the\_way}(\\{x0})(\\{x1})$;\5 +$\\{x1}\K\\{t\_of\_the\_way}(\\{x1})(\\{x2})$;\5 +$\\{x2a}\K\\{t\_of\_the\_way}(\\{x1a})(\\{x1})$;\6 +$\\{y1a}\K\\{t\_of\_the\_way}(\\{y0})(\\{y1})$;\5 +$\\{y1}\K\\{t\_of\_the\_way}(\\{y1})(\\{y2})$;\5 +$\\{y2a}\K\\{t\_of\_the\_way}(\\{y1a})(\\{y1})$;\6 +$\\{fin\_offset\_prep}(\|p,\39\|k,\39\|w,\39\\{x0},\39\\{x1a},\39\\{x2a},\39% +\\{y0},\39\\{y1a},\39\\{y2a},\39\\{true},\39\|n)$;\5 +$\\{x0}\K\\{x2a}$;\5 +$\\{y0}\K\\{y2a}$;\5 +$\\{t1}\K\\{t\_of\_the\_way}(\\{t1})(\\{t2})$;\6 +\&{if} $\\{t1}<0$ \1\&{then}\5 +$\\{t1}\K0$;\2\6 +$\|t\K\\{crossing\_point}(0,\39\\{t1},\39\\{t2})$;\6 +\&{if} $\|t<\\{fraction\_one}$ \1\&{then}\5 +\X504:Split off another \\{rising} cubic for \\{fin\_offset\_prep}\X;\2\6 +$\\{fin\_offset\_prep}(\|r,\39\|k-1,\39\\{ww},\39-\\{x0},\39-\\{x1},\39-\\{x2},% +\39-\\{y0},\39-\\{y1},\39-\\{y2},\39\\{false},\39\|n)$;\6 +\&{end}\2\par +\U494.\fi + +\M504. \P$\X504:Split off another \\{rising} cubic for \\{fin\_offset\_prep}\X% +\S$\6 +\&{begin} \37$\\{split\_for\_offset}(\|r,\39\|t)$;\6 +$\\{x1a}\K\\{t\_of\_the\_way}(\\{x1})(\\{x2})$;\5 +$\\{x1}\K\\{t\_of\_the\_way}(\\{x0})(\\{x1})$;\5 +$\\{x0a}\K\\{t\_of\_the\_way}(\\{x1})(\\{x1a})$;\6 +$\\{y1a}\K\\{t\_of\_the\_way}(\\{y1})(\\{y2})$;\5 +$\\{y1}\K\\{t\_of\_the\_way}(\\{y0})(\\{y1})$;\5 +$\\{y0a}\K\\{t\_of\_the\_way}(\\{y1})(\\{y1a})$;\6 +$\\{fin\_offset\_prep}(\\{link}(\|r),\39\|k,\39\|w,\39\\{x0a},\39\\{x1a},\39% +\\{x2},\39\\{y0a},\39\\{y1a},\39\\{y2},\39\\{true},\39\|n)$;\5 +$\\{x2}\K\\{x0a}$;\5 +$\\{y2}\K\\{y0a}$;\6 +\&{end}\par +\U503.\fi + +\M505. \P$\X505:Handle the special case of infinite slope\X\S$\6 +$\\{fin\_offset\_prep}(\|p,\39\|n,\39\\{knil}(\\{knil}(\\{lh})),\39-\\{x0},\39-% +\\{x1},\39-\\{x2},\39-\\{y0},\39-\\{y1},\39-\\{y2},\39\\{false},\39\|n)$\par +\U494.\fi + +\M506. OK, it's time now for the biggie. The \\{fill\_envelope} routine +generalizes +\\{fill\_spec} to polygonal envelopes. Its outer structure is essentially the +same as before, except that octants with no cubics do contribute to +the envelope. + +\Y\P\hbox{\4}\X510:Declare the procedure called \\{skew\_line\_edges}\X\6 +\hbox{\4}\X518:Declare the procedure called \\{dual\_moves}\X\6 +\4\&{procedure}\1\ \37$\\{fill\_envelope}(\\{spec\_head}:\\{pointer})$;\6 +\4\&{label} \37$\\{done},\39\\{done1}$;\6 +\4\&{var} \37$\|p,\39\|q,\39\|r,\39\|s$: \37\\{pointer};\C{for list traversal}\6 +\|h: \37\\{pointer};\C{head of pen offset list for current octant}\6 +\\{www}: \37\\{pointer};\C{a pen offset of temporary interest}\6 +\X511:Other local variables for \\{fill\_envelope}\X\2\6 +\&{begin} \37\&{if} $\\{internal}[\\{tracing\_edges}]>0$ \1\&{then}\5 +\\{begin\_edge\_tracing};\2\6 +$\|p\K\\{spec\_head}$;\C{we assume that $\\{left\_type}(\\{spec\_head})=% +\\{endpoint}$}\6 +\1\&{repeat} \37$\\{octant}\K\\{left\_octant}(\|p)$;\5 +$\|h\K\\{cur\_pen}+\\{octant}$;\5 +\X466:Set variable \|q to the node at the end of the current octant\X;\6 +\X508:Determine the envelope's starting and ending lattice points $(\\{m0},% +\\{n0})$ and $(\\{m1},\\{n1})$\X;\6 +$\\{offset\_prep}(\|p,\39\|h)$;\C{this may clobber node~\|q, if it becomes +``dead''}\6 +\X466:Set variable \|q to the node at the end of the current octant\X;\6 +\X512:Make the envelope moves for the current octant and insert them in the +pixel data\X;\6 +$\|p\K\\{link}(\|q)$;\6 +\4\&{until}\5 +$\|p=\\{spec\_head}$;\2\6 +\&{if} $\\{internal}[\\{tracing\_edges}]>0$ \1\&{then}\5 +\\{end\_edge\_tracing};\2\6 +$\\{toss\_knot\_list}(\\{spec\_head})$;\6 +\&{end};\par +\fi + +\M507. In even-numbered octants we have reflected the coordinates an odd number +of times, hence clockwise and counterclockwise are reversed; this means that +the envelope is being formed in a ``dual'' manner. For the time being, let's +concentrate on odd-numbered octants, since they're easier to understand. +After we have coded the program for odd-numbered octants, the changes needed +to dualize it will not be so mysterious. + +It is convenient to assume that we enter an odd-numbered octant with +an \\{axis} transition (where the skewed slope is zero) and leave at a +\\{diagonal} one (where the skewed slope is infinite). Then all of the +offset points $z(t)+w(t)$ will lie in a rectangle whose lower left and +upper right corners are the initial and final offset points. If this +assumption doesn't hold we can implicitly change the curve so that it does. +For example, if the entering transition is diagonal, we can draw a +straight line from $z_0+w_{n+1}$ to $z_0+w_0$ and continue as if the +curve were moving rightward. The effect of this on the envelope is simply +to ``doubly color'' the region enveloped by a section of the pen that +goes from $w_0$ to $w_1$ to $\cdots$ to $w_{n+1}$ to~$w_0$. The additional +straight line at the beginning (and a similar one at the end, where it +may be necessary to go from $z_1+w_{n+1}$ to $z_1+w_0$) can be drawn by +the \\{line\_edges} routine; we are thereby saved from the embarrassment that +these lines travel backwards from the current octant direction. + +Once we have established the assumption that the curve goes from +$z_0+w_0$ to $z_1+w_{n+1}$, any further retrograde moves that might +occur within the octant can be essentially ignored; we merely need to +keep track of the rightmost edge in each row, in order to compute +the envelope. + +Envelope moves consist of offset cubics intermixed with straight line +segments. We record them in a separate \\{env\_move} array, which is +something like \\{move} but it keeps track of the rightmost position of the +envelope in each row. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{env\_move}: \37\&{array} $[0\to\\{move\_size}]$ \1\&{of}\5 +\\{integer};\2\par +\fi + +\M508. \P$\X508:Determine the envelope's starting and ending lattice points $(% +\\{m0},\\{n0})$ and $(\\{m1},\\{n1})$\X\S$\6 +$\|w\K\\{link}(\|h)$;\ \&{if} $\\{left\_transition}(\|p)=\\{diagonal}$ \1% +\&{then}\5 +$\|w\K\\{knil}(\|w)$;\2\6 +\&{stat} \37\&{if} $\\{internal}[\\{tracing\_edges}]>\\{unity}$ \1\&{then}\5 +\X509:Print a line of diagnostic info to introduce this octant\X;\2\6 +\&{tats}\6 +$\\{ww}\K\\{link}(\|h)$;\5 +$\\{www}\K\\{ww}$;\C{starting and ending offsets}\6 +\&{if} $\\{odd}(\\{octant\_number}[\\{octant}])$ \1\&{then}\5 +$\\{www}\K\\{knil}(\\{www})$\ \&{else} $\\{ww}\K\\{knil}(\\{ww})$;\2\6 +\&{if} $\|w\I\\{ww}$ \1\&{then}\5 +$\\{skew\_line\_edges}(\|p,\39\|w,\39\\{ww})$;\2\6 +$\\{end\_round}(\\{x\_coord}(\|p)+\\{x\_coord}(\\{ww}),\39\\{y\_coord}(\|p)+% +\\{y\_coord}(\\{ww}))$;\5 +$\\{m0}\K\\{m1}$;\5 +$\\{n0}\K\\{n1}$;\5 +$\\{d0}\K\\{d1}$;\6 +$\\{end\_round}(\\{x\_coord}(\|q)+\\{x\_coord}(\\{www}),\39\\{y\_coord}(\|q)+% +\\{y\_coord}(\\{www}))$;\6 +\&{if} $\\{n1}-\\{n0}\G\\{move\_size}$ \1\&{then}\5 +$\\{overflow}(\.{"move\ table\ size"},\39\\{move\_size})$\2\par +\U506.\fi + +\M509. \P$\X509:Print a line of diagnostic info to introduce this octant\X\S$\6 +\&{begin} \37$\\{print\_nl}(\.{"@\ Octant\ "})$;\5 +$\\{print}(\\{octant\_dir}[\\{octant}])$;\5 +$\\{print}(\.{"\ ("})$;\5 +$\\{print\_int}(\\{info}(\|h))$;\5 +$\\{print}(\.{"\ offset"})$;\6 +\&{if} $\\{info}(\|h)\I1$ \1\&{then}\5 +$\\{print\_char}(\.{"s"})$;\2\6 +$\\{print}(\.{"),\ from\ "})$;\5 +$\\{print\_two\_true}(\\{x\_coord}(\|p)+\\{x\_coord}(\|w),\39\\{y\_coord}(\|p)+% +\\{y\_coord}(\|w))$;\5 +$\\{ww}\K\\{link}(\|h)$;\ \&{if} $\\{right\_transition}(\|q)=\\{diagonal}$ \1% +\&{then}\5 +$\\{ww}\K\\{knil}(\\{ww})$;\2\6 +$\\{print}(\.{"\ to\ "})$;\5 +$\\{print\_two\_true}(\\{x\_coord}(\|q)+\\{x\_coord}(\\{ww}),\39\\{y\_coord}(% +\|q)+\\{y\_coord}(\\{ww}))$;\6 +\&{end}\par +\U508.\fi + +\M510. A slight variation of the \\{line\_edges} procedure comes in handy +when we must draw the retrograde lines for nonstandard entry and exit +conditions. + +\Y\P$\4\X510:Declare the procedure called \\{skew\_line\_edges}\X\S$\6 +\4\&{procedure}\1\ \37$\\{skew\_line\_edges}(\|p,\39\|w,\39\\{ww}:% +\\{pointer})$;\6 +\4\&{var} \37$\\{x0},\39\\{y0},\39\\{x1},\39\\{y1}$: \37\\{scaled};\C{from and +to}\2\6 +\&{begin} \37\&{if} $(\\{x\_coord}(\|w)\I\\{x\_coord}(\\{ww}))\V(\\{y\_coord}(% +\|w)\I\\{y\_coord}(\\{ww}))$ \1\&{then}\6 +\&{begin} \37$\\{x0}\K\\{x\_coord}(\|p)+\\{x\_coord}(\|w)$;\5 +$\\{y0}\K\\{y\_coord}(\|p)+\\{y\_coord}(\|w)$;\6 +$\\{x1}\K\\{x\_coord}(\|p)+\\{x\_coord}(\\{ww})$;\5 +$\\{y1}\K\\{y\_coord}(\|p)+\\{y\_coord}(\\{ww})$;\6 +$\\{unskew}(\\{x0},\39\\{y0},\39\\{octant})$;\C{unskew and unrotate the +coordinates}\6 +$\\{x0}\K\\{cur\_x}$;\5 +$\\{y0}\K\\{cur\_y}$;\6 +$\\{unskew}(\\{x1},\39\\{y1},\39\\{octant})$;\6 +\&{stat} \37\&{if} $\\{internal}[\\{tracing\_edges}]>\\{unity}$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"@\ retrograde\ line\ from\ "})$;\5 +$\\{print\_two}(\\{x0},\39\\{y0})$;\5 +$\\{print}(\.{"\ to\ "})$;\5 +$\\{print\_two}(\\{cur\_x},\39\\{cur\_y})$;\5 +$\\{print\_nl}(\.{""})$;\6 +\&{end};\ \2\6 +\&{tats}\6 +$\\{line\_edges}(\\{x0},\39\\{y0},\39\\{cur\_x},\39\\{cur\_y})$;\C{then draw a +straight line}\6 +\&{end};\2\6 +\&{end};\par +\U506.\fi + +\M511. The envelope calculations require more local variables than we needed +in the simpler case of \\{fill\_spec}. At critical points in the computation, +\|w will point to offset $w_k$; \|m and \|n will record the current +lattice positions. The values of \\{move\_ptr} after the initial and before +the final offset adjustments are stored in \\{smooth\_bot} and \\{smooth\_top}, +respectively. + +\Y\P$\4\X511:Other local variables for \\{fill\_envelope}\X\S$\6 +\4$\|m,\39\|n$: \37\\{integer};\C{current lattice position}\6 +\4$\\{mm0},\39\\{mm1}$: \37\\{integer};\C{skewed equivalents of \\{m0} and % +\\{m1}}\6 +\4\|k: \37\\{integer};\C{current offset number}\6 +\4$\|w,\39\\{ww}$: \37\\{pointer};\C{pointers to the current offset and its +neighbor}\6 +\4$\\{smooth\_bot},\39\\{smooth\_top}$: \37$0\to\\{move\_size}$;\C{boundaries +of smoothing}\6 +\4$\\{xx},\39\\{yy},\39\\{xp},\39\\{yp},\39\\{delx},\39\\{dely},\39\\{tx},\39% +\\{ty}$: \37\\{scaled};\C{registers for coordinate calculations}\par +\Us506\ET518.\fi + +\M512. \P$\X512:Make the envelope moves for the current octant and insert them +in the pixel data\X\S$\6 +\&{if} $\\{odd}(\\{octant\_number}[\\{octant}])$ \1\&{then}\6 +\&{begin} \37\X513:Initialize for ordinary envelope moves\X;\6 +$\|r\K\|p$;\5 +$\\{right\_type}(\|q)\K\\{info}(\|h)+1$;\6 +\~ \1\&{loop}\ \&{begin} \37\&{if} $\|r=\|q$ \1\&{then}\5 +$\\{smooth\_top}\K\\{move\_ptr}$;\2\6 +\&{while} $\\{right\_type}(\|r)\I\|k$ \1\&{do}\5 +\X515:Insert a line segment to approach the correct offset\X;\2\6 +\&{if} $\|r=\|p$ \1\&{then}\5 +$\\{smooth\_bot}\K\\{move\_ptr}$;\2\6 +\&{if} $\|r=\|q$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\\{move}[\\{move\_ptr}]\K1$;\5 +$\|n\K\\{move\_ptr}$;\5 +$\|s\K\\{link}(\|r)$;\6 +$\\{make\_moves}(\\{x\_coord}(\|r)+\\{x\_coord}(\|w),\39\\{right\_x}(\|r)+\\{x% +\_coord}(\|w),\39\\{left\_x}(\|s)+\\{x\_coord}(\|w),\39\\{x\_coord}(\|s)+\\{x% +\_coord}(\|w),\39\30\\{y\_coord}(\|r)+\\{y\_coord}(\|w)+\\{half\_unit},\39% +\\{right\_y}(\|r)+\\{y\_coord}(\|w)+\\{half\_unit},\39\\{left\_y}(\|s)+\\{y% +\_coord}(\|w)+\\{half\_unit},\39\\{y\_coord}(\|s)+\\{y\_coord}(\|w)+\\{half% +\_unit},\39\30\\{xy\_corr}[\\{octant}],\39\\{y\_corr}[\\{octant}])$;\6 +\X514:Transfer moves from the \\{move} array to \\{env\_move}\X;\6 +$\|r\K\|s$;\6 +\&{end};\2\6 +\4\\{done}: \37\X517:Insert the new envelope moves in the pixel data\X;\6 +\&{end}\6 +\4\&{else} $\\{dual\_moves}(\|h,\39\|p,\39\|q)$;\2\6 +$\\{right\_type}(\|q)\K\\{endpoint}$\par +\U506.\fi + +\M513. \P$\X513:Initialize for ordinary envelope moves\X\S$\6 +$\|k\K0$;\5 +$\|w\K\\{link}(\|h)$;\5 +$\\{ww}\K\\{knil}(\|w)$;\5 +$\\{mm0}\K\\{floor\_unscaled}(\\{x\_coord}(\|p)+\\{x\_coord}(\|w)-\\{xy\_corr}[% +\\{octant}])$;\5 +$\\{mm1}\K\\{floor\_unscaled}(\\{x\_coord}(\|q)+\\{x\_coord}(\\{ww})-\\{xy% +\_corr}[\\{octant}])$;\6 +\&{for} $\|n\K0\mathrel{\&{to}}\\{n1}-\\{n0}$ \1\&{do}\5 +$\\{env\_move}[\|n]\K\\{mm0}$;\2\6 +$\\{env\_move}[\\{n1}-\\{n0}]\K\\{mm1}$;\5 +$\\{move\_ptr}\K0$;\5 +$\|m\K\\{mm0}$\par +\U512.\fi + +\M514. At this point \|n holds the value of \\{move\_ptr} that was current +when \\{make\_moves} began to record its moves. + +\Y\P$\4\X514:Transfer moves from the \\{move} array to \\{env\_move}\X\S$\6 +\1\&{repeat} \37$\|m\K\|m+\\{move}[\|n]-1$;\6 +\&{if} $\|m>\\{env\_move}[\|n]$ \1\&{then}\5 +$\\{env\_move}[\|n]\K\|m$;\2\6 +$\\{incr}(\|n)$;\6 +\4\&{until}\5 +$\|n>\\{move\_ptr}$\2\par +\U512.\fi + +\M515. Retrograde lines (when \|k decreases) do not need to be recorded in +\\{env\_move} because their edges are not the furthest right in any row. + +\Y\P$\4\X515:Insert a line segment to approach the correct offset\X\S$\6 +\&{begin} \37$\\{xx}\K\\{x\_coord}(\|r)+\\{x\_coord}(\|w)$;\5 +$\\{yy}\K\\{y\_coord}(\|r)+\\{y\_coord}(\|w)+\\{half\_unit}$;\6 +\&{stat} \37\&{if} $\\{internal}[\\{tracing\_edges}]>\\{unity}$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"@\ transition\ line\ "})$;\5 +$\\{print\_int}(\|k)$;\5 +$\\{print}(\.{",\ from\ "})$;\5 +$\\{print\_two\_true}(\\{xx},\39\\{yy}-\\{half\_unit})$;\6 +\&{end};\ \2\6 +\&{tats}\6 +\&{if} $\\{right\_type}(\|r)>\|k$ \1\&{then}\6 +\&{begin} \37$\\{incr}(\|k)$;\5 +$\|w\K\\{link}(\|w)$;\5 +$\\{xp}\K\\{x\_coord}(\|r)+\\{x\_coord}(\|w)$;\5 +$\\{yp}\K\\{y\_coord}(\|r)+\\{y\_coord}(\|w)+\\{half\_unit}$;\6 +\&{if} $\\{yp}\I\\{yy}$ \1\&{then}\5 +\X516:Record a line segment from $(\\{xx},\\{yy})$ to $(\\{xp},\\{yp})$ in % +\\{env\_move}\X;\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{decr}(\|k)$;\5 +$\|w\K\\{knil}(\|w)$;\5 +$\\{xp}\K\\{x\_coord}(\|r)+\\{x\_coord}(\|w)$;\5 +$\\{yp}\K\\{y\_coord}(\|r)+\\{y\_coord}(\|w)+\\{half\_unit}$;\6 +\&{end};\2\6 +\&{stat} \37\&{if} $\\{internal}[\\{tracing\_edges}]>\\{unity}$ \1\&{then}\6 +\&{begin} \37$\\{print}(\.{"\ to\ "})$;\5 +$\\{print\_two\_true}(\\{xp},\39\\{yp}-\\{half\_unit})$;\5 +$\\{print\_nl}(\.{""})$;\6 +\&{end};\ \2\6 +\&{tats}\6 +$\|m\K\\{floor\_unscaled}(\\{xp}-\\{xy\_corr}[\\{octant}])$;\5 +$\\{move\_ptr}\K\\{floor\_unscaled}(\\{yp}-\\{y\_corr}[\\{octant}])-\\{n0}$;\6 +\&{if} $\|m>\\{env\_move}[\\{move\_ptr}]$ \1\&{then}\5 +$\\{env\_move}[\\{move\_ptr}]\K\|m$;\2\6 +\&{end}\par +\U512.\fi + +\M516. In this step we have $\\{xp}\G\\{xx}$ and $\\{yp}\G\\{yy}$. + +\Y\P$\4\X516:Record a line segment from $(\\{xx},\\{yy})$ to $(\\{xp},\\{yp})$ +in \\{env\_move}\X\S$\6 +\&{begin} \37$\\{ty}\K\\{floor\_scaled}(\\{yy}-\\{y\_corr}[\\{octant}])$;\5 +$\\{dely}\K\\{yp}-\\{yy}$;\5 +$\\{yy}\K\\{yy}-\\{ty}$;\5 +$\\{ty}\K\\{yp}-\\{y\_corr}[\\{octant}]-\\{ty}$;\6 +\&{if} $\\{ty}\G\\{unity}$ \1\&{then}\6 +\&{begin} \37$\\{delx}\K\\{xp}-\\{xx}$;\5 +$\\{yy}\K\\{unity}-\\{yy}$;\6 +\~ \1\&{loop}\ \&{begin} \37$\\{tx}\K\\{take\_fraction}(\\{delx},\39\\{make% +\_fraction}(\\{yy},\39\\{dely}))$;\6 +\&{if} $\\{ab\_vs\_cd}(\\{tx},\39\\{dely},\39\\{delx},\39\\{yy})+\\{xy\_corr}[% +\\{octant}]>0$ \1\&{then}\5 +$\\{decr}(\\{tx})$;\2\6 +$\|m\K\\{floor\_unscaled}(\\{xx}+\\{tx})$;\6 +\&{if} $\|m>\\{env\_move}[\\{move\_ptr}]$ \1\&{then}\5 +$\\{env\_move}[\\{move\_ptr}]\K\|m$;\2\6 +$\\{ty}\K\\{ty}-\\{unity}$;\6 +\&{if} $\\{ty}<\\{unity}$ \1\&{then}\5 +\&{goto} \37\\{done1};\2\6 +$\\{yy}\K\\{yy}+\\{unity}$;\5 +$\\{incr}(\\{move\_ptr})$;\6 +\&{end};\2\6 +\4\\{done1}: \37\&{end};\2\6 +\&{end}\par +\U515.\fi + +\M517. \P$\X517:Insert the new envelope moves in the pixel data\X\S$\6 +\&{debug} \37\&{if} $(\|m\I\\{mm1})\V(\\{move\_ptr}\I\\{n1}-\\{n0})$ \1\&{then}% +\5 +$\\{confusion}(\.{"1"})$;\ \2\6 +\&{gubed}\6 +$\\{move}[0]\K\\{d0}+\\{env\_move}[0]-\\{mm0}$;\6 +\&{for} $\|n\K1\mathrel{\&{to}}\\{move\_ptr}$ \1\&{do}\5 +$\\{move}[\|n]\K\\{env\_move}[\|n]-\\{env\_move}[\|n-1]+1$;\2\6 +$\\{move}[\\{move\_ptr}]\K\\{move}[\\{move\_ptr}]-\\{d1}$;\6 +\&{if} $\\{internal}[\\{smoothing}]>0$ \1\&{then}\5 +$\\{smooth\_moves}(\\{smooth\_bot},\39\\{smooth\_top})$;\2\6 +$\\{move\_to\_edges}(\\{m0},\39\\{n0},\39\\{m1},\39\\{n1})$;\6 +\&{if} $\\{right\_transition}(\|q)=\\{axis}$ \1\&{then}\6 +\&{begin} \37$\|w\K\\{link}(\|h)$;\5 +$\\{skew\_line\_edges}(\|q,\39\\{knil}(\|w),\39\|w)$;\6 +\&{end}\2\par +\U512.\fi + +\M518. We've done it all in the odd-octant case; the only thing remaining +is to repeat the same ideas, upside down and/or backwards. + +The following code has been split off as a subprocedure of \\{fill\_envelope}, +because some \PASCAL\ compilers cannot handle procedures as large as +\\{fill\_envelope} would otherwise be. + +\Y\P$\4\X518:Declare the procedure called \\{dual\_moves}\X\S$\6 +\4\&{procedure}\1\ \37$\\{dual\_moves}(\|h,\39\|p,\39\|q:\\{pointer})$;\6 +\4\&{label} \37$\\{done},\39\\{done1}$;\6 +\4\&{var} \37$\|r,\39\|s$: \37\\{pointer};\C{for list traversal}\6 +\X511:Other local variables for \\{fill\_envelope}\X\2\6 +\&{begin} \37\X519:Initialize for dual envelope moves\X;\6 +$\|r\K\|p$;\C{recall that $\\{right\_type}(\|q)=\\{endpoint}=0$ now}\6 +\~ \1\&{loop}\ \&{begin} \37\&{if} $\|r=\|q$ \1\&{then}\5 +$\\{smooth\_top}\K\\{move\_ptr}$;\2\6 +\&{while} $\\{right\_type}(\|r)\I\|k$ \1\&{do}\5 +\X521:Insert a line segment dually to approach the correct offset\X;\2\6 +\&{if} $\|r=\|p$ \1\&{then}\5 +$\\{smooth\_bot}\K\\{move\_ptr}$;\2\6 +\&{if} $\|r=\|q$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\\{move}[\\{move\_ptr}]\K1$;\5 +$\|n\K\\{move\_ptr}$;\5 +$\|s\K\\{link}(\|r)$;\6 +$\\{make\_moves}(\\{x\_coord}(\|r)+\\{x\_coord}(\|w),\39\\{right\_x}(\|r)+\\{x% +\_coord}(\|w),\39\\{left\_x}(\|s)+\\{x\_coord}(\|w),\39\\{x\_coord}(\|s)+\\{x% +\_coord}(\|w),\39\30\\{y\_coord}(\|r)+\\{y\_coord}(\|w)+\\{half\_unit},\39% +\\{right\_y}(\|r)+\\{y\_coord}(\|w)+\\{half\_unit},\39\\{left\_y}(\|s)+\\{y% +\_coord}(\|w)+\\{half\_unit},\39\\{y\_coord}(\|s)+\\{y\_coord}(\|w)+\\{half% +\_unit},\39\30\\{xy\_corr}[\\{octant}],\39\\{y\_corr}[\\{octant}])$;\5 +\X520:Transfer moves dually from the \\{move} array to \\{env\_move}\X;\6 +$\|r\K\|s$;\6 +\&{end};\2\6 +\4\\{done}: \37\X523:Insert the new envelope moves dually in the pixel data\X;\6 +\&{end};\par +\U506.\fi + +\M519. In the dual case the normal situation is to arrive with a \\{diagonal} +transition and to leave at the \\{axis}. The leftmost edge in each row +is relevant instead of the rightmost one. + +\Y\P$\4\X519:Initialize for dual envelope moves\X\S$\6 +$\|k\K\\{info}(\|h)+1$;\5 +$\\{ww}\K\\{link}(\|h)$;\5 +$\|w\K\\{knil}(\\{ww})$;\6 +$\\{mm0}\K\\{floor\_unscaled}(\\{x\_coord}(\|p)+\\{x\_coord}(\|w)-\\{xy\_corr}[% +\\{octant}])$;\5 +$\\{mm1}\K\\{floor\_unscaled}(\\{x\_coord}(\|q)+\\{x\_coord}(\\{ww})-\\{xy% +\_corr}[\\{octant}])$;\6 +\&{for} $\|n\K1\mathrel{\&{to}}\\{n1}-\\{n0}+1$ \1\&{do}\5 +$\\{env\_move}[\|n]\K\\{mm1}$;\2\6 +$\\{env\_move}[0]\K\\{mm0}$;\5 +$\\{move\_ptr}\K0$;\5 +$\|m\K\\{mm0}$\par +\U518.\fi + +\M520. \P$\X520:Transfer moves dually from the \\{move} array to \\{env\_move}% +\X\S$\6 +\1\&{repeat} \37\&{if} $\|m<\\{env\_move}[\|n]$ \1\&{then}\5 +$\\{env\_move}[\|n]\K\|m$;\2\6 +$\|m\K\|m+\\{move}[\|n]-1$;\5 +$\\{incr}(\|n)$;\6 +\4\&{until}\5 +$\|n>\\{move\_ptr}$\2\par +\U518.\fi + +\M521. Dual retrograde lines occur when \|k increases; the edges of such lines +are not the furthest left in any row. + +\Y\P$\4\X521:Insert a line segment dually to approach the correct offset\X\S$\6 +\&{begin} \37$\\{xx}\K\\{x\_coord}(\|r)+\\{x\_coord}(\|w)$;\5 +$\\{yy}\K\\{y\_coord}(\|r)+\\{y\_coord}(\|w)+\\{half\_unit}$;\6 +\&{stat} \37\&{if} $\\{internal}[\\{tracing\_edges}]>\\{unity}$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"@\ transition\ line\ "})$;\5 +$\\{print\_int}(\|k)$;\5 +$\\{print}(\.{",\ from\ "})$;\5 +$\\{print\_two\_true}(\\{xx},\39\\{yy}-\\{half\_unit})$;\6 +\&{end};\ \2\6 +\&{tats}\6 +\&{if} $\\{right\_type}(\|r)<\|k$ \1\&{then}\6 +\&{begin} \37$\\{decr}(\|k)$;\5 +$\|w\K\\{knil}(\|w)$;\5 +$\\{xp}\K\\{x\_coord}(\|r)+\\{x\_coord}(\|w)$;\5 +$\\{yp}\K\\{y\_coord}(\|r)+\\{y\_coord}(\|w)+\\{half\_unit}$;\6 +\&{if} $\\{yp}\I\\{yy}$ \1\&{then}\5 +\X522:Record a line segment from $(\\{xx},\\{yy})$ to $(\\{xp},\\{yp})$ dually +in \\{env\_move}\X;\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{incr}(\|k)$;\5 +$\|w\K\\{link}(\|w)$;\5 +$\\{xp}\K\\{x\_coord}(\|r)+\\{x\_coord}(\|w)$;\5 +$\\{yp}\K\\{y\_coord}(\|r)+\\{y\_coord}(\|w)+\\{half\_unit}$;\6 +\&{end};\2\6 +\&{stat} \37\&{if} $\\{internal}[\\{tracing\_edges}]>\\{unity}$ \1\&{then}\6 +\&{begin} \37$\\{print}(\.{"\ to\ "})$;\5 +$\\{print\_two\_true}(\\{xp},\39\\{yp}-\\{half\_unit})$;\5 +$\\{print\_nl}(\.{""})$;\6 +\&{end};\ \2\6 +\&{tats}\6 +$\|m\K\\{floor\_unscaled}(\\{xp}-\\{xy\_corr}[\\{octant}])$;\5 +$\\{move\_ptr}\K\\{floor\_unscaled}(\\{yp}-\\{y\_corr}[\\{octant}])-\\{n0}$;\6 +\&{if} $\|m<\\{env\_move}[\\{move\_ptr}]$ \1\&{then}\5 +$\\{env\_move}[\\{move\_ptr}]\K\|m$;\2\6 +\&{end}\par +\U518.\fi + +\M522. Again, $\\{xp}\G\\{xx}$ and $\\{yp}\G\\{yy}$; but this time we are +interested in the {\sl +smallest\/} \|m that belongs to a given \\{move\_ptr} position, instead of +the largest~\|m. + +\Y\P$\4\X522:Record a line segment from $(\\{xx},\\{yy})$ to $(\\{xp},\\{yp})$ +dually in \\{env\_move}\X\S$\6 +\&{begin} \37$\\{ty}\K\\{floor\_scaled}(\\{yy}-\\{y\_corr}[\\{octant}])$;\5 +$\\{dely}\K\\{yp}-\\{yy}$;\5 +$\\{yy}\K\\{yy}-\\{ty}$;\5 +$\\{ty}\K\\{yp}-\\{y\_corr}[\\{octant}]-\\{ty}$;\6 +\&{if} $\\{ty}\G\\{unity}$ \1\&{then}\6 +\&{begin} \37$\\{delx}\K\\{xp}-\\{xx}$;\5 +$\\{yy}\K\\{unity}-\\{yy}$;\6 +\~ \1\&{loop}\ \&{begin} \37\&{if} $\|m<\\{env\_move}[\\{move\_ptr}]$ \1% +\&{then}\5 +$\\{env\_move}[\\{move\_ptr}]\K\|m$;\2\6 +$\\{tx}\K\\{take\_fraction}(\\{delx},\39\\{make\_fraction}(\\{yy},\39% +\\{dely}))$;\6 +\&{if} $\\{ab\_vs\_cd}(\\{tx},\39\\{dely},\39\\{delx},\39\\{yy})+\\{xy\_corr}[% +\\{octant}]>0$ \1\&{then}\5 +$\\{decr}(\\{tx})$;\2\6 +$\|m\K\\{floor\_unscaled}(\\{xx}+\\{tx})$;\5 +$\\{ty}\K\\{ty}-\\{unity}$;\5 +$\\{incr}(\\{move\_ptr})$;\6 +\&{if} $\\{ty}<\\{unity}$ \1\&{then}\5 +\&{goto} \37\\{done1};\2\6 +$\\{yy}\K\\{yy}+\\{unity}$;\6 +\&{end};\2\6 +\4\\{done1}: \37\&{if} $\|m<\\{env\_move}[\\{move\_ptr}]$ \1\&{then}\5 +$\\{env\_move}[\\{move\_ptr}]\K\|m$;\2\6 +\&{end};\2\6 +\&{end}\par +\U521.\fi + +\M523. Since \\{env\_move} contains minimum values instead of maximum values, +the +finishing-up process is slightly different in the dual case. + +\Y\P$\4\X523:Insert the new envelope moves dually in the pixel data\X\S$\6 +\&{debug} \37\&{if} $(\|m\I\\{mm1})\V(\\{move\_ptr}\I\\{n1}-\\{n0})$ \1\&{then}% +\5 +$\\{confusion}(\.{"2"})$;\ \2\6 +\&{gubed}\6 +$\\{move}[0]\K\\{d0}+\\{env\_move}[1]-\\{mm0}$;\6 +\&{for} $\|n\K1\mathrel{\&{to}}\\{move\_ptr}$ \1\&{do}\5 +$\\{move}[\|n]\K\\{env\_move}[\|n+1]-\\{env\_move}[\|n]+1$;\2\6 +$\\{move}[\\{move\_ptr}]\K\\{move}[\\{move\_ptr}]-\\{d1}$;\6 +\&{if} $\\{internal}[\\{smoothing}]>0$ \1\&{then}\5 +$\\{smooth\_moves}(\\{smooth\_bot},\39\\{smooth\_top})$;\2\6 +$\\{move\_to\_edges}(\\{m0},\39\\{n0},\39\\{m1},\39\\{n1})$;\6 +\&{if} $\\{right\_transition}(\|q)=\\{diagonal}$ \1\&{then}\6 +\&{begin} \37$\|w\K\\{link}(\|h)$;\5 +$\\{skew\_line\_edges}(\|q,\39\|w,\39\\{knil}(\|w))$;\6 +\&{end}\2\par +\U518.\fi + +\N524. \[25] Elliptical pens. +To get the envelope of a cyclic path with respect to an ellipse, \MF\ +calculates the envelope with respect to a polygonal approximation to +the ellipse, using an approach due to John Hobby (Ph.D. thesis, +Stanford University, 1985). +This has two important advantages over trying to obtain the ``exact'' +envelope: + +\yskip\textindent{1)}It gives better results, because the polygon has been +designed to counteract problems that arise from digitization; the +polygon includes sub-pixel corrections to an exact ellipse that make +the results essentially independent of where the path falls on the raster. +For example, the exact envelope with respect to a pen of diameter~1 +blackens a pixel if and only if the path intersects a circle of diameter~1 +inscribed in that pixel; the resulting pattern has ``blots'' when the path +is travelling diagonally in unfortunate raster positions. A much better +result is obtained when pixels are blackened only when the path intersects +an inscribed {\sl diamond\/} of diameter~1. Such a diamond is precisely +the polygon that \MF\ uses in the special case of a circle whose diameter is~1. + +\yskip\textindent{2)}Polygonal envelopes of cubic splines are cubic +splines, hence it isn't necessary to introduce completely different +routines. By contrast, exact envelopes of cubic splines with respect +to circles are complicated curves, more difficult to plot than cubics. + +\fi + +\M525. Hobby's construction involves some interesting number theory. +If $u$ and~$v$ are relatively prime integers, we divide the +set of integer points $(m,n)$ into equivalence classes by saying +that $(m,n)$ belongs to class $um+vn$. Then any two integer points +that lie on a line of slope $-u/v$ belong to the same class, because +such points have the form $(m+tv,n-tu)$. Neighboring lines of slope $-u/v$ +that go through integer points are separated by distance $1/\psqrt{u^2+v^2}$ +from each other, and these lines are perpendicular to lines of slope~$v/u$. +If we start at the origin and travel a distance $k/\psqrt{u^2+v^2}$ in +direction $(u,v)$, we reach the line of slope~$-u/v$ whose points +belong to class~$k$. + +For example, let $u=2$ and $v=3$. Then the points $(0,0)$, $(3,-2)$, +$\ldots$ belong to class~0; the points $(-1,1)$, $(2,-1)$, $\ldots$ belong +to class~1; and the distance between these two lines is $1/\sqrt{13}$. +The point $(2,3)$ itself belongs to class~13, hence its distance from +the origin is $13/\sqrt{13}=\sqrt{13}$ (which we already knew). + +Suppose we wish to plot envelopes with respect to polygons with +integer vertices. Then the best polygon for curves that travel in +direction $(v,-u)$ will contain the points of class~$k$ such that +$k/\psqrt{u^2+v^2}$ is as close as possible to~$d$, where $d$ is the +maximum distance of the given ellipse from the line $ux+vy=0$. + +The \\{fillin} correction assumes that a diagonal line has an +apparent thickness $$2f\cdot\min(\vert u\vert,\vert v\vert)/\psqrt{u^2+v^2}$$ +greater than would be obtained with truly square pixels. (If a +white pixel at an exterior corner is assumed to have apparent +darkness $f_1$ and a black pixel at an interior corner is assumed +to have apparent darkness $1-f_2$, then $f=f_1-f_2$ is the \\{fillin} +parameter.) Under this assumption we want to choose $k$ so that +$\bigl(k+2f\cdot\min(\vert u\vert,\vert v\vert)\bigr)\big/\psqrt{u^2+v^2}$ +is as close as possible to $d$. + +Integer coordinates for the vertices work nicely because the thickness of +the envelope at any given slope is independent of the position of the +path with respect to the raster. It turns out, in fact, that the same +property holds for polygons whose vertices have coordinates that are +integer multiples of~$1\over2$, because ellipses are symmetric about +the origin. It's convenient to double all dimensions and require the +resulting polygon to have vertices with integer coordinates. For example, +to get a circle of {\sl diameter}~$r$, we shall compute integer +coordinates for a circle of {\sl radius}~$r$. The circle of radius~$r$ +will want to be represented by a polygon that contains the boundary +points $(0,\pm r)$ and~$(\pm r,0)$; later we will divide everything +by~2 and get a polygon with $(0,\pm{1\over2}r)$ and $(\pm{1\over2}r,0)$ +on its boundary. + +\fi + +\M526. In practice the important slopes are those having small values of +$u$ and~$v$; these make regular patterns in which our eyes quickly +spot irregularities. For example, horizontal and vertical lines +(when $u=0$ and $\vert v\vert=1$, or $\vert u\vert=1$ and $v=0$) +are the most important; diagonal lines (when $\vert u\vert=\vert v\vert=1$) +are next; and then come lines with slope $\pm2$ or $\pm1/2$. + +The nicest way to generate all rational directions having small +numerators and denominators is to generalize the Stern-Brocot tree +[cf.~{\sl Concrete Mathematics}, section 4.5] +to a ``Stern-Brocot wreath'' as follows: Begin with four nodes +arranged in a circle, containing the respective directions +$(u,v)=(1,0)$, $(0,1)$, $(-1,0)$, and~$(0,-1)$. Then between pairs of +consecutive terms $(u,v)$ and $(u',v')$ of the wreath, insert the +direction $(u+u',v+v')$; continue doing this until some stopping +criterion is fulfilled. + +It is not difficult to verify that, regardless of the stopping +criterion, consecutive directions $(u,v)$ and $(u',v')$ of this +wreath will always satisfy the relation $uv'-u'v=1$. Such pairs +of directions have a nice property with respect to the equivalence +classes described above. Let $l$ be a line of equivalent integer points +$(m+tv,n-tu)$ with respect to~$(u,v)$, and let $l'$ be a line of +equivalent integer points $(m'+tv',n'-tu')$ with respect to~$(u',v')$. +Then $l$ and~$l'$ intersect in an integer point $(m'',n'')$, because +the determinant of the linear equations for intersection is $uv'-u'v=1$. +Notice that the class number of $(m'',n'')$ with respect to $(u+u',v+v')$ +is the sum of its class numbers with respect to $(u,v)$ and~$(u',v')$. +Moreover, consecutive points on~$l$ and~$l'$ belong to classes that +differ by exactly~1 with respect to $(u+u',v+v')$. + +This leads to a nice algorithm in which we construct a polygon having +``correct'' class numbers for as many small-integer directions $(u,v)$ +as possible: Assuming that lines $l$ and~$l'$ contain points of the +correct class for $(u,v)$ and~$(u',v')$, respectively, we determine +the intersection $(m'',n'')$ and compute its class with respect to +$(u+u',v+v')$. If the class is too large to be the best approximation, +we move back the proper number of steps from $(m'',n'')$ toward smaller +class numbers on both $l$ and~$l'$, unless this requires moving to points +that are no longer in the polygon; in this we arrive at two points that +determine a line~$l''$ having the appropriate class. The process continues +recursively, until it cannot proceed without removing the last remaining +point from the class for $(u,v)$ or the class for $(u',v')$. + +\fi + +\M527. The \\{make\_ellipse} subroutine produces a pointer to a cyclic path +whose vertices define a polygon suitable for envelopes. The control +points on this path will be ignored; in fact, the fields in knot nodes +that are usually reserved for control points are occupied by other +data that helps \\{make\_ellipse} compute the desired polygon. + +Parameters \\{major\_axis} and \\{minor\_axis} define the axes of the ellipse; +and parameter \\{theta} is an angle by which the ellipse is rotated +counterclockwise. If $\\{theta}=0$, the ellipse has the equation +$(x/a)^2+(y/b)^2=1$, where $\|a=\\{major\_axis}/2$ and $\|b=\\{minor\_axis}/2$. +In general, the points of the ellipse are generated in the complex plane +by the formula $e^{i\theta}(a\cos t+ib\sin t)$, as $t$~ranges over all +angles. Notice that if $\\{major\_axis}=\\{minor\_axis}=\|d$, we obtain a +circle +of diameter~\|d, regardless of the value of \\{theta}. + +The method sketched above is used to produce the elliptical polygon, +except that the main work is done only in the halfplane obtained from +the three starting directions $(0,-1)$, $(1,0)$,~$(0,1)$. Since the ellipse +has circular symmetry, we use the fact that the last half of the polygon +is simply the negative of the first half. Furthermore, we need to compute only +one quarter of the polygon if the ellipse has axis symmetry. + +\Y\P\4\&{function}\1\ \37$\\{make\_ellipse}(\\{major\_axis},\39\\{minor% +\_axis}:\\{scaled};\,\35\\{theta}:\\{angle})$: \37\\{pointer};\6 +\4\&{label} \37$\\{done},\39\\{done1},\39\\{found}$;\6 +\4\&{var} \37$\|p,\39\|q,\39\|r,\39\|s$: \37\\{pointer};\C{for list +manipulation}\6 +\|h: \37\\{pointer};\C{head of the constructed knot list}\6 +$\\{alpha},\39\\{beta},\39\\{gamma},\39\\{delta}$: \37\\{integer};\C{special +points}\6 +$\|c,\39\|d$: \37\\{integer};\C{class numbers}\6 +$\|u,\39\|v$: \37\\{integer};\C{directions}\6 +\\{symmetric}: \37\\{boolean};\C{should the result be symmetric about the +axes?}\2\6 +\&{begin} \37\X528:Initialize the ellipse data structure by beginning with +directions $(0,-1)$, $(1,0)$, $(0,1)$\X;\6 +\X531:Interpolate new vertices in the ellipse data structure until improvement +is impossible\X;\6 +\&{if} $\\{symmetric}$ \1\&{then}\5 +\X536:Complete the half ellipse by reflecting the quarter already computed\X;\2% +\6 +\X537:Complete the ellipse by copying the negative of the half already computed% +\X;\6 +$\\{make\_ellipse}\K\|h$;\6 +\&{end};\par +\fi + +\M528. A special data structure is used only with \\{make\_ellipse}: The +\\{right\_x}, \\{left\_x}, \\{right\_y}, and \\{left\_y} fields of knot nodes +are renamed \\{right\_u}, \\{left\_v}, \\{right\_class}, and \\{left\_length}, +in order to store information that simplifies the necessary computations. + +If \|p and \|q are consecutive knots in this data structure, the +\\{x\_coord} and \\{y\_coord} fields of \|p and~\|q contain current vertices +of the polygon; their values are integer multiples +of \\{half\_unit}. Both of these vertices belong to equivalence class +$\\{right\_class}(\|p)$ with respect to the direction +$\bigl($$\\{right\_u}(\|p),\\{left\_v}(\|q)$$\bigr)$. The number of points of +this class +on the line from vertex~\|p to vertex~\|q is $1+\\{left\_length}(\|q)$. +In particular, $\\{left\_length}(\|q)=0$ means that $\\{x\_coord}(\|p)=\\{x% +\_coord}(\|q)$ +and $\\{y\_coord}(\|p)=\\{y\_coord}(\|q)$; such duplicate vertices will be +discarded during the course of the algorithm. + +The contents of $\\{right\_u}(\|p)$ and $\\{left\_v}(\|q)$ are integer +multiples +of \\{half\_unit}, just like the coordinate fields. Hence, for example, +the point $\bigl($$\\{x\_coord}(\|p)-\\{left\_v}(\|q),\\{y\_coord}(\|p)+% +\\{right\_u}(\|q)$$\bigr)$ +also belongs to class number $\\{right\_class}(\|p)$. This point is one +step closer to the vertex in node~\|q; it equals that vertex +if and only if $\\{left\_length}(\|q)=1$. + +The \\{left\_type} and \\{right\_type} fields are not used, but \\{link} +has its normal meaning. + +To start the process, we create four nodes for the three directions +$(0,-1)$, $(1,0)$, and $(0,1)$. The corresponding vertices are +$(-\alpha,-\beta)$, $(\gamma,-\beta)$, $(\gamma,\beta)$, and +$(\alpha,\beta)$, where $(\alpha,\beta)$ is a half-integer approximation +to where the ellipse rises highest above the $x$-axis, and where +$\gamma$ is a half-integer approximation to the maximum $x$~coordinate +of the ellipse. The fourth of these nodes is not actually calculated +if the ellipse has axis symmetry. + +\Y\P\D \37$\\{right\_u}\S\\{right\_x}$\C{\|u value for a pen edge}\par +\P\D \37$\\{left\_v}\S\\{left\_x}$\C{\|v value for a pen edge}\par +\P\D \37$\\{right\_class}\S\\{right\_y}$\C{equivalence class number of a pen +edge}\par +\P\D \37$\\{left\_length}\S\\{left\_y}$\C{length of a pen edge}\par +\Y\P$\4\X528:Initialize the ellipse data structure by beginning with directions +$(0,-1)$, $(1,0)$, $(0,1)$\X\S$\6 +\X530:Calculate integers $\alpha$, $\beta$, $\gamma$ for the vertex coordinates% +\X;\6 +$\|p\K\\{get\_node}(\\{knot\_node\_size})$;\5 +$\|q\K\\{get\_node}(\\{knot\_node\_size})$;\5 +$\|r\K\\{get\_node}(\\{knot\_node\_size})$;\6 +\&{if} $\\{symmetric}$ \1\&{then}\5 +$\|s\K\\{null}$\ \&{else} $\|s\K\\{get\_node}(\\{knot\_node\_size})$;\2\6 +$\|h\K\|p$;\5 +$\\{link}(\|p)\K\|q$;\5 +$\\{link}(\|q)\K\|r$;\5 +$\\{link}(\|r)\K\|s$;\C{$\|s=\\{null}$ or $\\{link}(\|s)=\\{null}$}\6 +\X529:Revise the values of $\alpha$, $\beta$, $\gamma$, if necessary, so that +degenerate lines of length zero will not be obtained\X;\6 +$\\{x\_coord}(\|p)\K-\\{alpha}\ast\\{half\_unit}$;\5 +$\\{y\_coord}(\|p)\K-\\{beta}\ast\\{half\_unit}$;\5 +$\\{x\_coord}(\|q)\K\\{gamma}\ast\\{half\_unit}$;\6 +$\\{y\_coord}(\|q)\K\\{y\_coord}(\|p)$;\5 +$\\{x\_coord}(\|r)\K\\{x\_coord}(\|q)$;\6 +$\\{right\_u}(\|p)\K0$;\5 +$\\{left\_v}(\|q)\K-\\{half\_unit}$;\6 +$\\{right\_u}(\|q)\K\\{half\_unit}$;\5 +$\\{left\_v}(\|r)\K0$;\6 +$\\{right\_u}(\|r)\K0$;\5 +$\\{right\_class}(\|p)\K\\{beta}$;\5 +$\\{right\_class}(\|q)\K\\{gamma}$;\5 +$\\{right\_class}(\|r)\K\\{beta}$;\6 +$\\{left\_length}(\|q)\K\\{gamma}+\\{alpha}$;\6 +\&{if} $\\{symmetric}$ \1\&{then}\6 +\&{begin} \37$\\{y\_coord}(\|r)\K0$;\5 +$\\{left\_length}(\|r)\K\\{beta}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{y\_coord}(\|r)\K-\\{y\_coord}(\|p)$;\5 +$\\{left\_length}(\|r)\K\\{beta}+\\{beta}$;\6 +$\\{x\_coord}(\|s)\K-\\{x\_coord}(\|p)$;\5 +$\\{y\_coord}(\|s)\K\\{y\_coord}(\|r)$;\6 +$\\{left\_v}(\|s)\K\\{half\_unit}$;\5 +$\\{left\_length}(\|s)\K\\{gamma}-\\{alpha}$;\6 +\&{end}\2\par +\U527.\fi + +\M529. One of the important invariants of the pen data structure is that +the points are distinct. We may need to correct the pen specification +in order to avoid this. (The result of \&{pencircle} will always be at +least one pixel wide and one pixel tall, although \&{makepen} is +capable of producing smaller pens.) + +\Y\P$\4\X529:Revise the values of $\alpha$, $\beta$, $\gamma$, if necessary, so +that degenerate lines of length zero will not be obtained\X\S$\6 +\&{if} $\\{beta}=0$ \1\&{then}\5 +$\\{beta}\K1$;\2\6 +\&{if} $\\{gamma}=0$ \1\&{then}\5 +$\\{gamma}\K1$;\2\6 +\&{if} $\\{gamma}\L\\{abs}(\\{alpha})$ \1\&{then}\6 +\&{if} $\\{alpha}>0$ \1\&{then}\5 +$\\{alpha}\K\\{gamma}-1$\6 +\4\&{else} $\\{alpha}\K1-\\{gamma}$\2\2\par +\U528.\fi + +\M530. If $a$ and $b$ are the semi-major and semi-minor axes, +the given ellipse rises highest above the $y$-axis at the point +$\bigl((a^2-b^2)\sin\theta\cos\theta/\rho\bigr)+i\rho$, where +$\rho=\sqrt{(a\sin\theta)^2+(b\cos\theta)^2}$. It reaches +furthest to the right of~the $x$-axis at the point +$\sigma+i(a^2-b^2)\sin\theta\cos\theta/\sigma$, where +$\sigma=\sqrt{(a\cos\theta)^2+(b\sin\theta)^2}$. + +\Y\P$\4\X530:Calculate integers $\alpha$, $\beta$, $\gamma$ for the vertex +coordinates\X\S$\6 +\&{if} $(\\{major\_axis}=\\{minor\_axis})\V(\\{theta}\mathbin{\&{mod}}\\{ninety% +\_deg}=0)$ \1\&{then}\6 +\&{begin} \37$\\{symmetric}\K\\{true}$;\5 +$\\{alpha}\K0$;\6 +\&{if} $\\{odd}(\\{theta}\mathbin{\&{div}}\\{ninety\_deg})$ \1\&{then}\6 +\&{begin} \37$\\{beta}\K\\{major\_axis}$;\5 +$\\{gamma}\K\\{minor\_axis}$;\5 +$\\{n\_sin}\K\\{fraction\_one}$;\5 +$\\{n\_cos}\K0$;\C{\\{n\_sin} and \\{n\_cos} are used later}\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{beta}\K\\{minor\_axis}$;\5 +$\\{gamma}\K\\{major\_axis}$;\6 +\&{end};\C{\\{n\_sin} and \\{n\_cos} aren't needed in this case}\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{symmetric}\K\\{false}$;\5 +$\\{n\_sin\_cos}(\\{theta})$;\C{set up $\\{n\_sin}=\sin\theta$ and $\\{n\_cos}=% +\cos\theta$}\6 +$\\{gamma}\K\\{take\_fraction}(\\{major\_axis},\39\\{n\_sin})$;\5 +$\\{delta}\K\\{take\_fraction}(\\{minor\_axis},\39\\{n\_cos})$;\5 +$\\{beta}\K\\{pyth\_add}(\\{gamma},\39\\{delta})$;\5 +$\\{alpha}\K\\{take\_fraction}(\\{take\_fraction}(\\{major\_axis},\39\\{make% +\_fraction}(\\{gamma},\39\\{beta})),\39\\{n\_cos})\30-\\{take\_fraction}(% +\\{take\_fraction}(\\{minor\_axis},\39\\{make\_fraction}(\\{delta},\39% +\\{beta})),\39\\{n\_sin})$;\5 +$\\{alpha}\K(\\{alpha}+\\{half\_unit})\mathbin{\&{div}}\\{unity}$;\5 +$\\{gamma}\K\\{pyth\_add}(\\{take\_fraction}(\\{major\_axis},\39\\{n\_cos}),\39% +\\{take\_fraction}(\\{minor\_axis},\39\\{n\_sin}))$;\6 +\&{end};\2\6 +$\\{beta}\K(\\{beta}+\\{half\_unit})\mathbin{\&{div}}\\{unity}$;\5 +$\\{gamma}\K(\\{gamma}+\\{half\_unit})\mathbin{\&{div}}\\{unity}$\par +\U528.\fi + +\M531. Now \|p, \|q, and \|r march through the list, always representing +three consecutive vertices and two consecutive slope directions. +When a new slope is interpolated, we back up slightly, until +further refinement is impossible; then we march forward again. +The somewhat magical operations performed in this part of the +algorithm are justified by the theory sketched earlier. +Complications arise only from the need to keep zero-length lines +out of the final data structure. + +\Y\P$\4\X531:Interpolate new vertices in the ellipse data structure until +improvement is impossible\X\S$\6 +\~ \1\&{loop}\ \&{begin} \37$\|u\K\\{right\_u}(\|p)+\\{right\_u}(\|q)$;\5 +$\|v\K\\{left\_v}(\|q)+\\{left\_v}(\|r)$;\5 +$\|c\K\\{right\_class}(\|p)+\\{right\_class}(\|q)$;\6 +\X533:Compute the distance \|d from class~0 to the edge of the ellipse in +direction $(\|u,\|v)$, times $\psqrt{u^2+v^2}$, rounded to the nearest integer% +\X;\6 +$\\{delta}\K\|c-\|d$;\C{we want to move \\{delta} steps back from the +intersection vertex~\|q}\6 +\&{if} $\\{delta}>0$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{delta}>\\{left\_length}(\|r)$ \1\&{then}\5 +$\\{delta}\K\\{left\_length}(\|r)$;\2\6 +\&{if} $\\{delta}\G\\{left\_length}(\|q)$ \1\&{then}\5 +\X534:Remove the line from \|p to \|q, and adjust vertex~\|q to introduce a new +line\X\6 +\4\&{else} \X535:Insert a new line for direction $(\|u,\|v)$ between \|p and~% +\|q\X;\2\6 +\&{end}\6 +\4\&{else} $\|p\K\|q$;\2\6 +\X532:Move to the next remaining triple $(\|p,\|q,\|r)$, removing and skipping +past zero-length lines that might be present; \&{goto} \\{done} if all triples +have been processed\X;\6 +\&{end};\2\6 +\4\\{done}: \37\par +\U527.\fi + +\M532. The appearance of a zero-length line means that we should advance \|p +past it. We must not try to straddle a missing direction, because the +algorithm works only on consecutive pairs of directions. + +\Y\P$\4\X532:Move to the next remaining triple $(\|p,\|q,\|r)$, removing and +skipping past zero-length lines that might be present; \&{goto} \\{done} if all +triples have been processed\X\S$\6 +\~ \1\&{loop}\ \&{begin} \37$\|q\K\\{link}(\|p)$;\6 +\&{if} $\|q=\\{null}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +\&{if} $\\{left\_length}(\|q)=0$ \1\&{then}\6 +\&{begin} \37$\\{link}(\|p)\K\\{link}(\|q)$;\5 +$\\{right\_class}(\|p)\K\\{right\_class}(\|q)$;\5 +$\\{right\_u}(\|p)\K\\{right\_u}(\|q)$;\5 +$\\{free\_node}(\|q,\39\\{knot\_node\_size})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|r\K\\{link}(\|q)$;\6 +\&{if} $\|r=\\{null}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +\&{if} $\\{left\_length}(\|r)=0$ \1\&{then}\6 +\&{begin} \37$\\{link}(\|p)\K\|r$;\5 +$\\{free\_node}(\|q,\39\\{knot\_node\_size})$;\5 +$\|p\K\|r$;\6 +\&{end}\6 +\4\&{else} \&{goto} \37\\{found};\2\6 +\&{end};\2\6 +\&{end};\2\6 +\4\\{found}: \37\par +\U531.\fi + +\M533. The `\&{div} 8' near the end of this step comes from +the fact that \\{delta} is scaled by~$2^{15}$ and $d$~by~$2^{16}$, +while \\{take\_fraction} removes a scale factor of~$2^{28}$. +We also make sure that $d\G\max(\vert u\vert,\vert v\vert)$, so that +the pen will always include a circular pen of diameter~1 as a subset; +then it won't be possible to get disconnected path envelopes. + +\Y\P$\4\X533:Compute the distance \|d from class~0 to the edge of the ellipse +in direction $(\|u,\|v)$, times $\psqrt{u^2+v^2}$, rounded to the nearest +integer\X\S$\6 +$\\{delta}\K\\{pyth\_add}(\|u,\39\|v)$;\6 +\&{if} $\\{major\_axis}=\\{minor\_axis}$ \1\&{then}\5 +$\|d\K\\{major\_axis}$\C{circles are easy}\6 +\4\&{else} \&{begin} \37\&{if} $\\{theta}=0$ \1\&{then}\6 +\&{begin} \37$\\{alpha}\K\|u$;\5 +$\\{beta}\K\|v$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{alpha}\K\\{take\_fraction}(\|u,\39\\{n\_cos})+% +\\{take\_fraction}(\|v,\39\\{n\_sin})$;\5 +$\\{beta}\K\\{take\_fraction}(\|v,\39\\{n\_cos})-\\{take\_fraction}(\|u,\39\\{n% +\_sin})$;\6 +\&{end};\2\6 +$\\{alpha}\K\\{make\_fraction}(\\{alpha},\39\\{delta})$;\5 +$\\{beta}\K\\{make\_fraction}(\\{beta},\39\\{delta})$;\5 +$\|d\K\\{pyth\_add}(\\{take\_fraction}(\\{major\_axis},\39\\{alpha}),\39\\{take% +\_fraction}(\\{minor\_axis},\39\\{beta}))$;\6 +\&{end};\2\6 +$\\{alpha}\K\\{abs}(\|u)$;\5 +$\\{beta}\K\\{abs}(\|v)$;\6 +\&{if} $\\{alpha}<\\{beta}$ \1\&{then}\6 +\&{begin} \37$\\{alpha}\K\\{abs}(\|v)$;\5 +$\\{beta}\K\\{abs}(\|u)$;\6 +\&{end};\C{now $\alpha=\max(\vert u\vert,\vert v\vert)$, $\beta=\min(% +\vert u\vert,\vert v\vert)$}\2\6 +\&{if} $\\{internal}[\\{fillin}]\I0$ \1\&{then}\5 +$\|d\K\|d-\\{take\_fraction}(\\{internal}[\\{fillin}],\39\\{make\_fraction}(% +\\{beta}+\\{beta},\39\\{delta}))$;\2\6 +$\|d\K\\{take\_fraction}((\|d+4)\mathbin{\&{div}}8,\39\\{delta})$;\5 +$\\{alpha}\K\\{alpha}\mathbin{\&{div}}\\{half\_unit}$;\6 +\&{if} $\|d<\\{alpha}$ \1\&{then}\5 +$\|d\K\\{alpha}$\2\par +\U531.\fi + +\M534. At this point there's a line of length $\L\\{delta}$ from vertex~\|p +to vertex~\|q, orthogonal to direction $\bigl($$\\{right\_u}(\|p),\\{left\_v}(% +\|q)$$\bigr)$; +and there's a line of length $\G\\{delta}$ from vertex~\|q to +to vertex~\|r, orthogonal to direction $\bigl($$\\{right\_u}(\|q),\\{left\_v}(% +\|r)$$\bigr)$. +The best line to direction $(u,v)$ should replace the line from +\|p to~\|q; this new line will have the same length as the old. + +\Y\P$\4\X534:Remove the line from \|p to \|q, and adjust vertex~\|q to +introduce a new line\X\S$\6 +\&{begin} \37$\\{delta}\K\\{left\_length}(\|q)$;\6 +$\\{right\_class}(\|p)\K\|c-\\{delta}$;\5 +$\\{right\_u}(\|p)\K\|u$;\5 +$\\{left\_v}(\|q)\K\|v$;\6 +$\\{x\_coord}(\|q)\K\\{x\_coord}(\|q)-\\{delta}\ast\\{left\_v}(\|r)$;\5 +$\\{y\_coord}(\|q)\K\\{y\_coord}(\|q)+\\{delta}\ast\\{right\_u}(\|q)$;\6 +$\\{left\_length}(\|r)\K\\{left\_length}(\|r)-\\{delta}$;\6 +\&{end}\par +\U531.\fi + +\M535. Here is the main case, now that we have dealt with the exception: +We insert a new line of length \\{delta} for direction $(\|u,\|v)$, decreasing +each of the adjacent lines by \\{delta} steps. + +\Y\P$\4\X535:Insert a new line for direction $(\|u,\|v)$ between \|p and~\|q\X% +\S$\6 +\&{begin} \37$\|s\K\\{get\_node}(\\{knot\_node\_size})$;\5 +$\\{link}(\|p)\K\|s$;\5 +$\\{link}(\|s)\K\|q$;\6 +$\\{x\_coord}(\|s)\K\\{x\_coord}(\|q)+\\{delta}\ast\\{left\_v}(\|q)$;\5 +$\\{y\_coord}(\|s)\K\\{y\_coord}(\|q)-\\{delta}\ast\\{right\_u}(\|p)$;\6 +$\\{x\_coord}(\|q)\K\\{x\_coord}(\|q)-\\{delta}\ast\\{left\_v}(\|r)$;\5 +$\\{y\_coord}(\|q)\K\\{y\_coord}(\|q)+\\{delta}\ast\\{right\_u}(\|q)$;\6 +$\\{left\_v}(\|s)\K\\{left\_v}(\|q)$;\5 +$\\{right\_u}(\|s)\K\|u$;\5 +$\\{left\_v}(\|q)\K\|v$;\6 +$\\{right\_class}(\|s)\K\|c-\\{delta}$;\6 +$\\{left\_length}(\|s)\K\\{left\_length}(\|q)-\\{delta}$;\5 +$\\{left\_length}(\|q)\K\\{delta}$;\5 +$\\{left\_length}(\|r)\K\\{left\_length}(\|r)-\\{delta}$;\6 +\&{end}\par +\U531.\fi + +\M536. Only the coordinates need to be copied, not the class numbers and other +stuff. + +\Y\P$\4\X536:Complete the half ellipse by reflecting the quarter already +computed\X\S$\6 +\&{begin} \37$\|s\K\\{null}$;\5 +$\|q\K\|h$;\6 +\~ \1\&{loop}\ \&{begin} \37$\|r\K\\{get\_node}(\\{knot\_node\_size})$;\5 +$\\{link}(\|r)\K\|s$;\5 +$\|s\K\|r$;\6 +$\\{x\_coord}(\|s)\K\\{x\_coord}(\|q)$;\5 +$\\{y\_coord}(\|s)\K-\\{y\_coord}(\|q)$;\6 +\&{if} $\|q=\|p$ \1\&{then}\5 +\&{goto} \37\\{done1};\2\6 +$\|q\K\\{link}(\|q)$;\6 +\&{if} $\\{y\_coord}(\|q)=0$ \1\&{then}\5 +\&{goto} \37\\{done1};\2\6 +\&{end};\2\6 +\4\\{done1}: \37$\\{link}(\|p)\K\|s$;\5 +$\\{beta}\K-\\{y\_coord}(\|h)$;\6 +\&{while} $\\{y\_coord}(\|p)\I\\{beta}$ \1\&{do}\5 +$\|p\K\\{link}(\|p)$;\2\6 +$\|q\K\\{link}(\|p)$;\6 +\&{end}\par +\U527.\fi + +\M537. Now we use a somewhat tricky fact: The pointer \|q will be null if and +only if the line for the final direction $(0,1)$ has been removed. If +that line still survives, it should be combined with a possibly +surviving line in the initial direction $(0,-1)$. + +\Y\P$\4\X537:Complete the ellipse by copying the negative of the half already +computed\X\S$\6 +\&{if} $\|q\I\\{null}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{right\_u}(\|h)=0$ \1\&{then}\6 +\&{begin} \37$\|p\K\|h$;\5 +$\|h\K\\{link}(\|h)$;\5 +$\\{free\_node}(\|p,\39\\{knot\_node\_size})$;\6 +$\\{x\_coord}(\|q)\K-\\{x\_coord}(\|h)$;\6 +\&{end};\2\6 +$\|p\K\|q$;\6 +\&{end}\6 +\4\&{else} $\|q\K\|p$;\2\6 +$\|r\K\\{link}(\|h)$;\C{now $\|p=\|q$, $\\{x\_coord}(\|p)=-\\{x\_coord}(\|h)$, +$\\{y\_coord}(\|p)=-\\{y\_coord}(\|h)$}\6 +\1\&{repeat} \37$\|s\K\\{get\_node}(\\{knot\_node\_size})$;\5 +$\\{link}(\|p)\K\|s$;\5 +$\|p\K\|s$;\6 +$\\{x\_coord}(\|p)\K-\\{x\_coord}(\|r)$;\5 +$\\{y\_coord}(\|p)\K-\\{y\_coord}(\|r)$;\5 +$\|r\K\\{link}(\|r)$;\6 +\4\&{until}\5 +$\|r=\|q$;\2\6 +$\\{link}(\|p)\K\|h$\par +\U527.\fi + +\N538. \[26] Direction and intersection times. +A path of length $n$ is defined parametrically by functions $x(t)$ and +$y(t)$, for $0\L\|t\L\|n$; we can regard $t$ as the ``time'' at which the path +reaches the point $\bigl(x(t),y(t)\bigr)$. In this section of the program +we shall consider operations that determine special times associated with +given paths: the first time that a path travels in a given direction, and +a pair of times at which two paths cross each other. + +\fi + +\M539. Let's start with the easier task. The function \\{find\_direction\_time} +is +given a direction $(\|x,\|y)$ and a path starting at~\|h. If the path never +travels in direction $(\|x,\|y)$, the direction time will be~$-1$; otherwise +it will be nonnegative. + +Certain anomalous cases can arise: If $(\|x,\|y)=(0,0)$, so that the given +direction is undefined, the direction time will be~0. If $\bigl(x'(t), +y'(t)\bigr)=(0,0)$, so that the path direction is undefined, it will be +assumed to match any given direction at time~\|t. + +The routine solves this problem in nondegenerate cases by rotating the path +and the given direction so that $(\|x,\|y)=(1,0)$; i.e., the main task will be +to find when a given path first travels ``due east.'' + +\Y\P\4\&{function}\1\ \37$\\{find\_direction\_time}(\|x,\39\|y:\\{scaled};\,% +\35\|h:\\{pointer})$: \37\\{scaled};\6 +\4\&{label} \37$\\{exit},\39\\{found},\39\\{not\_found},\39\\{done}$;\6 +\4\&{var} \37\\{max}: \37\\{scaled};\C{$\max\bigl(\vert x\vert,\vert y\vert% +\bigr)$}\6 +$\|p,\39\|q$: \37\\{pointer};\C{for list traversal}\6 +\|n: \37\\{scaled};\C{the direction time at knot \|p}\6 +\\{tt}: \37\\{scaled};\C{the direction time within a cubic}\6 +\X542:Other local variables for \\{find\_direction\_time}\X\2\6 +\&{begin} \37\X540:Normalize the given direction for better accuracy; but % +\&{return} with zero result if it's zero\X;\6 +$\|n\K0$;\5 +$\|p\K\|h$;\6 +\~ \1\&{loop}\ \&{begin} \37\&{if} $\\{right\_type}(\|p)=\\{endpoint}$ \1% +\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +$\|q\K\\{link}(\|p)$;\5 +\X541:Rotate the cubic between \|p and \|q; then \&{goto} \\{found} if the +rotated cubic travels due east at some time \\{tt}; but \&{goto} \\{not\_found} +if an entire cyclic path has been traversed\X;\6 +$\|p\K\|q$;\5 +$\|n\K\|n+\\{unity}$;\6 +\&{end};\2\6 +\4\\{not\_found}: \37$\\{find\_direction\_time}\K-\\{unity}$;\5 +\&{return};\6 +\4\\{found}: \37$\\{find\_direction\_time}\K\|n+\\{tt}$;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M540. \P$\X540:Normalize the given direction for better accuracy; but % +\&{return} with zero result if it's zero\X\S$\6 +\&{if} $\\{abs}(\|x)<\\{abs}(\|y)$ \1\&{then}\6 +\&{begin} \37$\|x\K\\{make\_fraction}(\|x,\39\\{abs}(\|y))$;\6 +\&{if} $\|y>0$ \1\&{then}\5 +$\|y\K\\{fraction\_one}$\ \&{else} $\|y\K-\\{fraction\_one}$;\2\6 +\&{end}\6 +\4\&{else} \&{if} $\|x=0$ \1\&{then}\6 +\&{begin} \37$\\{find\_direction\_time}\K0$;\5 +\&{return};\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|y\K\\{make\_fraction}(\|y,\39\\{abs}(\|x))$;\6 +\&{if} $\|x>0$ \1\&{then}\5 +$\|x\K\\{fraction\_one}$\ \&{else} $\|x\K-\\{fraction\_one}$;\2\6 +\&{end}\2\2\par +\U539.\fi + +\M541. Since we're interested in the tangent directions, we work with the +derivative $${\textstyle1\over3}B'(x_0,x_1,x_2,x_3;t)= +B(x_1-x_0,x_2-x_1,x_3-x_2;t)$$ instead of +$B(x_0,x_1,x_2,x_3;t)$ itself. The derived coefficients are also scaled up +in order to achieve better accuracy. + +The given path may turn abruptly at a knot, and it might pass the critical +tangent direction at such a time. Therefore we remember the direction \\{phi} +in which the previous rotated cubic was traveling. (The value of \\{phi} will +be +undefined on the first cubic, i.e., when $\|n=0$.) + +\Y\P$\4\X541:Rotate the cubic between \|p and \|q; then \&{goto} \\{found} if +the rotated cubic travels due east at some time \\{tt}; but \&{goto} \\{not% +\_found} if an entire cyclic path has been traversed\X\S$\6 +$\\{tt}\K0$;\5 +\X543:Set local variables $\\{x1},\\{x2},\\{x3}$ and $\\{y1},\\{y2},\\{y3}$ to +multiples of the control points of the rotated derivatives\X;\6 +\&{if} $\\{y1}=0$ \1\&{then}\6 +\&{if} $\\{x1}\G0$ \1\&{then}\5 +\&{goto} \37\\{found};\2\2\6 +\&{if} $\|n>0$ \1\&{then}\6 +\&{begin} \37\X544:Exit to \\{found} if an eastward direction occurs at knot % +\|p\X;\6 +\&{if} $\|p=\|h$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +\&{end};\2\6 +\&{if} $(\\{x3}\I0)\V(\\{y3}\I0)$ \1\&{then}\5 +$\\{phi}\K\\{n\_arg}(\\{x3},\39\\{y3})$;\2\6 +\X546:Exit to \\{found} if the curve whose derivatives are specified by $% +\\{x1},\\{x2},\\{x3},\\{y1},\\{y2},\\{y3}$ travels eastward at some time~\\{tt}% +\X\par +\U539.\fi + +\M542. \P$\X542:Other local variables for \\{find\_direction\_time}\X\S$\6 +\4$\\{x1},\39\\{x2},\39\\{x3},\39\\{y1},\39\\{y2},\39\\{y3}$: \37\\{scaled};% +\C{multiples of rotated derivatives}\6 +\4$\\{theta},\39\\{phi}$: \37\\{angle};\C{angles of exit and entry at a knot}\6 +\4\|t: \37\\{fraction};\C{temp storage}\par +\U539.\fi + +\M543. \P$\X543:Set local variables $\\{x1},\\{x2},\\{x3}$ and $\\{y1},\\{y2},% +\\{y3}$ to multiples of the control points of the rotated derivatives\X\S$\6 +$\\{x1}\K\\{right\_x}(\|p)-\\{x\_coord}(\|p)$;\5 +$\\{x2}\K\\{left\_x}(\|q)-\\{right\_x}(\|p)$;\5 +$\\{x3}\K\\{x\_coord}(\|q)-\\{left\_x}(\|q)$;\6 +$\\{y1}\K\\{right\_y}(\|p)-\\{y\_coord}(\|p)$;\5 +$\\{y2}\K\\{left\_y}(\|q)-\\{right\_y}(\|p)$;\5 +$\\{y3}\K\\{y\_coord}(\|q)-\\{left\_y}(\|q)$;\6 +$\\{max}\K\\{abs}(\\{x1})$;\6 +\&{if} $\\{abs}(\\{x2})>\\{max}$ \1\&{then}\5 +$\\{max}\K\\{abs}(\\{x2})$;\2\6 +\&{if} $\\{abs}(\\{x3})>\\{max}$ \1\&{then}\5 +$\\{max}\K\\{abs}(\\{x3})$;\2\6 +\&{if} $\\{abs}(\\{y1})>\\{max}$ \1\&{then}\5 +$\\{max}\K\\{abs}(\\{y1})$;\2\6 +\&{if} $\\{abs}(\\{y2})>\\{max}$ \1\&{then}\5 +$\\{max}\K\\{abs}(\\{y2})$;\2\6 +\&{if} $\\{abs}(\\{y3})>\\{max}$ \1\&{then}\5 +$\\{max}\K\\{abs}(\\{y3})$;\2\6 +\&{if} $\\{max}=0$ \1\&{then}\5 +\&{goto} \37\\{found};\2\6 +\&{while} $\\{max}<\\{fraction\_half}$ \1\&{do}\6 +\&{begin} \37$\\{double}(\\{max})$;\5 +$\\{double}(\\{x1})$;\5 +$\\{double}(\\{x2})$;\5 +$\\{double}(\\{x3})$;\5 +$\\{double}(\\{y1})$;\5 +$\\{double}(\\{y2})$;\5 +$\\{double}(\\{y3})$;\6 +\&{end};\2\6 +$\|t\K\\{x1}$;\5 +$\\{x1}\K\\{take\_fraction}(\\{x1},\39\|x)+\\{take\_fraction}(\\{y1},\39\|y)$;\5 +$\\{y1}\K\\{take\_fraction}(\\{y1},\39\|x)-\\{take\_fraction}(\|t,\39\|y)$;\6 +$\|t\K\\{x2}$;\5 +$\\{x2}\K\\{take\_fraction}(\\{x2},\39\|x)+\\{take\_fraction}(\\{y2},\39\|y)$;\5 +$\\{y2}\K\\{take\_fraction}(\\{y2},\39\|x)-\\{take\_fraction}(\|t,\39\|y)$;\6 +$\|t\K\\{x3}$;\5 +$\\{x3}\K\\{take\_fraction}(\\{x3},\39\|x)+\\{take\_fraction}(\\{y3},\39\|y)$;\5 +$\\{y3}\K\\{take\_fraction}(\\{y3},\39\|x)-\\{take\_fraction}(\|t,\39\|y)$\par +\U541.\fi + +\M544. \P$\X544:Exit to \\{found} if an eastward direction occurs at knot \|p\X% +\S$\6 +$\\{theta}\K\\{n\_arg}(\\{x1},\39\\{y1})$;\6 +\&{if} $\\{theta}\G0$ \1\&{then}\6 +\&{if} $\\{phi}\L0$ \1\&{then}\6 +\&{if} $\\{phi}\G\\{theta}-\\{one\_eighty\_deg}$ \1\&{then}\5 +\&{goto} \37\\{found};\2\2\2\6 +\&{if} $\\{theta}\L0$ \1\&{then}\6 +\&{if} $\\{phi}\G0$ \1\&{then}\6 +\&{if} $\\{phi}\L\\{theta}+\\{one\_eighty\_deg}$ \1\&{then}\5 +\&{goto} \37\\{found}\2\2\2\par +\U541.\fi + +\M545. In this step we want to use the \\{crossing\_point} routine to find the +roots of the quadratic equation $B(y_1,y_2,y_3;t)=0$. +Several complications arise: If the quadratic equation has a double root, +the curve never crosses zero, and \\{crossing\_point} will find nothing; +this case occurs iff $y_1y_3=y_2^2$ and $y_1y_2<0$. If the quadratic +equation has simple roots, or only one root, we may have to negate it +so that $B(y_1,y_2,y_3;t)$ crosses from positive to negative at its first root. +And finally, we need to do special things if $B(y_1,y_2,y_3;t)$ is +identically zero. + +\fi + +\M546. \P$\X546:Exit to \\{found} if the curve whose derivatives are specified +by $\\{x1},\\{x2},\\{x3},\\{y1},\\{y2},\\{y3}$ travels eastward at some time~% +\\{tt}\X\S$\6 +\&{if} $\\{x1}<0$ \1\&{then}\6 +\&{if} $\\{x2}<0$ \1\&{then}\6 +\&{if} $\\{x3}<0$ \1\&{then}\5 +\&{goto} \37\\{done};\2\2\2\6 +\&{if} $\\{ab\_vs\_cd}(\\{y1},\39\\{y3},\39\\{y2},\39\\{y2})=0$ \1\&{then}\5 +\X548:Handle the test for eastward directions when $y_1y_3=y_2^2$; either % +\&{goto} \\{found} or \&{goto} \\{done}\X;\2\6 +\&{if} $\\{y1}\L0$ \1\&{then}\6 +\&{if} $\\{y1}<0$ \1\&{then}\6 +\&{begin} \37$\\{y1}\K-\\{y1}$;\5 +$\\{y2}\K-\\{y2}$;\5 +$\\{y3}\K-\\{y3}$;\6 +\&{end}\6 +\4\&{else} \&{if} $\\{y2}>0$ \1\&{then}\6 +\&{begin} \37$\\{y2}\K-\\{y2}$;\5 +$\\{y3}\K-\\{y3}$;\6 +\&{end};\2\2\2\6 +\X547:Check the places where $B(y_1,y_2,y_3;t)=0$ to see if $B(x_1,x_2,x_3;t)% +\ge0$\X;\6 +\4\\{done}: \37\par +\U541.\fi + +\M547. The quadratic polynomial $B(y_1,y_2,y_3;t)$ begins $\G0$ and has at most +two roots, because we know that it isn't identically zero. + +It must be admitted that the \\{crossing\_point} routine is not perfectly +accurate; +rounding errors might cause it to find a root when $y_1y_3>y_2^2$, or to +miss the roots when $y_1y_3<y_2^2$. The rotation process is itself +subject to rounding errors. Yet this code optimistically tries to +do the right thing. + +\Y\P\D \37$\\{we\_found\_it}\S$\1\6 +\&{begin} \37$\\{tt}\K(\|t+\O{4000})\mathbin{\&{div}}\O{10000}$;\5 +\&{goto} \37\\{found};\6 +\&{end}\2\par +\Y\P$\4\X547:Check the places where $B(y_1,y_2,y_3;t)=0$ to see if +$B(x_1,x_2,x_3;t)\ge0$\X\S$\6 +$\|t\K\\{crossing\_point}(\\{y1},\39\\{y2},\39\\{y3})$;\6 +\&{if} $\|t>\\{fraction\_one}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\\{y2}\K\\{t\_of\_the\_way}(\\{y2})(\\{y3})$;\5 +$\\{x1}\K\\{t\_of\_the\_way}(\\{x1})(\\{x2})$;\5 +$\\{x2}\K\\{t\_of\_the\_way}(\\{x2})(\\{x3})$;\5 +$\\{x1}\K\\{t\_of\_the\_way}(\\{x1})(\\{x2})$;\6 +\&{if} $\\{x1}\G0$ \1\&{then}\5 +\\{we\_found\_it};\2\6 +\&{if} $\\{y2}>0$ \1\&{then}\5 +$\\{y2}\K0$;\2\6 +$\\{tt}\K\|t$;\5 +$\|t\K\\{crossing\_point}(0,\39-\\{y2},\39-\\{y3})$;\6 +\&{if} $\|t>\\{fraction\_one}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\\{x1}\K\\{t\_of\_the\_way}(\\{x1})(\\{x2})$;\5 +$\\{x2}\K\\{t\_of\_the\_way}(\\{x2})(\\{x3})$;\6 +\&{if} $\\{t\_of\_the\_way}(\\{x1})(\\{x2})\G0$ \1\&{then}\6 +\&{begin} \37$\|t\K\\{t\_of\_the\_way}(\\{tt})(\\{fraction\_one})$;\5 +\\{we\_found\_it};\6 +\&{end}\2\par +\U546.\fi + +\M548. \P$\X548:Handle the test for eastward directions when $y_1y_3=y_2^2$; +either \&{goto} \\{found} or \&{goto} \\{done}\X\S$\6 +\&{begin} \37\&{if} $\\{ab\_vs\_cd}(\\{y1},\39\\{y2},\390,\390)<0$ \1\&{then}\6 +\&{begin} \37$\|t\K\\{make\_fraction}(\\{y1},\39\\{y1}-\\{y2})$;\5 +$\\{x1}\K\\{t\_of\_the\_way}(\\{x1})(\\{x2})$;\5 +$\\{x2}\K\\{t\_of\_the\_way}(\\{x2})(\\{x3})$;\6 +\&{if} $\\{t\_of\_the\_way}(\\{x1})(\\{x2})\G0$ \1\&{then}\5 +\\{we\_found\_it};\2\6 +\&{end}\6 +\4\&{else} \&{if} $\\{y3}=0$ \1\&{then}\6 +\&{if} $\\{y1}=0$ \1\&{then}\5 +\X549:Exit to \\{found} if the derivative $B(x_1,x_2,x_3;t)$ becomes $\G0$\X\6 +\4\&{else} \&{if} $\\{x3}\G0$ \1\&{then}\6 +\&{begin} \37$\\{tt}\K\\{unity}$;\5 +\&{goto} \37\\{found};\6 +\&{end};\2\2\2\2\6 +\&{goto} \37\\{done};\6 +\&{end}\par +\U546.\fi + +\M549. At this point we know that the derivative of $\|y(\|t)$ is identically +zero, +and that $\\{x1}<0$; but either $\\{x2}\G0$ or $\\{x3}\G0$, so there's some +hope of +traveling east. + +\Y\P$\4\X549:Exit to \\{found} if the derivative $B(x_1,x_2,x_3;t)$ becomes $% +\G0$\X\S$\6 +\&{begin} \37$\|t\K\\{crossing\_point}(-\\{x1},\39-\\{x2},\39-\\{x3})$;\6 +\&{if} $\|t\L\\{fraction\_one}$ \1\&{then}\5 +\\{we\_found\_it};\2\6 +\&{if} $\\{ab\_vs\_cd}(\\{x1},\39\\{x3},\39\\{x2},\39\\{x2})\L0$ \1\&{then}\6 +\&{begin} \37$\|t\K\\{make\_fraction}(\\{x1},\39\\{x1}-\\{x2})$;\5 +\\{we\_found\_it};\6 +\&{end};\2\6 +\&{end}\par +\U548.\fi + +\M550. The intersection of two cubics can be found by an interesting variant +of the general bisection scheme described in the introduction to \\{make% +\_moves}.\ +Given $w(t)=B(w_0,w_1,w_2,w_3;t)$ and $z(t)=B(z_0,z_1,z_2,z_3;t)$, +we wish to find a pair of times $(t_1,t_2)$ such that $w(t_1)=z(t_2)$, +if an intersection exists. First we find the smallest rectangle that +encloses the points $\{w_0,w_1,w_2,w_3\}$ and check that it overlaps +the smallest rectangle that encloses +$\{z_0,z_1,z_2,z_3\}$; if not, the cubics certainly don't intersect. +But if the rectangles do overlap, we bisect the intervals, getting +new cubics $w'$ and~$w''$, $z'$~and~$z''$; the intersection routine first +tries for an intersection between $w'$ and~$z'$, then (if unsuccessful) +between $w'$ and~$z''$, then (if still unsuccessful) between $w''$ and~$z'$, +finally (if thrice unsuccessful) between $w''$ and~$z''$. After $l$~successful +levels of bisection we will have determined the intersection times $t_1$ +and~$t_2$ to $l$~bits of accuracy. + +\def\submin{_{\rm min}} \def\submax{_{\rm max}} +As before, it is better to work with the numbers $W_k=2^l(w_k-w_{k-1})$ +and $Z_k=2^l(z_k-z_{k-1})$ rather than the coefficients $w_k$ and $z_k$ +themselves. We also need one other quantity, $\Delta=2^l(w_0-z_0)$, +to determine when the enclosing rectangles overlap. Here's why: +The $x$~coordinates of~$w(t)$ are between $u\submin$ and $u\submax$, +and the $x$~coordinates of~$z(t)$ are between $x\submin$ and $x\submax$, +if we write $w_k=(u_k,v_k)$ and $z_k=(x_k,y_k)$ and $u\submin= +\min(u_0,u_1,u_2,u_3)$, etc. These intervals of $x$~coordinates +overlap if and only if $u\submin\L x\submax$ and +$x\submin\L u\submax$. Letting +$$U\submin=\min(0,U_1,U_1+U_2,U_1+U_2+U_3),\; +U\submax=\max(0,U_1,U_1+U_2,U_1+U_2+U_3),$$ +we have $u\submin=2^lu_0+U\submin$, etc.; the condition for overlap +reduces to +$$X\submin-U\submax\L 2^l(u_0-x_0)\L X\submax-U\submin.$$ +Thus we want to maintain the quantity $2^l(u_0-x_0)$; similarly, +the quantity $2^l(v_0-y_0)$ accounts for the $y$~coordinates. The +coordinates of $\Delta=2^l(w_0-z_0)$ must stay bounded as $l$ increases, +because of the overlap condition; i.e., we know that $X\submin$, +$X\submax$, and their relatives are bounded, hence $X\submax- +U\submin$ and $X\submin-U\submax$ are bounded. + +\fi + +\M551. Incidentally, if the given cubics intersect more than once, the process +just sketched will not necessarily find the lexicographically smallest pair +$(t_1,t_2)$. The solution actually obtained will be smallest in ``shuffled +order''; i.e., if $t_1=(.a_1a_2\ldots a_{16})_2$ and +$t_2=(.b_1b_2\ldots b_{16})_2$, then we will minimize +$a_1b_1a_2b_2\ldots a_{16}b_{16}$, not +$a_1a_2\ldots a_{16}b_1b_2\ldots b_{16}$. +Shuffled order agrees with lexicographic order if all pairs of solutions +$(t_1,t_2)$ and $(t_1',t_2')$ have the property that $t_1<t_1'$ iff +$t_2<t_2'$; but in general, lexicographic order can be quite different, +and the bisection algorithm would be substantially less efficient if it were +constrained by lexicographic order. + +For example, suppose that an overlap has been found for $l=3$ and +$(t_1,t_2)= (.101,.011)$ in binary, but that no overlap is produced by +either of the alternatives $(.1010,.0110)$, $(.1010,.0111)$ at level~4. +Then there is probably an intersection in one of the subintervals +$(.1011,.011x)$; but lexicographic order would require us to explore +$(.1010,.1xxx)$ and $(.1011,.00xx)$ and $(.1011,.010x)$ first. We wouldn't +want to store all of the subdivision data for the second path, so the +subdivisions would have to be regenerated many times. Such inefficiencies +would be associated with every `1' in the binary representation of~$t_1$. + +\fi + +\M552. The subdivision process introduces rounding errors, hence we need to +make a more liberal test for overlap. It is not hard to show that the +computed values of $U_i$ differ from the truth by at most~$l$, on +level~$l$, hence $U\submin$ and $U\submax$ will be at most $3l$ in error. +If $\beta$ is an upper bound on the absolute error in the computed +components of $\Delta=(\\{delx},\\{dely})$ on level~$l$, we will replace +the test `$X\submin-U\submax\L\\{delx}$' by the more liberal test +`$X\submin-U\submax\L\\{delx}+\\{tol}$', where $\\{tol}=6l+\beta$. + +More accuracy is obtained if we try the algorithm first with $\\{tol}=0$; +the more liberal tolerance is used only if an exact approach fails. +It is convenient to do this double-take by letting `3' in the preceding +paragraph be a parameter, which is first 0, then 3. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{tol\_step}: \37$0\to6$;\C{either 0 or 3, usually}\par +\fi + +\M553. We shall use an explicit stack to implement the recursive bisection +method described above. In fact, the \\{bisect\_stack} array is available for +this purpose. It will contain numerous 5-word packets like +$(U_1,U_2,U_3,U\submin,U\submax)$, as well as 20-word packets comprising +the 5-word packets for $U$, $V$, $X$, and~$Y$. + +The following macros define the allocation of stack positions to +the quantities needed for bisection-intersection. + +\Y\P\D \37$\\{stack\_1}(\#)\S\\{bisect\_stack}[\#]$\C{$U_1$, $V_1$, $X_1$, or +$Y_1$}\par +\P\D \37$\\{stack\_2}(\#)\S\\{bisect\_stack}[\#+1]$\C{$U_2$, $V_2$, $X_2$, or +$Y_2$}\par +\P\D \37$\\{stack\_3}(\#)\S\\{bisect\_stack}[\#+2]$\C{$U_3$, $V_3$, $X_3$, or +$Y_3$}\par +\P\D \37$\\{stack\_min}(\#)\S\\{bisect\_stack}[\#+3]$\C{$U\submin$, $V\submin$, +$X\submin$, or $Y\submin$}\par +\P\D \37$\\{stack\_max}(\#)\S\\{bisect\_stack}[\#+4]$\C{$U\submax$, $V\submax$, +$X\submax$, or $Y\submax$}\par +\P\D \37$\\{int\_packets}=20$\C{number of words to represent $U_k$, $V_k$, +$X_k$, and $Y_k$}\Y\par +\P\D \37$\\{u\_packet}(\#)\S\#-5$\par +\P\D \37$\\{v\_packet}(\#)\S\#-10$\par +\P\D \37$\\{x\_packet}(\#)\S\#-15$\par +\P\D \37$\\{y\_packet}(\#)\S\#-20$\par +\P\D \37$\\{l\_packets}\S\\{bisect\_ptr}-\\{int\_packets}$\par +\P\D \37$\\{r\_packets}\S\\{bisect\_ptr}$\par +\P\D \37$\\{ul\_packet}\S\\{u\_packet}(\\{l\_packets})$\C{base of $U'_k$ +variables}\par +\P\D \37$\\{vl\_packet}\S\\{v\_packet}(\\{l\_packets})$\C{base of $V'_k$ +variables}\par +\P\D \37$\\{xl\_packet}\S\\{x\_packet}(\\{l\_packets})$\C{base of $X'_k$ +variables}\par +\P\D \37$\\{yl\_packet}\S\\{y\_packet}(\\{l\_packets})$\C{base of $Y'_k$ +variables}\par +\P\D \37$\\{ur\_packet}\S\\{u\_packet}(\\{r\_packets})$\C{base of $U''_k$ +variables}\par +\P\D \37$\\{vr\_packet}\S\\{v\_packet}(\\{r\_packets})$\C{base of $V''_k$ +variables}\par +\P\D \37$\\{xr\_packet}\S\\{x\_packet}(\\{r\_packets})$\C{base of $X''_k$ +variables}\par +\P\D \37$\\{yr\_packet}\S\\{y\_packet}(\\{r\_packets})$\C{base of $Y''_k$ +variables}\Y\par +\P\D \37$\\{u1l}\S\\{stack\_1}(\\{ul\_packet})$\C{$U'_1$}\par +\P\D \37$\\{u2l}\S\\{stack\_2}(\\{ul\_packet})$\C{$U'_2$}\par +\P\D \37$\\{u3l}\S\\{stack\_3}(\\{ul\_packet})$\C{$U'_3$}\par +\P\D \37$\\{v1l}\S\\{stack\_1}(\\{vl\_packet})$\C{$V'_1$}\par +\P\D \37$\\{v2l}\S\\{stack\_2}(\\{vl\_packet})$\C{$V'_2$}\par +\P\D \37$\\{v3l}\S\\{stack\_3}(\\{vl\_packet})$\C{$V'_3$}\par +\P\D \37$\\{x1l}\S\\{stack\_1}(\\{xl\_packet})$\C{$X'_1$}\par +\P\D \37$\\{x2l}\S\\{stack\_2}(\\{xl\_packet})$\C{$X'_2$}\par +\P\D \37$\\{x3l}\S\\{stack\_3}(\\{xl\_packet})$\C{$X'_3$}\par +\P\D \37$\\{y1l}\S\\{stack\_1}(\\{yl\_packet})$\C{$Y'_1$}\par +\P\D \37$\\{y2l}\S\\{stack\_2}(\\{yl\_packet})$\C{$Y'_2$}\par +\P\D \37$\\{y3l}\S\\{stack\_3}(\\{yl\_packet})$\C{$Y'_3$}\par +\P\D \37$\\{u1r}\S\\{stack\_1}(\\{ur\_packet})$\C{$U''_1$}\par +\P\D \37$\\{u2r}\S\\{stack\_2}(\\{ur\_packet})$\C{$U''_2$}\par +\P\D \37$\\{u3r}\S\\{stack\_3}(\\{ur\_packet})$\C{$U''_3$}\par +\P\D \37$\\{v1r}\S\\{stack\_1}(\\{vr\_packet})$\C{$V''_1$}\par +\P\D \37$\\{v2r}\S\\{stack\_2}(\\{vr\_packet})$\C{$V''_2$}\par +\P\D \37$\\{v3r}\S\\{stack\_3}(\\{vr\_packet})$\C{$V''_3$}\par +\P\D \37$\\{x1r}\S\\{stack\_1}(\\{xr\_packet})$\C{$X''_1$}\par +\P\D \37$\\{x2r}\S\\{stack\_2}(\\{xr\_packet})$\C{$X''_2$}\par +\P\D \37$\\{x3r}\S\\{stack\_3}(\\{xr\_packet})$\C{$X''_3$}\par +\P\D \37$\\{y1r}\S\\{stack\_1}(\\{yr\_packet})$\C{$Y''_1$}\par +\P\D \37$\\{y2r}\S\\{stack\_2}(\\{yr\_packet})$\C{$Y''_2$}\par +\P\D \37$\\{y3r}\S\\{stack\_3}(\\{yr\_packet})$\C{$Y''_3$}\Y\par +\P\D \37$\\{stack\_dx}\S\\{bisect\_stack}[\\{bisect\_ptr}]$\C{stacked value of % +\\{delx}}\par +\P\D \37$\\{stack\_dy}\S\\{bisect\_stack}[\\{bisect\_ptr}+1]$\C{stacked value +of \\{dely}}\par +\P\D \37$\\{stack\_tol}\S\\{bisect\_stack}[\\{bisect\_ptr}+2]$\C{stacked value +of \\{tol}}\par +\P\D \37$\\{stack\_uv}\S\\{bisect\_stack}[\\{bisect\_ptr}+3]$\C{stacked value +of \\{uv}}\par +\P\D \37$\\{stack\_xy}\S\\{bisect\_stack}[\\{bisect\_ptr}+4]$\C{stacked value +of \\{xy}}\par +\P\D \37$\\{int\_increment}=\\{int\_packets}+\\{int\_packets}+5$\C{number of +stack words per level}\par +\Y\P$\4\X14:Check the ``constant'' values for consistency\X\mathrel{+}\S$\6 +\&{if} $\\{int\_packets}+17\ast\\{int\_increment}>\\{bistack\_size}$ \1\&{then}% +\5 +$\\{bad}\K32$;\2\par +\fi + +\M554. Computation of the min and max is a tedious but fairly fast sequence of +instructions; exactly four comparisons are made in each branch. + +\Y\P\D \37$\\{set\_min\_max}(\#)\S$\1\6 +\&{if} $\\{stack\_1}(\#)<0$ \1\&{then}\6 +\&{if} $\\{stack\_3}(\#)\G0$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{stack\_2}(\#)<0$ \1\&{then}\5 +$\\{stack\_min}(\#)\K\\{stack\_1}(\#)+\\{stack\_2}(\#)$\6 +\4\&{else} $\\{stack\_min}(\#)\K\\{stack\_1}(\#)$;\2\6 +$\\{stack\_max}(\#)\K\\{stack\_1}(\#)+\\{stack\_2}(\#)+\\{stack\_3}(\#)$;\6 +\&{if} $\\{stack\_max}(\#)<0$ \1\&{then}\5 +$\\{stack\_max}(\#)\K0$;\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{stack\_min}(\#)\K\\{stack\_1}(\#)+\\{stack\_2}(\#)+% +\\{stack\_3}(\#)$;\6 +\&{if} $\\{stack\_min}(\#)>\\{stack\_1}(\#)$ \1\&{then}\5 +$\\{stack\_min}(\#)\K\\{stack\_1}(\#)$;\2\6 +$\\{stack\_max}(\#)\K\\{stack\_1}(\#)+\\{stack\_2}(\#)$;\6 +\&{if} $\\{stack\_max}(\#)<0$ \1\&{then}\5 +$\\{stack\_max}(\#)\K0$;\2\6 +\&{end}\2\6 +\4\&{else} \&{if} $\\{stack\_3}(\#)\L0$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{stack\_2}(\#)>0$ \1\&{then}\5 +$\\{stack\_max}(\#)\K\\{stack\_1}(\#)+\\{stack\_2}(\#)$\6 +\4\&{else} $\\{stack\_max}(\#)\K\\{stack\_1}(\#)$;\2\6 +$\\{stack\_min}(\#)\K\\{stack\_1}(\#)+\\{stack\_2}(\#)+\\{stack\_3}(\#)$;\6 +\&{if} $\\{stack\_min}(\#)>0$ \1\&{then}\5 +$\\{stack\_min}(\#)\K0$;\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{stack\_max}(\#)\K\\{stack\_1}(\#)+\\{stack\_2}(\#)+% +\\{stack\_3}(\#)$;\6 +\&{if} $\\{stack\_max}(\#)<\\{stack\_1}(\#)$ \1\&{then}\5 +$\\{stack\_max}(\#)\K\\{stack\_1}(\#)$;\2\6 +$\\{stack\_min}(\#)\K\\{stack\_1}(\#)+\\{stack\_2}(\#)$;\6 +\&{if} $\\{stack\_min}(\#)>0$ \1\&{then}\5 +$\\{stack\_min}(\#)\K0$;\2\6 +\&{end}\2\2\2\par +\fi + +\M555. It's convenient to keep the current values of $l$, $t_1$, and $t_2$ in +the integer form $2^l+2^lt_1$ and $2^l+2^lt_2$. The \\{cubic\_intersection} +routine uses global variables \\{cur\_t} and \\{cur\_tt} for this purpose; +after successful completion, \\{cur\_t} and \\{cur\_tt} will contain \\{unity} +plus the \\{scaled} values of $t_1$ and~$t_2$. + +The values of \\{cur\_t} and \\{cur\_tt} will be set to zero if \\{cubic% +\_intersection} +finds no intersection. The routine gives up and gives an approximate answer +if it has backtracked +more than 5000 times (otherwise there are cases where several minutes +of fruitless computation would be possible). + +\Y\P\D \37$\\{max\_patience}=5000$\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4$\\{cur\_t},\39\\{cur\_tt}$: \37\\{integer};\C{controls and results of % +\\{cubic\_intersection}}\6 +\4\\{time\_to\_go}: \37\\{integer};\C{this many backtracks before giving up}\6 +\4\\{max\_t}: \37\\{integer};\C{maximum of $2^{l+1}$ so far achieved}\par +\fi + +\M556. The given cubics $B(w_0,w_1,w_2,w_3;t)$ and +$B(z_0,z_1,z_2,z_3;t)$ are specified in adjacent knot nodes $(\|p,\\{link}(% +\|p))$ +and $(\\{pp},\\{link}(\\{pp}))$, respectively. + +\Y\P\4\&{procedure}\1\ \37$\\{cubic\_intersection}(\|p,\39\\{pp}:% +\\{pointer})$;\6 +\4\&{label} \37$\\{continue},\39\\{not\_found},\39\\{exit}$;\6 +\4\&{var} \37$\|q,\39\\{qq}$: \37\\{pointer};\C{$\\{link}(\|p)$, $\\{link}(% +\\{pp})$}\2\6 +\&{begin} \37$\\{time\_to\_go}\K\\{max\_patience}$;\5 +$\\{max\_t}\K2$;\5 +\X558:Initialize for intersections at level zero\X;\6 +\~ \1\&{loop}\ \&{begin} \37\\{continue}: \37\&{if} $\\{delx}-\\{tol}\L\\{stack% +\_max}(\\{x\_packet}(\\{xy}))-\\{stack\_min}(\\{u\_packet}(\\{uv}))$ \1\&{then}% +\6 +\&{if} $\\{delx}+\\{tol}\G\\{stack\_min}(\\{x\_packet}(\\{xy}))-\\{stack\_max}(% +\\{u\_packet}(\\{uv}))$ \1\&{then}\6 +\&{if} $\\{dely}-\\{tol}\L\\{stack\_max}(\\{y\_packet}(\\{xy}))-\\{stack\_min}(% +\\{v\_packet}(\\{uv}))$ \1\&{then}\6 +\&{if} $\\{dely}+\\{tol}\G\\{stack\_min}(\\{y\_packet}(\\{xy}))-\\{stack\_max}(% +\\{v\_packet}(\\{uv}))$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{cur\_t}\G\\{max\_t}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{max\_t}=\\{two}$ \1\&{then}\C{we've done 17 bisections}% +\6 +\&{begin} \37$\\{cur\_t}\K\\{half}(\\{cur\_t}+1)$;\5 +$\\{cur\_tt}\K\\{half}(\\{cur\_tt}+1)$;\5 +\&{return};\6 +\&{end};\2\6 +$\\{double}(\\{max\_t})$;\5 +$\\{appr\_t}\K\\{cur\_t}$;\5 +$\\{appr\_tt}\K\\{cur\_tt}$;\6 +\&{end};\2\6 +\X559:Subdivide for a new level of intersection\X;\6 +\&{goto} \37\\{continue};\6 +\&{end};\2\2\2\2\6 +\&{if} $\\{time\_to\_go}>0$ \1\&{then}\5 +$\\{decr}(\\{time\_to\_go})$\6 +\4\&{else} \&{begin} \37\&{while} $\\{appr\_t}<\\{unity}$ \1\&{do}\6 +\&{begin} \37$\\{double}(\\{appr\_t})$;\5 +$\\{double}(\\{appr\_tt})$;\6 +\&{end};\2\6 +$\\{cur\_t}\K\\{appr\_t}$;\5 +$\\{cur\_tt}\K\\{appr\_tt}$;\5 +\&{return};\6 +\&{end};\2\6 +\X560:Advance to the next pair $(\\{cur\_t},\\{cur\_tt})$\X;\6 +\&{end};\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M557. The following variables are global, although they are used only by +\\{cubic\_intersection}, because it is necessary on some machines to +split \\{cubic\_intersection} up into two procedures. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4$\\{delx},\39\\{dely}$: \37\\{integer};\C{the components of $% +\Delta=2^l(w_0-z_0)$}\6 +\4\\{tol}: \37\\{integer};\C{bound on the uncertainly in the overlap test}\6 +\4$\\{uv},\39\\{xy}$: \37$0\to\\{bistack\_size}$;\C{pointers to the current +packets of interest}\6 +\4\\{three\_l}: \37\\{integer};\C{\\{tol\_step} times the bisection level}\6 +\4$\\{appr\_t},\39\\{appr\_tt}$: \37\\{integer};\C{best approximations known to +the answers}\par +\fi + +\M558. We shall assume that the coordinates are sufficiently non-extreme that +integer overflow will not occur. + +\Y\P$\4\X558:Initialize for intersections at level zero\X\S$\6 +$\|q\K\\{link}(\|p)$;\5 +$\\{qq}\K\\{link}(\\{pp})$;\5 +$\\{bisect\_ptr}\K\\{int\_packets}$;\6 +$\\{u1r}\K\\{right\_x}(\|p)-\\{x\_coord}(\|p)$;\5 +$\\{u2r}\K\\{left\_x}(\|q)-\\{right\_x}(\|p)$;\5 +$\\{u3r}\K\\{x\_coord}(\|q)-\\{left\_x}(\|q)$;\5 +$\\{set\_min\_max}(\\{ur\_packet})$;\6 +$\\{v1r}\K\\{right\_y}(\|p)-\\{y\_coord}(\|p)$;\5 +$\\{v2r}\K\\{left\_y}(\|q)-\\{right\_y}(\|p)$;\5 +$\\{v3r}\K\\{y\_coord}(\|q)-\\{left\_y}(\|q)$;\5 +$\\{set\_min\_max}(\\{vr\_packet})$;\6 +$\\{x1r}\K\\{right\_x}(\\{pp})-\\{x\_coord}(\\{pp})$;\5 +$\\{x2r}\K\\{left\_x}(\\{qq})-\\{right\_x}(\\{pp})$;\5 +$\\{x3r}\K\\{x\_coord}(\\{qq})-\\{left\_x}(\\{qq})$;\5 +$\\{set\_min\_max}(\\{xr\_packet})$;\6 +$\\{y1r}\K\\{right\_y}(\\{pp})-\\{y\_coord}(\\{pp})$;\5 +$\\{y2r}\K\\{left\_y}(\\{qq})-\\{right\_y}(\\{pp})$;\5 +$\\{y3r}\K\\{y\_coord}(\\{qq})-\\{left\_y}(\\{qq})$;\5 +$\\{set\_min\_max}(\\{yr\_packet})$;\6 +$\\{delx}\K\\{x\_coord}(\|p)-\\{x\_coord}(\\{pp})$;\5 +$\\{dely}\K\\{y\_coord}(\|p)-\\{y\_coord}(\\{pp})$;\6 +$\\{tol}\K0$;\5 +$\\{uv}\K\\{r\_packets}$;\5 +$\\{xy}\K\\{r\_packets}$;\5 +$\\{three\_l}\K0$;\5 +$\\{cur\_t}\K1$;\5 +$\\{cur\_tt}\K1$\par +\U556.\fi + +\M559. \P$\X559:Subdivide for a new level of intersection\X\S$\6 +$\\{stack\_dx}\K\\{delx}$;\5 +$\\{stack\_dy}\K\\{dely}$;\5 +$\\{stack\_tol}\K\\{tol}$;\5 +$\\{stack\_uv}\K\\{uv}$;\5 +$\\{stack\_xy}\K\\{xy}$;\5 +$\\{bisect\_ptr}\K\\{bisect\_ptr}+\\{int\_increment}$;\6 +$\\{double}(\\{cur\_t})$;\5 +$\\{double}(\\{cur\_tt})$;\6 +$\\{u1l}\K\\{stack\_1}(\\{u\_packet}(\\{uv}))$;\5 +$\\{u3r}\K\\{stack\_3}(\\{u\_packet}(\\{uv}))$;\5 +$\\{u2l}\K\\{half}(\\{u1l}+\\{stack\_2}(\\{u\_packet}(\\{uv})))$;\5 +$\\{u2r}\K\\{half}(\\{u3r}+\\{stack\_2}(\\{u\_packet}(\\{uv})))$;\5 +$\\{u3l}\K\\{half}(\\{u2l}+\\{u2r})$;\5 +$\\{u1r}\K\\{u3l}$;\5 +$\\{set\_min\_max}(\\{ul\_packet})$;\5 +$\\{set\_min\_max}(\\{ur\_packet})$;\6 +$\\{v1l}\K\\{stack\_1}(\\{v\_packet}(\\{uv}))$;\5 +$\\{v3r}\K\\{stack\_3}(\\{v\_packet}(\\{uv}))$;\5 +$\\{v2l}\K\\{half}(\\{v1l}+\\{stack\_2}(\\{v\_packet}(\\{uv})))$;\5 +$\\{v2r}\K\\{half}(\\{v3r}+\\{stack\_2}(\\{v\_packet}(\\{uv})))$;\5 +$\\{v3l}\K\\{half}(\\{v2l}+\\{v2r})$;\5 +$\\{v1r}\K\\{v3l}$;\5 +$\\{set\_min\_max}(\\{vl\_packet})$;\5 +$\\{set\_min\_max}(\\{vr\_packet})$;\6 +$\\{x1l}\K\\{stack\_1}(\\{x\_packet}(\\{xy}))$;\5 +$\\{x3r}\K\\{stack\_3}(\\{x\_packet}(\\{xy}))$;\5 +$\\{x2l}\K\\{half}(\\{x1l}+\\{stack\_2}(\\{x\_packet}(\\{xy})))$;\5 +$\\{x2r}\K\\{half}(\\{x3r}+\\{stack\_2}(\\{x\_packet}(\\{xy})))$;\5 +$\\{x3l}\K\\{half}(\\{x2l}+\\{x2r})$;\5 +$\\{x1r}\K\\{x3l}$;\5 +$\\{set\_min\_max}(\\{xl\_packet})$;\5 +$\\{set\_min\_max}(\\{xr\_packet})$;\6 +$\\{y1l}\K\\{stack\_1}(\\{y\_packet}(\\{xy}))$;\5 +$\\{y3r}\K\\{stack\_3}(\\{y\_packet}(\\{xy}))$;\5 +$\\{y2l}\K\\{half}(\\{y1l}+\\{stack\_2}(\\{y\_packet}(\\{xy})))$;\5 +$\\{y2r}\K\\{half}(\\{y3r}+\\{stack\_2}(\\{y\_packet}(\\{xy})))$;\5 +$\\{y3l}\K\\{half}(\\{y2l}+\\{y2r})$;\5 +$\\{y1r}\K\\{y3l}$;\5 +$\\{set\_min\_max}(\\{yl\_packet})$;\5 +$\\{set\_min\_max}(\\{yr\_packet})$;\6 +$\\{uv}\K\\{l\_packets}$;\5 +$\\{xy}\K\\{l\_packets}$;\5 +$\\{double}(\\{delx})$;\5 +$\\{double}(\\{dely})$;\6 +$\\{tol}\K\\{tol}-\\{three\_l}+\\{tol\_step}$;\5 +$\\{double}(\\{tol})$;\5 +$\\{three\_l}\K\\{three\_l}+\\{tol\_step}$\par +\U556.\fi + +\M560. \P$\X560:Advance to the next pair $(\\{cur\_t},\\{cur\_tt})$\X\S$\6 +\4\\{not\_found}: \37\&{if} $\\{odd}(\\{cur\_tt})$ \1\&{then}\6 +\&{if} $\\{odd}(\\{cur\_t})$ \1\&{then}\5 +\X561:Descend to the previous level and \&{goto} \\{not\_found}\X\6 +\4\&{else} \&{begin} \37$\\{incr}(\\{cur\_t})$;\5 +$\\{delx}\K\\{delx}+\\{stack\_1}(\\{u\_packet}(\\{uv}))+\\{stack\_2}(\\{u% +\_packet}(\\{uv}))+\\{stack\_3}(\\{u\_packet}(\\{uv}))$;\5 +$\\{dely}\K\\{dely}+\\{stack\_1}(\\{v\_packet}(\\{uv}))+\\{stack\_2}(\\{v% +\_packet}(\\{uv}))+\\{stack\_3}(\\{v\_packet}(\\{uv}))$;\5 +$\\{uv}\K\\{uv}+\\{int\_packets}$;\C{switch from \\{l\_packet} to \\{r% +\_packet}}\6 +$\\{decr}(\\{cur\_tt})$;\5 +$\\{xy}\K\\{xy}-\\{int\_packets}$;\C{switch from \\{r\_packet} to \\{l% +\_packet}}\6 +$\\{delx}\K\\{delx}+\\{stack\_1}(\\{x\_packet}(\\{xy}))+\\{stack\_2}(\\{x% +\_packet}(\\{xy}))+\\{stack\_3}(\\{x\_packet}(\\{xy}))$;\5 +$\\{dely}\K\\{dely}+\\{stack\_1}(\\{y\_packet}(\\{xy}))+\\{stack\_2}(\\{y% +\_packet}(\\{xy}))+\\{stack\_3}(\\{y\_packet}(\\{xy}))$;\6 +\&{end}\2\6 +\4\&{else} \&{begin} \37$\\{incr}(\\{cur\_tt})$;\5 +$\\{tol}\K\\{tol}+\\{three\_l}$;\5 +$\\{delx}\K\\{delx}-\\{stack\_1}(\\{x\_packet}(\\{xy}))-\\{stack\_2}(\\{x% +\_packet}(\\{xy}))-\\{stack\_3}(\\{x\_packet}(\\{xy}))$;\5 +$\\{dely}\K\\{dely}-\\{stack\_1}(\\{y\_packet}(\\{xy}))-\\{stack\_2}(\\{y% +\_packet}(\\{xy}))-\\{stack\_3}(\\{y\_packet}(\\{xy}))$;\5 +$\\{xy}\K\\{xy}+\\{int\_packets}$;\C{switch from \\{l\_packet} to \\{r% +\_packet}}\6 +\&{end}\2\par +\U556.\fi + +\M561. \P$\X561:Descend to the previous level and \&{goto} \\{not\_found}\X\S$\6 +\&{begin} \37$\\{cur\_t}\K\\{half}(\\{cur\_t})$;\5 +$\\{cur\_tt}\K\\{half}(\\{cur\_tt})$;\6 +\&{if} $\\{cur\_t}=0$ \1\&{then}\5 +\&{return};\2\6 +$\\{bisect\_ptr}\K\\{bisect\_ptr}-\\{int\_increment}$;\5 +$\\{three\_l}\K\\{three\_l}-\\{tol\_step}$;\5 +$\\{delx}\K\\{stack\_dx}$;\5 +$\\{dely}\K\\{stack\_dy}$;\5 +$\\{tol}\K\\{stack\_tol}$;\5 +$\\{uv}\K\\{stack\_uv}$;\5 +$\\{xy}\K\\{stack\_xy}$;\6 +\&{goto} \37\\{not\_found};\6 +\&{end}\par +\U560.\fi + +\M562. The \\{path\_intersection} procedure is much simpler. +It invokes \\{cubic\_intersection} in lexicographic order until finding a +pair of cubics that intersect. The final intersection times are placed in +\\{cur\_t} and~\\{cur\_tt}. + +\Y\P\4\&{procedure}\1\ \37$\\{path\_intersection}(\|h,\39\\{hh}:\\{pointer})$;% +\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37$\|p,\39\\{pp}$: \37\\{pointer};\C{link registers that traverse +the given paths}\6 +$\|n,\39\\{nn}$: \37\\{integer};\C{integer parts of intersection times, minus % +\\{unity}}\2\6 +\&{begin} \37\X563:Change one-point paths into dead cycles\X;\6 +$\\{tol\_step}\K0$;\6 +\1\&{repeat} \37$\|n\K-\\{unity}$;\5 +$\|p\K\|h$;\6 +\1\&{repeat} \37\&{if} $\\{right\_type}(\|p)\I\\{endpoint}$ \1\&{then}\6 +\&{begin} \37$\\{nn}\K-\\{unity}$;\5 +$\\{pp}\K\\{hh}$;\6 +\1\&{repeat} \37\&{if} $\\{right\_type}(\\{pp})\I\\{endpoint}$ \1\&{then}\6 +\&{begin} \37$\\{cubic\_intersection}(\|p,\39\\{pp})$;\6 +\&{if} $\\{cur\_t}>0$ \1\&{then}\6 +\&{begin} \37$\\{cur\_t}\K\\{cur\_t}+\|n$;\5 +$\\{cur\_tt}\K\\{cur\_tt}+\\{nn}$;\5 +\&{return};\6 +\&{end};\2\6 +\&{end};\2\6 +$\\{nn}\K\\{nn}+\\{unity}$;\5 +$\\{pp}\K\\{link}(\\{pp})$;\6 +\4\&{until}\5 +$\\{pp}=\\{hh}$;\2\6 +\&{end};\2\6 +$\|n\K\|n+\\{unity}$;\5 +$\|p\K\\{link}(\|p)$;\6 +\4\&{until}\5 +$\|p=\|h$;\2\6 +$\\{tol\_step}\K\\{tol\_step}+3$;\6 +\4\&{until}\5 +$\\{tol\_step}>3$;\2\6 +$\\{cur\_t}\K-\\{unity}$;\5 +$\\{cur\_tt}\K-\\{unity}$;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M563. \P$\X563:Change one-point paths into dead cycles\X\S$\6 +\&{if} $\\{right\_type}(\|h)=\\{endpoint}$ \1\&{then}\6 +\&{begin} \37$\\{right\_x}(\|h)\K\\{x\_coord}(\|h)$;\5 +$\\{left\_x}(\|h)\K\\{x\_coord}(\|h)$;\5 +$\\{right\_y}(\|h)\K\\{y\_coord}(\|h)$;\5 +$\\{left\_y}(\|h)\K\\{y\_coord}(\|h)$;\5 +$\\{right\_type}(\|h)\K\\{explicit}$;\6 +\&{end};\2\6 +\&{if} $\\{right\_type}(\\{hh})=\\{endpoint}$ \1\&{then}\6 +\&{begin} \37$\\{right\_x}(\\{hh})\K\\{x\_coord}(\\{hh})$;\5 +$\\{left\_x}(\\{hh})\K\\{x\_coord}(\\{hh})$;\5 +$\\{right\_y}(\\{hh})\K\\{y\_coord}(\\{hh})$;\5 +$\\{left\_y}(\\{hh})\K\\{y\_coord}(\\{hh})$;\5 +$\\{right\_type}(\\{hh})\K\\{explicit}$;\6 +\&{end};\2\par +\U562.\fi + +\N564. \[27] Online graphic output. +\MF\ displays images on the user's screen by means of a few primitive +operations that are defined below. These operations have deliberately been +kept simple so that they can be implemented without great difficulty on a +wide variety of machines. Since \PASCAL\ has no traditional standards for +graphic output, some system-dependent code needs to be written in order to +support this aspect of \MF; but the necessary routines are usually quite +easy to write. + +In fact, there are exactly four such routines: + +\yskip\hang +\\{init\_screen} does whatever initialization is necessary to +support the other operations; it is a boolean function that returns +\\{false} if graphic output cannot be supported (e.g., if the other three +routines have not been written, or if the user doesn't have the +right kind of terminal). + +\yskip\hang +\\{blank\_rectangle} updates a buffer area in memory so that +all pixels in a specified rectangle will be set to the background color. + +\yskip\hang +\\{paint\_row} assigns values to specified pixels in a row of +the buffer just mentioned, based on ``transition'' indices explained below. + +\yskip\hang +\\{update\_screen} displays the current screen buffer; the +effects of \\{blank\_rectangle} and \\{paint\_row} commands may or may not +become visible until the next \\{update\_screen} operation is performed. +(Thus, \\{update\_screen} is analogous to \\{update\_terminal}.) + +\yskip\noindent +The \PASCAL\ code here is a minimum version of \\{init\_screen} and +\\{update\_screen}, usable on \MF\ installations that don't +support screen output. If \\{init\_screen} is changed to return \\{true} +instead of \\{false}, the other routines will simply log the fact +that they have been called; they won't really display anything. +The standard test routines for \MF\ use this log information to check +that \MF\ is working properly, but the \\{wlog} instructions should be +removed from production versions of \MF. + +\Y\P\4\&{function}\1\ \37\\{init\_screen}: \37\\{boolean};\2\6 +\&{begin} \37$\\{init\_screen}\K\\{false}$;\6 +\&{end};\7 +\4\&{procedure}\1\ \37\\{update\_screen};\C{will be called only if \\{init% +\_screen} returns \\{true}}\2\6 +\&{begin} \37\&{init} \37$\\{wlog\_ln}(\.{\'Calling\ UPDATESCREEN\'})$;\ % +\&{tini}\C{for testing only}\6 +\&{end};\par +\fi + +\M565. The user's screen is assumed to be a rectangular area, \\{screen\_width} +pixels wide and \\{screen\_depth} pixels deep. The pixel in the upper left +corner is said to be in column~0 of row~0; the pixel in the lower right +corner is said to be in column $\\{screen\_width}-1$ of row $\\{screen% +\_depth}-1$. +Notice that row numbers increase from top to bottom, contrary to \MF's +other coordinates. + +Each pixel is assumed to have two states, referred to in this documentation +as \\{black} and \\{white}. The background color is called \\{white} and the +other color is called \\{black}; but any two distinct pixel values +can actually be used. For example, the author developed \MF\ on a +system for which \\{white} was black and \\{black} was bright green. + +\Y\P\D \37$\\{white}=0$\C{background pixels}\par +\P\D \37$\\{black}=1$\C{visible pixels}\par +\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6 +$\\{screen\_row}=0\to\\{screen\_depth}$;\C{a row number on the screen}\6 +$\\{screen\_col}=0\to\\{screen\_width}$;\C{a column number on the screen}\6 +$\\{trans\_spec}=$\1\5 +\&{array} $[\\{screen\_col}]$ \1\&{of}\5 +\\{screen\_col};\C{a transition spec, see below}\2\2\6 +$\\{pixel\_color}=\\{white}\to\\{black}$;\C{specifies one of the two pixel +values}\par +\fi + +\M566. We'll illustrate the \\{blank\_rectangle} and \\{paint\_row} operations +by +pretending to declare a screen buffer called \\{screen\_pixel}. This code +is actually commented out, but it does specify the intended effects. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4$\B\\{screen\_pixel}$: \37\&{array} $[\\{screen\_row},\39\\{screen\_col}]$ \1% +\&{of}\5 +\\{pixel\_color};\ \2\6 +$\T$\par +\fi + +\M567. The \\{blank\_rectangle} routine simply whitens all pixels that lie in +columns \\{left\_col} through $\\{right\_col}-1$, inclusive, of rows +\\{top\_row} through $\\{bot\_row}-1$, inclusive, given four parameters that +satisfy +the relations +$$\hbox{$0\L\\{left\_col}\L\\{right\_col}\L\\{screen\_width}$,\quad +$0\L\\{top\_row}\L\\{bot\_row}\L\\{screen\_depth}$.}$$ +If $\\{left\_col}=\\{right\_col}$ or $\\{top\_row}=\\{bot\_row}$, nothing +happens. + +The commented-out code in the following procedure is for illustrative +purposes only. + +\Y\P\4\&{procedure}\1\ \37$\\{blank\_rectangle}(\\{left\_col},\39\\{right% +\_col}:\\{screen\_col};\,\35\\{top\_row},\39\\{bot\_row}:\\{screen\_row})$;\6 +\4\&{var} \37\|r: \37\\{screen\_row};\5 +\|c: \37\\{screen\_col};\2\6 +\&{begin} \37$\B$\ \&{for} $\|r\K\\{top\_row}\mathrel{\&{to}}\\{bot\_row}-1$ \1% +\&{do}\6 +\&{for} $\|c\K\\{left\_col}\mathrel{\&{to}}\\{right\_col}-1$ \1\&{do}\5 +$\\{screen\_pixel}[\|r,\39\|c]\K\\{white}$;\ \2\2\6 +$\T$\6 +\&{init} \37\\{wlog\_cr};\C{this will be done only after $\\{init\_screen}=% +\\{true}$}\6 +$\\{wlog\_ln}(\.{\'Calling\ BLANKRECTANGLE(\'},\39\\{left\_col}:1,\39\.{\',\'},% +\39\\{right\_col}:1,\39\.{\',\'},\39\\{top\_row}:1,\39\.{\',\'},\39\\{bot% +\_row}:1,\39\.{\')\'})$;\ \&{tini}\6 +\&{end};\par +\fi + +\M568. The real work of screen display is done by \\{paint\_row}. But it's not +hard work, because the operation affects only +one of the screen rows, and it affects only a contiguous set of columns +in that row. There are four parameters: \|r~(the row), +\|b~(the initial color), +\|a~(the array of transition specifications), +and \|n~(the number of transitions). The elements of~\|a will satisfy +$$0\L a[0]<a[1]<\cdots<a[n]\L \\{screen\_width};$$ +the value of \|r will satisfy $0\L\|r<\\{screen\_depth}$; and \|n will be +positive. + +The general idea is to paint blocks of pixels in alternate colors; +the precise details are best conveyed by means of a \PASCAL\ +program (see the commented-out code below). + +\Y\P\4\&{procedure}\1\ \37$\\{paint\_row}(\|r:\\{screen\_row};\,\35\|b:% +\\{pixel\_color};\,\35\mathop{\&{var}}\|a:\\{trans\_spec};\,\35\|n:\\{screen% +\_col})$;\6 +\4\&{var} \37\|k: \37\\{screen\_col};\C{an index into \|a}\6 +\|c: \37\\{screen\_col};\C{an index into \\{screen\_pixel}}\2\6 +\&{begin} \37$\B\|k\K0$;\5 +$\|c\K\|a[0]$;\6 +\1\&{repeat} \37$\\{incr}(\|k)$;\6 +\1\&{repeat} \37$\\{screen\_pixel}[\|r,\39\|c]\K\|b$;\5 +$\\{incr}(\|c)$;\6 +\4\&{until}\5 +$\|c=\|a[\|k]$;\2\6 +$\|b\K\\{black}-\|b$;\C{$\\{black}\swap\\{white}$}\6 +\4\&{until}\5 +$\|k=\|n$;\ \2\6 +$\T$\6 +\&{init} \37$\\{wlog}(\.{\'Calling\ PAINTROW(\'},\39\|r:1,\39\.{\',\'},\39% +\|b:1,\39\.{\';\'})$;\C{this is done only after $\\{init\_screen}=\\{true}$}\6 +\&{for} $\|k\K0\mathrel{\&{to}}\|n$ \1\&{do}\6 +\&{begin} \37$\\{wlog}(\|a[\|k]:1)$;\6 +\&{if} $\|k\I\|n$ \1\&{then}\5 +$\\{wlog}(\.{\',\'})$;\2\6 +\&{end};\2\6 +$\\{wlog\_ln}(\.{\')\'})$;\ \&{tini}\6 +\&{end};\par +\fi + +\M569. The remainder of \MF's screen routines are system-independent calls +on the four primitives just defined. + +First we have a global boolean variable that tells if \\{init\_screen} +has been called, and another one that tells if \\{init\_screen} has +given a \\{true} response. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{screen\_started}: \37\\{boolean};\C{have the screen primitives been +initialized?}\6 +\4\\{screen\_OK}: \37\\{boolean};\C{is it legitimate to call \\{blank% +\_rectangle}, \\{paint\_row}, and \\{update\_screen}?}\par +\fi + +\M570. \P\D \37$\\{start\_screen}\S$\1\6 +\&{begin} \37\&{if} $\R\\{screen\_started}$ \1\&{then}\6 +\&{begin} \37$\\{screen\_OK}\K\\{init\_screen}$;\5 +$\\{screen\_started}\K\\{true}$;\6 +\&{end};\2\6 +\&{end}\2\par +\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{screen\_started}\K\\{false}$;\5 +$\\{screen\_OK}\K\\{false}$;\par +\fi + +\M571. \MF\ provides the user with 16 ``window'' areas on the screen, in each +of which it is possible to produce independent displays. + +It should be noted that \MF's windows aren't really independent +``clickable'' entities in the sense of multi-window graphic workstations; +\MF\ simply maps them into subsets of a single screen image that is +controlled by \\{init\_screen}, \\{blank\_rectangle}, \\{paint\_row}, and +\\{update\_screen} as described above. Implementations of \MF\ on a +multi-window workstation probably therefore make use of only two +windows in the other sense: one for the terminal output and another +for the screen with \MF's 16 areas. Henceforth we shall +use the term window only in \MF's sense. + +\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6 +$\\{window\_number}=0\to15$;\par +\fi + +\M572. A user doesn't have to use any of the 16 windows. But when a window is +``opened,'' it is allocated to a specific rectangular portion of the screen +and to a specific rectangle with respect to \MF's coordinates. The relevant +data is stored in global arrays \\{window\_open}, \\{left\_col}, \\{right% +\_col}, +\\{top\_row}, \\{bot\_row}, \\{m\_window}, and \\{n\_window}. + +The \\{window\_open} array is boolean, and its significance is obvious. The +\\{left\_col}, \dots, \\{bot\_row} arrays contain screen coordinates that +can be used to blank the entire window with \\{blank\_rectangle}. And the +other two arrays just mentioned handle the conversion between +actual coordinates and screen coordinates: \MF's pixel in column~$m$ +of row~$n$ will appear in screen column $\\{m\_window}+\|m$ and in screen row +$\\{n\_window}-\|n$, provided that these lie inside the boundaries of the +window. + +Another array \\{window\_time} holds the number of times this window has +been updated. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{window\_open}: \37\&{array} $[\\{window\_number}]$ \1\&{of}\5 +\\{boolean};\C{has this window been opened?}\2\6 +\4\\{left\_col}: \37\&{array} $[\\{window\_number}]$ \1\&{of}\5 +\\{screen\_col};\C{leftmost column position on screen}\2\6 +\4\\{right\_col}: \37\&{array} $[\\{window\_number}]$ \1\&{of}\5 +\\{screen\_col};\C{rightmost column position, plus~1}\2\6 +\4\\{top\_row}: \37\&{array} $[\\{window\_number}]$ \1\&{of}\5 +\\{screen\_row};\C{topmost row position on screen}\2\6 +\4\\{bot\_row}: \37\&{array} $[\\{window\_number}]$ \1\&{of}\5 +\\{screen\_row};\C{bottommost row position, plus~1}\2\6 +\4\\{m\_window}: \37\&{array} $[\\{window\_number}]$ \1\&{of}\5 +\\{integer};\C{offset between user and screen columns}\2\6 +\4\\{n\_window}: \37\&{array} $[\\{window\_number}]$ \1\&{of}\5 +\\{integer};\C{offset between user and screen rows}\2\6 +\4\\{window\_time}: \37\&{array} $[\\{window\_number}]$ \1\&{of}\5 +\\{integer};\C{it has been updated this often}\2\par +\fi + +\M573. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +\&{for} $\|k\K0\mathrel{\&{to}}15$ \1\&{do}\6 +\&{begin} \37$\\{window\_open}[\|k]\K\\{false}$;\5 +$\\{window\_time}[\|k]\K0$;\6 +\&{end};\2\par +\fi + +\M574. Opening a window isn't like opening a file, because you can open it +as often as you like, and you never have to close it again. The idea is +simply to define special points on the current screen display. + +Overlapping window specifications may cause complex effects that can +be understood only by scrutinizing \MF's display algorithms; thus it +has been left undefined in the \MF\ user manual, although the behavior +is in fact predictable. + +Here is a subroutine that implements the command `\&{openwindow}~\|k +\&{from}~$(\\{r0},\\{c0})$ \&{to}~$(\\{r1},\\{c1})$ \&{at}~$(x,y)$'. + +\Y\P\4\&{procedure}\1\ \37$\\{open\_a\_window}(\|k:\\{window\_number};\,\35% +\\{r0},\39\\{c0},\39\\{r1},\39\\{c1}:\\{scaled};\,\35\|x,\39\|y:\\{scaled})$;\6 +\4\&{var} \37$\|m,\39\|n$: \37\\{integer};\C{pixel coordinates}\2\6 +\&{begin} \37\X575:Adjust the coordinates $(\\{r0},\\{c0})$ and $(\\{r1},% +\\{c1})$ so that they lie in the proper range\X;\6 +$\\{window\_open}[\|k]\K\\{true}$;\5 +$\\{incr}(\\{window\_time}[\|k])$;\6 +$\\{left\_col}[\|k]\K\\{c0}$;\5 +$\\{right\_col}[\|k]\K\\{c1}$;\5 +$\\{top\_row}[\|k]\K\\{r0}$;\5 +$\\{bot\_row}[\|k]\K\\{r1}$;\6 +\X576:Compute the offsets between screen coordinates and actual coordinates\X;\6 +\\{start\_screen};\6 +\&{if} $\\{screen\_OK}$ \1\&{then}\6 +\&{begin} \37$\\{blank\_rectangle}(\\{c0},\39\\{c1},\39\\{r0},\39\\{r1})$;\5 +\\{update\_screen};\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M575. A window whose coordinates don't fit the existing screen size will be +truncated until they do. + +\Y\P$\4\X575:Adjust the coordinates $(\\{r0},\\{c0})$ and $(\\{r1},\\{c1})$ so +that they lie in the proper range\X\S$\6 +\&{if} $\\{r0}<0$ \1\&{then}\5 +$\\{r0}\K0$\ \&{else} $\\{r0}\K\\{round\_unscaled}(\\{r0})$;\2\6 +$\\{r1}\K\\{round\_unscaled}(\\{r1})$;\6 +\&{if} $\\{r1}>\\{screen\_depth}$ \1\&{then}\5 +$\\{r1}\K\\{screen\_depth}$;\2\6 +\&{if} $\\{r1}<\\{r0}$ \1\&{then}\6 +\&{if} $\\{r0}>\\{screen\_depth}$ \1\&{then}\5 +$\\{r0}\K\\{r1}$\ \&{else} $\\{r1}\K\\{r0}$;\2\2\6 +\&{if} $\\{c0}<0$ \1\&{then}\5 +$\\{c0}\K0$\ \&{else} $\\{c0}\K\\{round\_unscaled}(\\{c0})$;\2\6 +$\\{c1}\K\\{round\_unscaled}(\\{c1})$;\6 +\&{if} $\\{c1}>\\{screen\_width}$ \1\&{then}\5 +$\\{c1}\K\\{screen\_width}$;\2\6 +\&{if} $\\{c1}<\\{c0}$ \1\&{then}\6 +\&{if} $\\{c0}>\\{screen\_width}$ \1\&{then}\5 +$\\{c0}\K\\{c1}$\ \&{else} $\\{c1}\K\\{c0}$\2\2\par +\U574.\fi + +\M576. Three sets of coordinates are rampant, and they must be kept straight! +(i)~\MF's main coordinates refer to the edges between pixels. (ii)~\MF's +pixel coordinates (within edge structures) say that the pixel bounded by +$(m,n)$, $(m,n+1)$, $(m+1,n)$, and~$(m+1,n+1)$ is in pixel row number~$n$ +and pixel column number~$m$. (iii)~Screen coordinates, on the other hand, +have rows numbered in increasing order from top to bottom, as mentioned +above. + +The program here first computes integers $m$ and $n$ such that +pixel column~$m$ of pixel row~$n$ will be at the upper left corner +of the window. Hence pixel column $\|m-\\{c0}$ of pixel row $\|n+\\{r0}$ +will be at the upper left corner of the screen. + +\Y\P$\4\X576:Compute the offsets between screen coordinates and actual +coordinates\X\S$\6 +$\|m\K\\{round\_unscaled}(\|x)$;\5 +$\|n\K\\{round\_unscaled}(\|y)-1$;\6 +$\\{m\_window}[\|k]\K\\{c0}-\|m$;\5 +$\\{n\_window}[\|k]\K\\{r0}+\|n$\par +\U574.\fi + +\M577. Now here comes \MF's most complicated operation related to window +display: Given the number~\|k of an open window, the pixels of positive +weight in \\{cur\_edges} will be shown as \\{black} in the window; all other +pixels will be shown as \\{white}. + +\Y\P\4\&{procedure}\1\ \37$\\{disp\_edges}(\|k:\\{window\_number})$;\6 +\4\&{label} \37$\\{done},\39\\{found}$;\6 +\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{for list manipulation}\6 +\\{already\_there}: \37\\{boolean};\C{is a previous incarnation in the window?}% +\6 +\|r: \37\\{integer};\C{row number}\6 +\X580:Other local variables for \\{disp\_edges}\X\2\6 +\&{begin} \37\&{if} $\\{screen\_OK}$ \1\&{then}\6 +\&{if} $\\{left\_col}[\|k]<\\{right\_col}[\|k]$ \1\&{then}\6 +\&{if} $\\{top\_row}[\|k]<\\{bot\_row}[\|k]$ \1\&{then}\6 +\&{begin} \37$\\{already\_there}\K\\{false}$;\6 +\&{if} $\\{last\_window}(\\{cur\_edges})=\|k$ \1\&{then}\6 +\&{if} $\\{last\_window\_time}(\\{cur\_edges})=\\{window\_time}[\|k]$ \1% +\&{then}\5 +$\\{already\_there}\K\\{true}$;\2\2\6 +\&{if} $\R\\{already\_there}$ \1\&{then}\5 +$\\{blank\_rectangle}(\\{left\_col}[\|k],\39\\{right\_col}[\|k],\39\\{top% +\_row}[\|k],\39\\{bot\_row}[\|k])$;\2\6 +\X581:Initialize for the display computations\X;\6 +$\|p\K\\{link}(\\{cur\_edges})$;\5 +$\|r\K\\{n\_window}[\|k]-(\\{n\_min}(\\{cur\_edges})-\\{zero\_field})$;\6 +\&{while} $(\|p\I\\{cur\_edges})\W(\|r\G\\{top\_row}[\|k])$ \1\&{do}\6 +\&{begin} \37\&{if} $\|r<\\{bot\_row}[\|k]$ \1\&{then}\5 +\X578:Display the pixels of edge row \|p in screen row \|r\X;\2\6 +$\|p\K\\{link}(\|p)$;\5 +$\\{decr}(\|r)$;\6 +\&{end};\2\6 +\\{update\_screen};\5 +$\\{incr}(\\{window\_time}[\|k])$;\5 +$\\{last\_window}(\\{cur\_edges})\K\|k$;\5 +$\\{last\_window\_time}(\\{cur\_edges})\K\\{window\_time}[\|k]$;\6 +\&{end};\2\2\2\6 +\&{end};\par +\fi + +\M578. Since it takes some work to display a row, we try to avoid recomputation +whenever we can. + +\Y\P$\4\X578:Display the pixels of edge row \|p in screen row \|r\X\S$\6 +\&{begin} \37\&{if} $\\{unsorted}(\|p)>\\{void}$ \1\&{then}\5 +$\\{sort\_edges}(\|p)$\6 +\4\&{else} \&{if} $\\{unsorted}(\|p)=\\{void}$ \1\&{then}\6 +\&{if} $\\{already\_there}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\2\2\6 +$\\{unsorted}(\|p)\K\\{void}$;\C{this time we'll paint, but maybe not next +time}\6 +\X582:Set up the parameters needed for \\{paint\_row}; but \&{goto} \\{done} if +no painting is needed after all\X;\6 +$\\{paint\_row}(\|r,\39\|b,\39\\{row\_transition},\39\|n)$;\6 +\4\\{done}: \37\&{end}\par +\U577.\fi + +\M579. The transition-specification parameter to \\{paint\_row} is always the +same +array. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{row\_transition}: \37\\{trans\_spec};\C{an array of \\{black}/\\{white} +transitions}\par +\fi + +\M580. The job remaining is to go through the list $\\{sorted}(\|p)$, unpacking +the +\\{info} fields into \|m and weight, then making \\{black} the pixels whose +accumulated weight~\|w is positive. + +\Y\P$\4\X580:Other local variables for \\{disp\_edges}\X\S$\6 +\4\|n: \37\\{screen\_col};\C{the highest active index in \\{row\_transition}}\6 +\4$\|w,\39\\{ww}$: \37\\{integer};\C{old and new accumulated weights}\6 +\4\|b: \37\\{pixel\_color};\C{status of first pixel in the row transitions}\6 +\4$\|m,\39\\{mm}$: \37\\{integer};\C{old and new screen column positions}\6 +\4\|d: \37\\{integer};\C{edge-and-weight without \\{min\_halfword} +compensation}\6 +\4\\{m\_adjustment}: \37\\{integer};\C{conversion between edge and screen +coordinates}\6 +\4\\{right\_edge}: \37\\{integer};\C{largest edge-and-weight that could affect +the window}\6 +\4\\{min\_col}: \37\\{screen\_col};\C{the smallest screen column number in the +window}\par +\U577.\fi + +\M581. Some precomputed constants make the display calculations faster. + +\Y\P$\4\X581:Initialize for the display computations\X\S$\6 +$\\{m\_adjustment}\K\\{m\_window}[\|k]-\\{m\_offset}(\\{cur\_edges})$;\6 +$\\{right\_edge}\K8\ast(\\{right\_col}[\|k]-\\{m\_adjustment})$;\6 +$\\{min\_col}\K\\{left\_col}[\|k]$\par +\U577.\fi + +\M582. \P$\X582:Set up the parameters needed for \\{paint\_row}; but \&{goto} % +\\{done} if no painting is needed after all\X\S$\6 +$\|n\K0$;\5 +$\\{ww}\K0$;\5 +$\|m\K-1$;\5 +$\|w\K0$;\5 +$\|q\K\\{sorted}(\|p)$;\5 +$\\{row\_transition}[0]\K\\{min\_col}$;\6 +\~ \1\&{loop}\ \&{begin} \37\&{if} $\|q=\\{sentinel}$ \1\&{then}\5 +$\|d\K\\{right\_edge}$\6 +\4\&{else} $\|d\K\\{ho}(\\{info}(\|q))$;\2\6 +$\\{mm}\K(\|d\mathbin{\&{div}}8)+\\{m\_adjustment}$;\6 +\&{if} $\\{mm}\I\|m$ \1\&{then}\6 +\&{begin} \37\X583:Record a possible transition in column \|m\X;\6 +$\|m\K\\{mm}$;\5 +$\|w\K\\{ww}$;\6 +\&{end};\2\6 +\&{if} $\|d\G\\{right\_edge}$ \1\&{then}\5 +\&{goto} \37\\{found};\2\6 +$\\{ww}\K\\{ww}+(\|d\mathbin{\&{mod}}8)-\\{zero\_w}$;\5 +$\|q\K\\{link}(\|q)$;\6 +\&{end};\2\6 +\4\\{found}: \37\X584:Wind up the \\{paint\_row} parameter calculation by +inserting the final transition; \&{goto} \\{done} if no painting is needed\X;% +\par +\U578.\fi + +\M583. Now \|m is a screen column $<\\{right\_col}[\|k]$. + +\Y\P$\4\X583:Record a possible transition in column \|m\X\S$\6 +\&{if} $\|w\L0$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{ww}>0$ \1\&{then}\6 +\&{if} $\|m>\\{min\_col}$ \1\&{then}\6 +\&{begin} \37\&{if} $\|n=0$ \1\&{then}\6 +\&{if} $\\{already\_there}$ \1\&{then}\6 +\&{begin} \37$\|b\K\\{white}$;\5 +$\\{incr}(\|n)$;\6 +\&{end}\6 +\4\&{else} $\|b\K\\{black}$\2\6 +\4\&{else} $\\{incr}(\|n)$;\2\6 +$\\{row\_transition}[\|n]\K\|m$;\6 +\&{end};\2\2\6 +\&{end}\6 +\4\&{else} \&{if} $\\{ww}\L0$ \1\&{then}\6 +\&{if} $\|m>\\{min\_col}$ \1\&{then}\6 +\&{begin} \37\&{if} $\|n=0$ \1\&{then}\5 +$\|b\K\\{black}$;\2\6 +$\\{incr}(\|n)$;\5 +$\\{row\_transition}[\|n]\K\|m$;\6 +\&{end}\2\2\2\par +\U582.\fi + +\M584. If the entire row is \\{white} in the window area, we can omit painting +it +when \\{already\_there} is false, since it has already been blanked out in +that case. + +When the following code is invoked, $\\{row\_transition}[\|n]$ will be +strictly less than $\\{right\_col}[\|k]$. + +\Y\P$\4\X584:Wind up the \\{paint\_row} parameter calculation by inserting the +final transition; \&{goto} \\{done} if no painting is needed\X\S$\6 +\&{if} $\\{already\_there}\V(\\{ww}>0)$ \1\&{then}\6 +\&{begin} \37\&{if} $\|n=0$ \1\&{then}\6 +\&{if} $\\{ww}>0$ \1\&{then}\5 +$\|b\K\\{black}$\6 +\4\&{else} $\|b\K\\{white}$;\2\2\6 +$\\{incr}(\|n)$;\5 +$\\{row\_transition}[\|n]\K\\{right\_col}[\|k]$;\6 +\&{end}\6 +\4\&{else} \&{if} $\|n=0$ \1\&{then}\5 +\&{goto} \37\\{done}\2\2\par +\U582.\fi + +\N585. \[28] Dynamic linear equations. +\MF\ users define variables implicitly by stating equations that should be +satisfied; the computer is supposed to be smart enough to solve those +equations. +And indeed, the computer tries valiantly to do so, by distinguishing five +different types of numeric values: + +\smallskip\hang +$\\{type}(\|p)=\\{known}$ is the nice case, when $\\{value}(\|p)$ is the % +\\{scaled} value +of the variable whose address is~\|p. + +\smallskip\hang +$\\{type}(\|p)=\\{dependent}$ means that $\\{value}(\|p)$ is not present, but $% +\\{dep\_list}(\|p)$ +points to a {\sl dependency list\/} that expresses the value of variable~\|p +as a \\{scaled} number plus a sum of independent variables with \\{fraction} +coefficients. + +\smallskip\hang +$\\{type}(\|p)=\\{independent}$ means that $\\{value}(\|p)=64\|s+\|m$, where $% +\|s>0$ is a ``serial +number'' reflecting the time this variable was first used in an equation; +also $0\L\|m<64$, and each dependent variable +that refers to this one is actually referring to the future value of +this variable times~$2^m$. (Usually $\|m=0$, but higher degrees of +scaling are sometimes needed to keep the coefficients in dependency lists +from getting too large. The value of~\|m will always be even.) + +\smallskip\hang +$\\{type}(\|p)=\\{numeric\_type}$ means that variable \|p hasn't appeared in an +equation before, but it has been explicitly declared to be numeric. + +\smallskip\hang +$\\{type}(\|p)=\\{undefined}$ means that variable \|p hasn't appeared before. + +\smallskip\noindent +We have actually discussed these five types in the reverse order of their +history during a computation: Once \\{known}, a variable never again +becomes \\{dependent}; once \\{dependent}, it almost never again becomes +\\{independent}; once \\{independent}, it never again becomes \\{numeric% +\_type}; +and once \\{numeric\_type}, it never again becomes \\{undefined} (except +of course when the user specifically decides to scrap the old value +and start again). A backward step may, however, take place: Sometimes +a \\{dependent} variable becomes \\{independent} again, when one of the +independent variables it depends on is reverting to \\{undefined}. + +\Y\P\D \37$\\{s\_scale}=64$\C{the serial numbers are multiplied by this factor}% +\par +\P\D \37$\\{new\_indep}(\#)\S$\C{create a new independent variable}\6 +\&{begin} \37$\\{type}(\#)\K\\{independent}$;\5 +$\\{serial\_no}\K\\{serial\_no}+\\{s\_scale}$;\5 +$\\{value}(\#)\K\\{serial\_no}$;\6 +\&{end}\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{serial\_no}: \37\\{integer};\C{the most recent serial number, times \\{s% +\_scale}}\par +\fi + +\M586. \P$\X586:Make variable $\|q+\|s$ newly independent\X\S$\6 +$\\{new\_indep}(\|q+\|s)$\par +\U232.\fi + +\M587. But how are dependency lists represented? It's simple: The linear +combination +$\alpha_1v_1+\cdots+\alpha_kv_k+\beta$ appears in $\|k+1$ value nodes. If +$\|q=\\{dep\_list}(\|p)$ points to this list, and if $\|k>0$, then $\\{value}(% +\|q)=\hbox{$\alpha_1$}$ (which is a \\{fraction}); $\\{info}(\|q)$ points to +the location +of $v_1$; and $\\{link}(\|p)$ points to the dependency list +$\alpha_2v_2+\cdots+\alpha_kv_k+\beta$. On the other hand if $\|k=0$, +then $\\{value}(\|q)=\hbox{$\beta$}$ (which is \\{scaled}) and $\\{info}(\|q)=% +\\{null}$. +The independent variables $v_1$, \dots,~$v_k$ have been sorted so that +they appear in decreasing order of their \\{value} fields (i.e., of +their serial numbers). \ (It is convenient to use decreasing order, +since $\\{value}(\\{null})=0$. If the independent variables were not sorted by +serial number but by some other criterion, such as their location in \\{mem}, +the equation-solving mechanism would be too system-dependent, because +the ordering can affect the computed results.) + +The \\{link} field in the node that contains the constant term $\beta$ is +called the {\sl final link\/} of the dependency list. \MF\ maintains +a doubly-linked master list of all dependency lists, in terms of a permanently +allocated node +in \\{mem} called \\{dep\_head}. If there are no dependencies, we have +$\\{link}(\\{dep\_head})=\\{dep\_head}$ and $\\{prev\_dep}(\\{dep\_head})=% +\\{dep\_head}$; +otherwise $\\{link}(\\{dep\_head})$ points to the first dependent variable, +say~\|p, +and $\\{prev\_dep}(\|p)=\\{dep\_head}$. We have $\\{type}(\|p)=\\{dependent}$, +and $\\{dep\_list}(\|p)$ +points to its dependency list. If the final link of that dependency list +occurs in location~\|q, then $\\{link}(\|q)$ points to the next dependent +variable (say~\|r); and we have $\\{prev\_dep}(\|r)=\|q$, etc. + +\Y\P\D \37$\\{dep\_list}(\#)\S\\{link}(\\{value\_loc}(\#))$\C{half of the % +\\{value} field in a \\{dependent} variable}\par +\P\D \37$\\{prev\_dep}(\#)\S\\{info}(\\{value\_loc}(\#))$\C{the other half; +makes a doubly linked list}\par +\P\D \37$\\{dep\_node\_size}=2$\C{the number of words per dependency node}\par +\Y\P$\4\X176:Initialize table entries (done by \.{INIMF} only)\X\mathrel{+}\S$\6 +$\\{serial\_no}\K0$;\5 +$\\{link}(\\{dep\_head})\K\\{dep\_head}$;\5 +$\\{prev\_dep}(\\{dep\_head})\K\\{dep\_head}$;\5 +$\\{info}(\\{dep\_head})\K\\{null}$;\5 +$\\{dep\_list}(\\{dep\_head})\K\\{null}$;\par +\fi + +\M588. Actually the description above contains a little white lie. There's +another kind of variable called \\{proto\_dependent}, which is +just like a \\{dependent} one except that the $\alpha$ coefficients +in its dependency list are \\{scaled} instead of being fractions. +Proto-dependency lists are mixed with dependency lists in the +nodes reachable from \\{dep\_head}. + +\fi + +\M589. Here is a procedure that prints a dependency list in symbolic form. +The second parameter should be either \\{dependent} or \\{proto\_dependent}, +to indicate the scaling of the coefficients. + +\Y\P$\4\X257:Declare subroutines for printing expressions\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{print\_dependency}(\|p:\\{pointer};\,\35\|t:\\{small% +\_number})$;\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37\|v: \37\\{integer};\C{a coefficient}\6 +$\\{pp},\39\|q$: \37\\{pointer};\C{for list manipulation}\2\6 +\&{begin} \37$\\{pp}\K\|p$;\6 +\~ \1\&{loop}\ \&{begin} \37$\|v\K\\{abs}(\\{value}(\|p))$;\5 +$\|q\K\\{info}(\|p)$;\6 +\&{if} $\|q=\\{null}$ \1\&{then}\C{the constant term}\6 +\&{begin} \37\&{if} $(\|v\I0)\V(\|p=\\{pp})$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{value}(\|p)>0$ \1\&{then}\6 +\&{if} $\|p\I\\{pp}$ \1\&{then}\5 +$\\{print\_char}(\.{"+"})$;\2\2\6 +$\\{print\_scaled}(\\{value}(\|p))$;\6 +\&{end};\2\6 +\&{return};\6 +\&{end};\2\6 +\X590:Print the coefficient, unless it's $\pm1.0$\X;\6 +\&{if} $\\{type}(\|q)\I\\{independent}$ \1\&{then}\5 +$\\{confusion}(\.{"dep"})$;\2\6 +$\\{print\_variable\_name}(\|q)$;\5 +$\|v\K\\{value}(\|q)\mathbin{\&{mod}}\\{s\_scale}$;\6 +\&{while} $\|v>0$ \1\&{do}\6 +\&{begin} \37$\\{print}(\.{"*4"})$;\5 +$\|v\K\|v-2$;\6 +\&{end};\2\6 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M590. \P$\X590:Print the coefficient, unless it's $\pm1.0$\X\S$\6 +\&{if} $\\{value}(\|p)<0$ \1\&{then}\5 +$\\{print\_char}(\.{"-"})$\6 +\4\&{else} \&{if} $\|p\I\\{pp}$ \1\&{then}\5 +$\\{print\_char}(\.{"+"})$;\2\2\6 +\&{if} $\|t=\\{dependent}$ \1\&{then}\5 +$\|v\K\\{round\_fraction}(\|v)$;\2\6 +\&{if} $\|v\I\\{unity}$ \1\&{then}\5 +$\\{print\_scaled}(\|v)$\2\par +\U589.\fi + +\M591. The maximum absolute value of a coefficient in a given dependency list +is returned by the following simple function. + +\Y\P\4\&{function}\1\ \37$\\{max\_coef}(\|p:\\{pointer})$: \37\\{fraction};\6 +\4\&{var} \37\|x: \37\\{fraction};\C{the maximum so far}\2\6 +\&{begin} \37$\|x\K0$;\6 +\&{while} $\\{info}(\|p)\I\\{null}$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{abs}(\\{value}(\|p))>\|x$ \1\&{then}\5 +$\|x\K\\{abs}(\\{value}(\|p))$;\2\6 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +$\\{max\_coef}\K\|x$;\6 +\&{end};\par +\fi + +\M592. One of the main operations needed on dependency lists is to add a +multiple +of one list to the other; we call this \\{p\_plus\_fq}, where \|p and~\|q point +to dependency lists and \|f is a fraction. + +If the coefficient of any independent variable becomes \\{coef\_bound} or +more, in absolute value, this procedure changes the type of that variable +to `\\{independent\_needing\_fix}', and sets the global variable \\{fix% +\_needed} +to~\\{true}. The value of $\\{coef\_bound}=\mu$ is chosen so that +$\mu^2+\mu<8$; this means that the numbers we deal with won't +get too large. (Instead of the ``optimum'' $\mu=(\sqrt{33}-1)/2\approx +2.3723$, the safer value 7/3 is taken as the threshold.) + +The changes mentioned in the preceding paragraph are actually done only if +the global variable \\{watch\_coefs} is \\{true}. But it usually is; in fact, +it is \\{false} only when \MF\ is making a dependency list that will soon +be equated to zero. + +Several procedures that act on dependency lists, including \\{p\_plus\_fq}, +set the global variable \\{dep\_final} to the final (constant term) node of +the dependency list that they produce. + +\Y\P\D \37$\\{coef\_bound}\S\O{4525252525}$\C{\\{fraction} approximation to +7/3}\par +\P\D \37$\\{independent\_needing\_fix}=0$\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{fix\_needed}: \37\\{boolean};\C{does at least one \\{independent} variable +need scaling?}\6 +\4\\{watch\_coefs}: \37\\{boolean};\C{should we scale coefficients that exceed % +\\{coef\_bound}?}\6 +\4\\{dep\_final}: \37\\{pointer};\C{location of the constant term and final +link}\par +\fi + +\M593. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{fix\_needed}\K\\{false}$;\5 +$\\{watch\_coefs}\K\\{true}$;\par +\fi + +\M594. The \\{p\_plus\_fq} procedure has a fourth parameter, \|t, that should +be +set to \\{proto\_dependent} if \|p is a proto-dependency list. In this +case \|f will be \\{scaled}, not a \\{fraction}. Similarly, the fifth +parameter~\\{tt} +should be \\{proto\_dependent} if \|q is a proto-dependency list. + +List \|q is unchanged by the operation; but list \|p is totally destroyed. + +The final link of the dependency list or proto-dependency list returned +by \\{p\_plus\_fq} is the same as the original final link of~\|p. Indeed, the +constant term of the result will be located in the same \\{mem} location +as the original constant term of~\|p. + +Coefficients of the result are assumed to be zero if they are less than +a certain threshold. This compensates for inevitable rounding errors, +and tends to make more variables `\\{known}'. The threshold is approximately +$10^{-5}$ in the case of normal dependency lists, $10^{-4}$ for +proto-dependencies. + +\Y\P\D \37$\\{fraction\_threshold}=2685$\C{a \\{fraction} coefficient less than +this is zeroed}\par +\P\D \37$\\{half\_fraction\_threshold}=1342$\C{half of \\{fraction\_threshold}}% +\par +\P\D \37$\\{scaled\_threshold}=8$\C{a \\{scaled} coefficient less than this is +zeroed}\par +\P\D \37$\\{half\_scaled\_threshold}=4$\C{half of \\{scaled\_threshold}}\par +\Y\P$\4\X594:Declare basic dependency-list subroutines\X\S$\6 +\4\&{function}\1\ \37$\\{p\_plus\_fq}(\|p:\\{pointer};\,\35\|f:\\{integer};\,% +\35\|q:\\{pointer};\,\35\|t,\39\\{tt}:\\{small\_number})$: \37\\{pointer};\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37$\\{pp},\39\\{qq}$: \37\\{pointer};\C{$\\{info}(\|p)$ and $% +\\{info}(\|q)$, respectively}\6 +$\|r,\39\|s$: \37\\{pointer};\C{for list manipulation}\6 +\\{threshold}: \37\\{integer};\C{defines a neighborhood of zero}\6 +\|v: \37\\{integer};\C{temporary register}\2\6 +\&{begin} \37\&{if} $\|t=\\{dependent}$ \1\&{then}\5 +$\\{threshold}\K\\{fraction\_threshold}$\6 +\4\&{else} $\\{threshold}\K\\{scaled\_threshold}$;\2\6 +$\|r\K\\{temp\_head}$;\5 +$\\{pp}\K\\{info}(\|p)$;\5 +$\\{qq}\K\\{info}(\|q)$;\6 +\~ \1\&{loop}\ \&{if} $\\{pp}=\\{qq}$ \1\&{then}\6 +\&{if} $\\{pp}=\\{null}$ \1\&{then}\5 +\&{goto} \37\\{done}\6 +\4\&{else} \X595:Contribute a term from \|p, plus \|f times the corresponding +term from \|q\X\2\6 +\4\&{else} \&{if} $\\{value}(\\{pp})<\\{value}(\\{qq})$ \1\&{then}\5 +\X596:Contribute a term from \|q, multiplied by~\|f\X\6 +\4\&{else} \&{begin} \37$\\{link}(\|r)\K\|p$;\5 +$\|r\K\|p$;\5 +$\|p\K\\{link}(\|p)$;\5 +$\\{pp}\K\\{info}(\|p)$;\6 +\&{end};\2\2\2\6 +\4\\{done}: \37\&{if} $\|t=\\{dependent}$ \1\&{then}\5 +$\\{value}(\|p)\K\\{slow\_add}(\\{value}(\|p),\39\\{take\_fraction}(\\{value}(% +\|q),\39\|f))$\6 +\4\&{else} $\\{value}(\|p)\K\\{slow\_add}(\\{value}(\|p),\39\\{take\_scaled}(% +\\{value}(\|q),\39\|f))$;\2\6 +$\\{link}(\|r)\K\|p$;\5 +$\\{dep\_final}\K\|p$;\5 +$\\{p\_plus\_fq}\K\\{link}(\\{temp\_head})$;\6 +\&{end};\par +\As600, 602, 603\ETs604. +\U246.\fi + +\M595. \P$\X595:Contribute a term from \|p, plus \|f times the corresponding +term from \|q\X\S$\6 +\&{begin} \37\&{if} $\\{tt}=\\{dependent}$ \1\&{then}\5 +$\|v\K\\{value}(\|p)+\\{take\_fraction}(\|f,\39\\{value}(\|q))$\6 +\4\&{else} $\|v\K\\{value}(\|p)+\\{take\_scaled}(\|f,\39\\{value}(\|q))$;\2\6 +$\\{value}(\|p)\K\|v$;\5 +$\|s\K\|p$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{if} $\\{abs}(\|v)<\\{threshold}$ \1\&{then}\5 +$\\{free\_node}(\|s,\39\\{dep\_node\_size})$\6 +\4\&{else} \&{begin} \37\&{if} $\\{abs}(\|v)\G\\{coef\_bound}$ \1\&{then}\6 +\&{if} $\\{watch\_coefs}$ \1\&{then}\6 +\&{begin} \37$\\{type}(\\{qq})\K\\{independent\_needing\_fix}$;\5 +$\\{fix\_needed}\K\\{true}$;\6 +\&{end};\2\2\6 +$\\{link}(\|r)\K\|s$;\5 +$\|r\K\|s$;\6 +\&{end};\2\6 +$\\{pp}\K\\{info}(\|p)$;\5 +$\|q\K\\{link}(\|q)$;\5 +$\\{qq}\K\\{info}(\|q)$;\6 +\&{end}\par +\U594.\fi + +\M596. \P$\X596:Contribute a term from \|q, multiplied by~\|f\X\S$\6 +\&{begin} \37\&{if} $\\{tt}=\\{dependent}$ \1\&{then}\5 +$\|v\K\\{take\_fraction}(\|f,\39\\{value}(\|q))$\6 +\4\&{else} $\|v\K\\{take\_scaled}(\|f,\39\\{value}(\|q))$;\2\6 +\&{if} $\\{abs}(\|v)>\\{half}(\\{threshold})$ \1\&{then}\6 +\&{begin} \37$\|s\K\\{get\_node}(\\{dep\_node\_size})$;\5 +$\\{info}(\|s)\K\\{qq}$;\5 +$\\{value}(\|s)\K\|v$;\6 +\&{if} $\\{abs}(\|v)\G\\{coef\_bound}$ \1\&{then}\6 +\&{if} $\\{watch\_coefs}$ \1\&{then}\6 +\&{begin} \37$\\{type}(\\{qq})\K\\{independent\_needing\_fix}$;\5 +$\\{fix\_needed}\K\\{true}$;\6 +\&{end};\2\2\6 +$\\{link}(\|r)\K\|s$;\5 +$\|r\K\|s$;\6 +\&{end};\2\6 +$\|q\K\\{link}(\|q)$;\5 +$\\{qq}\K\\{info}(\|q)$;\6 +\&{end}\par +\U594.\fi + +\M597. It is convenient to have another subroutine for the special case +of \\{p\_plus\_fq} when $\|f=1.0$. In this routine lists \|p and \|q are +both of the same type~\|t (either \\{dependent} or \\{proto\_dependent}). + +\Y\P\4\&{function}\1\ \37$\\{p\_plus\_q}(\|p:\\{pointer};\,\35\|q:\\{pointer};% +\,\35\|t:\\{small\_number})$: \37\\{pointer};\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37$\\{pp},\39\\{qq}$: \37\\{pointer};\C{$\\{info}(\|p)$ and $% +\\{info}(\|q)$, respectively}\6 +$\|r,\39\|s$: \37\\{pointer};\C{for list manipulation}\6 +\\{threshold}: \37\\{integer};\C{defines a neighborhood of zero}\6 +\|v: \37\\{integer};\C{temporary register}\2\6 +\&{begin} \37\&{if} $\|t=\\{dependent}$ \1\&{then}\5 +$\\{threshold}\K\\{fraction\_threshold}$\6 +\4\&{else} $\\{threshold}\K\\{scaled\_threshold}$;\2\6 +$\|r\K\\{temp\_head}$;\5 +$\\{pp}\K\\{info}(\|p)$;\5 +$\\{qq}\K\\{info}(\|q)$;\6 +\~ \1\&{loop}\ \&{if} $\\{pp}=\\{qq}$ \1\&{then}\6 +\&{if} $\\{pp}=\\{null}$ \1\&{then}\5 +\&{goto} \37\\{done}\6 +\4\&{else} \X598:Contribute a term from \|p, plus the corresponding term from % +\|q\X\2\6 +\4\&{else} \&{if} $\\{value}(\\{pp})<\\{value}(\\{qq})$ \1\&{then}\6 +\&{begin} \37$\|s\K\\{get\_node}(\\{dep\_node\_size})$;\5 +$\\{info}(\|s)\K\\{qq}$;\5 +$\\{value}(\|s)\K\\{value}(\|q)$;\5 +$\|q\K\\{link}(\|q)$;\5 +$\\{qq}\K\\{info}(\|q)$;\5 +$\\{link}(\|r)\K\|s$;\5 +$\|r\K\|s$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{link}(\|r)\K\|p$;\5 +$\|r\K\|p$;\5 +$\|p\K\\{link}(\|p)$;\5 +$\\{pp}\K\\{info}(\|p)$;\6 +\&{end};\2\2\2\6 +\4\\{done}: \37$\\{value}(\|p)\K\\{slow\_add}(\\{value}(\|p),\39\\{value}(% +\|q))$;\5 +$\\{link}(\|r)\K\|p$;\5 +$\\{dep\_final}\K\|p$;\5 +$\\{p\_plus\_q}\K\\{link}(\\{temp\_head})$;\6 +\&{end};\par +\fi + +\M598. \P$\X598:Contribute a term from \|p, plus the corresponding term from % +\|q\X\S$\6 +\&{begin} \37$\|v\K\\{value}(\|p)+\\{value}(\|q)$;\5 +$\\{value}(\|p)\K\|v$;\5 +$\|s\K\|p$;\5 +$\|p\K\\{link}(\|p)$;\5 +$\\{pp}\K\\{info}(\|p)$;\6 +\&{if} $\\{abs}(\|v)<\\{threshold}$ \1\&{then}\5 +$\\{free\_node}(\|s,\39\\{dep\_node\_size})$\6 +\4\&{else} \&{begin} \37\&{if} $\\{abs}(\|v)\G\\{coef\_bound}$ \1\&{then}\6 +\&{if} $\\{watch\_coefs}$ \1\&{then}\6 +\&{begin} \37$\\{type}(\\{qq})\K\\{independent\_needing\_fix}$;\5 +$\\{fix\_needed}\K\\{true}$;\6 +\&{end};\2\2\6 +$\\{link}(\|r)\K\|s$;\5 +$\|r\K\|s$;\6 +\&{end};\2\6 +$\|q\K\\{link}(\|q)$;\5 +$\\{qq}\K\\{info}(\|q)$;\6 +\&{end}\par +\U597.\fi + +\M599. A somewhat simpler routine will multiply a dependency list +by a given constant~\|v. The constant is either a \\{fraction} less than +\\{fraction\_one}, or it is \\{scaled}. In the latter case we might be forced +to +convert a dependency list to a proto-dependency list. +Parameters \\{t0} and \\{t1} are the list types before and after; +they should agree unless $\\{t0}=\\{dependent}$ and $\\{t1}=\\{proto% +\_dependent}$ +and $\\{v\_is\_scaled}=\\{true}$. + +\Y\P\4\&{function}\1\ \37$\\{p\_times\_v}(\|p:\\{pointer};\,\35\|v:% +\\{integer};\,\35\\{t0},\39\\{t1}:\\{small\_number};\,\35\\{v\_is\_scaled}:% +\\{boolean})$: \37\\{pointer};\6 +\4\&{var} \37$\|r,\39\|s$: \37\\{pointer};\C{for list manipulation}\6 +\|w: \37\\{integer};\C{tentative coefficient}\6 +\\{threshold}: \37\\{integer};\5 +\\{scaling\_down}: \37\\{boolean};\2\6 +\&{begin} \37\&{if} $\\{t0}\I\\{t1}$ \1\&{then}\5 +$\\{scaling\_down}\K\\{true}$\ \&{else} $\\{scaling\_down}\K\R\\{v\_is% +\_scaled}$;\2\6 +\&{if} $\\{t1}=\\{dependent}$ \1\&{then}\5 +$\\{threshold}\K\\{half\_fraction\_threshold}$\6 +\4\&{else} $\\{threshold}\K\\{half\_scaled\_threshold}$;\2\6 +$\|r\K\\{temp\_head}$;\6 +\&{while} $\\{info}(\|p)\I\\{null}$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{scaling\_down}$ \1\&{then}\5 +$\|w\K\\{take\_fraction}(\|v,\39\\{value}(\|p))$\6 +\4\&{else} $\|w\K\\{take\_scaled}(\|v,\39\\{value}(\|p))$;\2\6 +\&{if} $\\{abs}(\|w)\L\\{threshold}$ \1\&{then}\6 +\&{begin} \37$\|s\K\\{link}(\|p)$;\5 +$\\{free\_node}(\|p,\39\\{dep\_node\_size})$;\5 +$\|p\K\|s$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37\&{if} $\\{abs}(\|w)\G\\{coef\_bound}$ \1\&{then}\6 +\&{begin} \37$\\{fix\_needed}\K\\{true}$;\5 +$\\{type}(\\{info}(\|p))\K\\{independent\_needing\_fix}$;\6 +\&{end};\2\6 +$\\{link}(\|r)\K\|p$;\5 +$\|r\K\|p$;\5 +$\\{value}(\|p)\K\|w$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +\&{end};\2\6 +$\\{link}(\|r)\K\|p$;\6 +\&{if} $\\{v\_is\_scaled}$ \1\&{then}\5 +$\\{value}(\|p)\K\\{take\_scaled}(\\{value}(\|p),\39\|v)$\6 +\4\&{else} $\\{value}(\|p)\K\\{take\_fraction}(\\{value}(\|p),\39\|v)$;\2\6 +$\\{p\_times\_v}\K\\{link}(\\{temp\_head})$;\6 +\&{end};\par +\fi + +\M600. Similarly, we sometimes need to divide a dependency list +by a given \\{scaled} constant. + +\Y\P$\4\X594:Declare basic dependency-list subroutines\X\mathrel{+}\S$\6 +\4\&{function}\1\ \37$\\{p\_over\_v}(\|p:\\{pointer};\,\35\|v:\\{scaled};\,\35% +\\{t0},\39\\{t1}:\\{small\_number})$: \37\\{pointer};\6 +\4\&{var} \37$\|r,\39\|s$: \37\\{pointer};\C{for list manipulation}\6 +\|w: \37\\{integer};\C{tentative coefficient}\6 +\\{threshold}: \37\\{integer};\5 +\\{scaling\_down}: \37\\{boolean};\2\6 +\&{begin} \37\&{if} $\\{t0}\I\\{t1}$ \1\&{then}\5 +$\\{scaling\_down}\K\\{true}$\ \&{else} $\\{scaling\_down}\K\\{false}$;\2\6 +\&{if} $\\{t1}=\\{dependent}$ \1\&{then}\5 +$\\{threshold}\K\\{half\_fraction\_threshold}$\6 +\4\&{else} $\\{threshold}\K\\{half\_scaled\_threshold}$;\2\6 +$\|r\K\\{temp\_head}$;\6 +\&{while} $\\{info}(\|p)\I\\{null}$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{scaling\_down}$ \1\&{then}\6 +\&{if} $\\{abs}(\|v)<\O{2000000}$ \1\&{then}\5 +$\|w\K\\{make\_scaled}(\\{value}(\|p),\39\|v\ast\O{10000})$\6 +\4\&{else} $\|w\K\\{make\_scaled}(\\{round\_fraction}(\\{value}(\|p)),\39\|v)$% +\2\6 +\4\&{else} $\|w\K\\{make\_scaled}(\\{value}(\|p),\39\|v)$;\2\6 +\&{if} $\\{abs}(\|w)\L\\{threshold}$ \1\&{then}\6 +\&{begin} \37$\|s\K\\{link}(\|p)$;\5 +$\\{free\_node}(\|p,\39\\{dep\_node\_size})$;\5 +$\|p\K\|s$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37\&{if} $\\{abs}(\|w)\G\\{coef\_bound}$ \1\&{then}\6 +\&{begin} \37$\\{fix\_needed}\K\\{true}$;\5 +$\\{type}(\\{info}(\|p))\K\\{independent\_needing\_fix}$;\6 +\&{end};\2\6 +$\\{link}(\|r)\K\|p$;\5 +$\|r\K\|p$;\5 +$\\{value}(\|p)\K\|w$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +\&{end};\2\6 +$\\{link}(\|r)\K\|p$;\5 +$\\{value}(\|p)\K\\{make\_scaled}(\\{value}(\|p),\39\|v)$;\5 +$\\{p\_over\_v}\K\\{link}(\\{temp\_head})$;\6 +\&{end};\par +\fi + +\M601. Here's another utility routine for dependency lists. When an independent +variable becomes dependent, we want to remove it from all existing +dependencies. The \\{p\_with\_x\_becoming\_q} function computes the +dependency list of~\|p after variable~\|x has been replaced by~\|q. + +This procedure has basically the same calling conventions as \\{p\_plus\_fq}: +List~\|q is unchanged; list~\|p is destroyed; the constant node and the +final link are inherited from~\|p; and the fourth parameter tells whether +or not \|p is \\{proto\_dependent}. However, the global variable \\{dep\_final} +is not altered if \|x does not occur in list~\|p. + +\Y\P\4\&{function}\1\ \37$\\{p\_with\_x\_becoming\_q}(\|p,\39\|x,\39\|q:% +\\{pointer};\,\35\|t:\\{small\_number})$: \37\\{pointer};\6 +\4\&{var} \37$\|r,\39\|s$: \37\\{pointer};\C{for list manipulation}\6 +\|v: \37\\{integer};\C{coefficient of \|x}\6 +\\{sx}: \37\\{integer};\C{serial number of \|x}\2\6 +\&{begin} \37$\|s\K\|p$;\5 +$\|r\K\\{temp\_head}$;\5 +$\\{sx}\K\\{value}(\|x)$;\6 +\&{while} $\\{value}(\\{info}(\|s))>\\{sx}$ \1\&{do}\6 +\&{begin} \37$\|r\K\|s$;\5 +$\|s\K\\{link}(\|s)$;\6 +\&{end};\2\6 +\&{if} $\\{info}(\|s)\I\|x$ \1\&{then}\5 +$\\{p\_with\_x\_becoming\_q}\K\|p$\6 +\4\&{else} \&{begin} \37$\\{link}(\\{temp\_head})\K\|p$;\5 +$\\{link}(\|r)\K\\{link}(\|s)$;\5 +$\|v\K\\{value}(\|s)$;\5 +$\\{free\_node}(\|s,\39\\{dep\_node\_size})$;\5 +$\\{p\_with\_x\_becoming\_q}\K\\{p\_plus\_fq}(\\{link}(\\{temp\_head}),\39\|v,% +\39\|q,\39\|t,\39\\{dependent})$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M602. Here's a simple procedure that reports an error when a variable +has just received a known value that's out of the required range. + +\Y\P$\4\X594:Declare basic dependency-list subroutines\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{val\_too\_big}(\|x:\\{scaled})$;\2\6 +\&{begin} \37\&{if} $\\{internal}[\\{warning\_check}]>0$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"Value\ is\ too\ large\ ("})$;\5 +$\\{print\_scaled}(\|x)$;\5 +$\\{print\_char}(\.{")"})$;\5 +$\\{help4}(\.{"The\ equation\ I\ just\ processed\ has\ given\ some\ +variable"})$\6 +$(\.{"a\ value\ of\ 4096\ or\ more.\ Continue\ and\ I\'ll\ try\ to\ cope"})$\6 +$(\.{"with\ that\ big\ value;\ but\ it\ might\ be\ dangerous."})$\6 +$(\.{"(Set\ warningcheck:=0\ to\ suppress\ this\ message.)"})$;\5 +\\{error};\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M603. When a dependent variable becomes known, the following routine +removes its dependency list. Here \|p points to the variable, and +\|q points to the dependency list (which is one node long). + +\Y\P$\4\X594:Declare basic dependency-list subroutines\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{make\_known}(\|p,\39\|q:\\{pointer})$;\6 +\4\&{var} \37\|t: \37$\\{dependent}\to\\{proto\_dependent}$;\C{the previous +type}\2\6 +\&{begin} \37$\\{prev\_dep}(\\{link}(\|q))\K\\{prev\_dep}(\|p)$;\5 +$\\{link}(\\{prev\_dep}(\|p))\K\\{link}(\|q)$;\5 +$\|t\K\\{type}(\|p)$;\5 +$\\{type}(\|p)\K\\{known}$;\5 +$\\{value}(\|p)\K\\{value}(\|q)$;\5 +$\\{free\_node}(\|q,\39\\{dep\_node\_size})$;\6 +\&{if} $\\{abs}(\\{value}(\|p))\G\\{fraction\_one}$ \1\&{then}\5 +$\\{val\_too\_big}(\\{value}(\|p))$;\2\6 +\&{if} $\\{internal}[\\{tracing\_equations}]>0$ \1\&{then}\6 +\&{if} $\\{interesting}(\|p)$ \1\&{then}\6 +\&{begin} \37\\{begin\_diagnostic};\5 +$\\{print\_nl}(\.{"\#\#\#\#\ "})$;\5 +$\\{print\_variable\_name}(\|p)$;\5 +$\\{print\_char}(\.{"="})$;\5 +$\\{print\_scaled}(\\{value}(\|p))$;\5 +$\\{end\_diagnostic}(\\{false})$;\6 +\&{end};\2\2\6 +\&{if} $\\{cur\_exp}=\|p$ \1\&{then}\6 +\&{if} $\\{cur\_type}=\|t$ \1\&{then}\6 +\&{begin} \37$\\{cur\_type}\K\\{known}$;\5 +$\\{cur\_exp}\K\\{value}(\|p)$;\5 +$\\{free\_node}(\|p,\39\\{value\_node\_size})$;\6 +\&{end};\2\2\6 +\&{end};\par +\fi + +\M604. The \\{fix\_dependencies} routine is called into action when \\{fix% +\_needed} +has been triggered. The program keeps a list~\|s of independent variables +whose coefficients must be divided by~4. + +In unusual cases, this fixup process might reduce one or more coefficients +to zero, so that a variable will become known more or less by default. + +\Y\P$\4\X594:Declare basic dependency-list subroutines\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{fix\_dependencies};\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37$\|p,\39\|q,\39\|r,\39\|s,\39\|t$: \37\\{pointer};\C{list +manipulation registers}\6 +\|x: \37\\{pointer};\C{an independent variable}\2\6 +\&{begin} \37$\|r\K\\{link}(\\{dep\_head})$;\5 +$\|s\K\\{null}$;\6 +\&{while} $\|r\I\\{dep\_head}$ \1\&{do}\6 +\&{begin} \37$\|t\K\|r$;\5 +\X605:Run through the dependency list for variable \|t, fixing all nodes, and +ending with final link~\|q\X;\6 +$\|r\K\\{link}(\|q)$;\6 +\&{if} $\|q=\\{dep\_list}(\|t)$ \1\&{then}\5 +$\\{make\_known}(\|t,\39\|q)$;\2\6 +\&{end};\2\6 +\&{while} $\|s\I\\{null}$ \1\&{do}\6 +\&{begin} \37$\|p\K\\{link}(\|s)$;\5 +$\|x\K\\{info}(\|s)$;\5 +$\\{free\_avail}(\|s)$;\5 +$\|s\K\|p$;\5 +$\\{type}(\|x)\K\\{independent}$;\5 +$\\{value}(\|x)\K\\{value}(\|x)+2$;\6 +\&{end};\2\6 +$\\{fix\_needed}\K\\{false}$;\6 +\&{end};\par +\fi + +\M605. \P\D \37$\\{independent\_being\_fixed}=1$\C{this variable already +appears in \|s}\par +\Y\P$\4\X605:Run through the dependency list for variable \|t, fixing all +nodes, and ending with final link~\|q\X\S$\6 +$\|r\K\\{value\_loc}(\|t)$;\C{$\\{link}(\|r)=\\{dep\_list}(\|t)$}\6 +\~ \1\&{loop}\ \&{begin} \37$\|q\K\\{link}(\|r)$;\5 +$\|x\K\\{info}(\|q)$;\6 +\&{if} $\|x=\\{null}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +\&{if} $\\{type}(\|x)\L\\{independent\_being\_fixed}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{type}(\|x)<\\{independent\_being\_fixed}$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{get\_avail}$;\5 +$\\{link}(\|p)\K\|s$;\5 +$\|s\K\|p$;\5 +$\\{info}(\|s)\K\|x$;\5 +$\\{type}(\|x)\K\\{independent\_being\_fixed}$;\6 +\&{end};\2\6 +$\\{value}(\|q)\K\\{value}(\|q)\mathbin{\&{div}}4$;\6 +\&{if} $\\{value}(\|q)=0$ \1\&{then}\6 +\&{begin} \37$\\{link}(\|r)\K\\{link}(\|q)$;\5 +$\\{free\_node}(\|q,\39\\{dep\_node\_size})$;\5 +$\|q\K\|r$;\6 +\&{end};\2\6 +\&{end};\2\6 +$\|r\K\|q$;\6 +\&{end};\2\6 +\4\\{done}: \37\par +\U604.\fi + +\M606. The \\{new\_dep} routine installs a dependency list~\|p into the value +node~\|q, +linking it into the list of all known dependencies. We assume that +\\{dep\_final} points to the final node of list~\|p. + +\Y\P\4\&{procedure}\1\ \37$\\{new\_dep}(\|q,\39\|p:\\{pointer})$;\6 +\4\&{var} \37\|r: \37\\{pointer};\C{what used to be the first dependency}\2\6 +\&{begin} \37$\\{dep\_list}(\|q)\K\|p$;\5 +$\\{prev\_dep}(\|q)\K\\{dep\_head}$;\5 +$\|r\K\\{link}(\\{dep\_head})$;\5 +$\\{link}(\\{dep\_final})\K\|r$;\5 +$\\{prev\_dep}(\|r)\K\\{dep\_final}$;\5 +$\\{link}(\\{dep\_head})\K\|q$;\6 +\&{end};\par +\fi + +\M607. Here is one of the ways a dependency list gets started. +The \\{const\_dependency} routine produces a list that has nothing but +a constant term. + +\Y\P\4\&{function}\1\ \37$\\{const\_dependency}(\|v:\\{scaled})$: \37% +\\{pointer};\2\6 +\&{begin} \37$\\{dep\_final}\K\\{get\_node}(\\{dep\_node\_size})$;\5 +$\\{value}(\\{dep\_final})\K\|v$;\5 +$\\{info}(\\{dep\_final})\K\\{null}$;\5 +$\\{const\_dependency}\K\\{dep\_final}$;\6 +\&{end};\par +\fi + +\M608. And here's a more interesting way to start a dependency list from +scratch: +The parameter to \\{single\_dependency} is the location of an +independent variable~\|x, and the result is the simple dependency list +`$\|x+0$'. + +In the unlikely event that the given independent variable has been doubled so +often that we can't refer to it with a nonzero coefficient, +\\{single\_dependency} returns the simple list `0'. This case can be +recognized by testing that the returned list pointer is equal to +\\{dep\_final}. + +\Y\P\4\&{function}\1\ \37$\\{single\_dependency}(\|p:\\{pointer})$: \37% +\\{pointer};\6 +\4\&{var} \37\|q: \37\\{pointer};\C{the new dependency list}\6 +\|m: \37\\{integer};\C{the number of doublings}\2\6 +\&{begin} \37$\|m\K\\{value}(\|p)\mathbin{\&{mod}}\\{s\_scale}$;\6 +\&{if} $\|m>28$ \1\&{then}\5 +$\\{single\_dependency}\K\\{const\_dependency}(0)$\6 +\4\&{else} \&{begin} \37$\|q\K\\{get\_node}(\\{dep\_node\_size})$;\5 +$\\{value}(\|q)\K\\{two\_to\_the}[28-\|m]$;\5 +$\\{info}(\|q)\K\|p$;\6 +$\\{link}(\|q)\K\\{const\_dependency}(0)$;\5 +$\\{single\_dependency}\K\|q$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M609. We sometimes need to make an exact copy of a dependency list. + +\Y\P\4\&{function}\1\ \37$\\{copy\_dep\_list}(\|p:\\{pointer})$: \37% +\\{pointer};\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37\|q: \37\\{pointer};\C{the new dependency list}\2\6 +\&{begin} \37$\|q\K\\{get\_node}(\\{dep\_node\_size})$;\5 +$\\{dep\_final}\K\|q$;\6 +\~ \1\&{loop}\ \&{begin} \37$\\{info}(\\{dep\_final})\K\\{info}(\|p)$;\5 +$\\{value}(\\{dep\_final})\K\\{value}(\|p)$;\6 +\&{if} $\\{info}(\\{dep\_final})=\\{null}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\\{link}(\\{dep\_final})\K\\{get\_node}(\\{dep\_node\_size})$;\5 +$\\{dep\_final}\K\\{link}(\\{dep\_final})$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +\4\\{done}: \37$\\{copy\_dep\_list}\K\|q$;\6 +\&{end};\par +\fi + +\M610. But how do variables normally become known? Ah, now we get to the heart +of the +equation-solving mechanism. The \\{linear\_eq} procedure is given a % +\\{dependent} +or \\{proto\_dependent} list,~\|p, in which at least one independent variable +appears. It equates this list to zero, by choosing an independent variable +with the largest coefficient and making it dependent on the others. The +newly dependent variable is eliminated from all current dependencies, +thereby possibly making other dependent variables known. + +The given list \|p is, of course, totally destroyed by all this processing. + +\Y\P\4\&{procedure}\1\ \37$\\{linear\_eq}(\|p:\\{pointer};\,\35\|t:\\{small% +\_number})$;\6 +\4\&{var} \37$\|q,\39\|r,\39\|s$: \37\\{pointer};\C{for link manipulation}\6 +\|x: \37\\{pointer};\C{the variable that loses its independence}\6 +\|n: \37\\{integer};\C{the number of times \|x had been halved}\6 +\|v: \37\\{integer};\C{the coefficient of \|x in list \|p}\6 +\\{prev\_r}: \37\\{pointer};\C{lags one step behind \|r}\6 +\\{final\_node}: \37\\{pointer};\C{the constant term of the new dependency +list}\6 +\|w: \37\\{integer};\C{a tentative coefficient}\2\6 +\&{begin} \37\X611:Find a node \|q in list \|p whose coefficient \|v is largest% +\X;\6 +$\|x\K\\{info}(\|q)$;\5 +$\|n\K\\{value}(\|x)\mathbin{\&{mod}}\\{s\_scale}$;\6 +\X612:Divide list \|p by $-\|v$, removing node \|q\X;\6 +\&{if} $\\{internal}[\\{tracing\_equations}]>0$ \1\&{then}\5 +\X613:Display the new dependency\X;\2\6 +\X614:Simplify all existing dependencies by substituting for \|x\X;\6 +\X615:Change variable \|x from \\{independent} to \\{dependent} or \\{known}\X;% +\6 +\&{if} $\\{fix\_needed}$ \1\&{then}\5 +\\{fix\_dependencies};\2\6 +\&{end};\par +\fi + +\M611. \P$\X611:Find a node \|q in list \|p whose coefficient \|v is largest\X% +\S$\6 +$\|q\K\|p$;\5 +$\|r\K\\{link}(\|p)$;\5 +$\|v\K\\{value}(\|q)$;\6 +\&{while} $\\{info}(\|r)\I\\{null}$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{abs}(\\{value}(\|r))>\\{abs}(\|v)$ \1\&{then}\6 +\&{begin} \37$\|q\K\|r$;\5 +$\|v\K\\{value}(\|r)$;\6 +\&{end};\2\6 +$\|r\K\\{link}(\|r)$;\6 +\&{end}\2\par +\U610.\fi + +\M612. Here we want to change the coefficients from \\{scaled} to \\{fraction}, +except in the constant term. In the common case of a trivial equation +like `\.{x=3.14}', we will have $\|v=-\\{fraction\_one}$, $\|q=\|p$, and $\|t=% +\\{dependent}$. + +\Y\P$\4\X612:Divide list \|p by $-\|v$, removing node \|q\X\S$\6 +$\|s\K\\{temp\_head}$;\5 +$\\{link}(\|s)\K\|p$;\5 +$\|r\K\|p$;\6 +\1\&{repeat} \37\&{if} $\|r=\|q$ \1\&{then}\6 +\&{begin} \37$\\{link}(\|s)\K\\{link}(\|r)$;\5 +$\\{free\_node}(\|r,\39\\{dep\_node\_size})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|w\K\\{make\_fraction}(\\{value}(\|r),\39\|v)$;\6 +\&{if} $\\{abs}(\|w)\L\\{half\_fraction\_threshold}$ \1\&{then}\6 +\&{begin} \37$\\{link}(\|s)\K\\{link}(\|r)$;\5 +$\\{free\_node}(\|r,\39\\{dep\_node\_size})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{value}(\|r)\K-\|w$;\5 +$\|s\K\|r$;\6 +\&{end};\2\6 +\&{end};\2\6 +$\|r\K\\{link}(\|s)$;\6 +\4\&{until}\5 +$\\{info}(\|r)=\\{null}$;\2\6 +\&{if} $\|t=\\{proto\_dependent}$ \1\&{then}\5 +$\\{value}(\|r)\K-\\{make\_scaled}(\\{value}(\|r),\39\|v)$\6 +\4\&{else} \&{if} $\|v\I-\\{fraction\_one}$ \1\&{then}\5 +$\\{value}(\|r)\K-\\{make\_fraction}(\\{value}(\|r),\39\|v)$;\2\2\6 +$\\{final\_node}\K\|r$;\5 +$\|p\K\\{link}(\\{temp\_head})$\par +\U610.\fi + +\M613. \P$\X613:Display the new dependency\X\S$\6 +\&{if} $\\{interesting}(\|x)$ \1\&{then}\6 +\&{begin} \37\\{begin\_diagnostic};\5 +$\\{print\_nl}(\.{"\#\#\ "})$;\5 +$\\{print\_variable\_name}(\|x)$;\5 +$\|w\K\|n$;\6 +\&{while} $\|w>0$ \1\&{do}\6 +\&{begin} \37$\\{print}(\.{"*4"})$;\5 +$\|w\K\|w-2$;\6 +\&{end};\2\6 +$\\{print\_char}(\.{"="})$;\5 +$\\{print\_dependency}(\|p,\39\\{dependent})$;\5 +$\\{end\_diagnostic}(\\{false})$;\6 +\&{end}\2\par +\U610.\fi + +\M614. \P$\X614:Simplify all existing dependencies by substituting for \|x\X\S$% +\6 +$\\{prev\_r}\K\\{dep\_head}$;\5 +$\|r\K\\{link}(\\{dep\_head})$;\6 +\&{while} $\|r\I\\{dep\_head}$ \1\&{do}\6 +\&{begin} \37$\|s\K\\{dep\_list}(\|r)$;\5 +$\|q\K\\{p\_with\_x\_becoming\_q}(\|s,\39\|x,\39\|p,\39\\{type}(\|r))$;\6 +\&{if} $\\{info}(\|q)=\\{null}$ \1\&{then}\5 +$\\{make\_known}(\|r,\39\|q)$\6 +\4\&{else} \&{begin} \37$\\{dep\_list}(\|r)\K\|q$;\6 +\1\&{repeat} \37$\|q\K\\{link}(\|q)$;\6 +\4\&{until}\5 +$\\{info}(\|q)=\\{null}$;\2\6 +$\\{prev\_r}\K\|q$;\6 +\&{end};\2\6 +$\|r\K\\{link}(\\{prev\_r})$;\6 +\&{end}\2\par +\U610.\fi + +\M615. \P$\X615:Change variable \|x from \\{independent} to \\{dependent} or % +\\{known}\X\S$\6 +\&{if} $\|n>0$ \1\&{then}\5 +\X616:Divide list \|p by $2^n$\X;\2\6 +\&{if} $\\{info}(\|p)=\\{null}$ \1\&{then}\6 +\&{begin} \37$\\{type}(\|x)\K\\{known}$;\5 +$\\{value}(\|x)\K\\{value}(\|p)$;\6 +\&{if} $\\{abs}(\\{value}(\|x))\G\\{fraction\_one}$ \1\&{then}\5 +$\\{val\_too\_big}(\\{value}(\|x))$;\2\6 +$\\{free\_node}(\|p,\39\\{dep\_node\_size})$;\6 +\&{if} $\\{cur\_exp}=\|x$ \1\&{then}\6 +\&{if} $\\{cur\_type}=\\{independent}$ \1\&{then}\6 +\&{begin} \37$\\{cur\_exp}\K\\{value}(\|x)$;\5 +$\\{cur\_type}\K\\{known}$;\5 +$\\{free\_node}(\|x,\39\\{value\_node\_size})$;\6 +\&{end};\2\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{type}(\|x)\K\\{dependent}$;\5 +$\\{dep\_final}\K\\{final\_node}$;\5 +$\\{new\_dep}(\|x,\39\|p)$;\6 +\&{if} $\\{cur\_exp}=\|x$ \1\&{then}\6 +\&{if} $\\{cur\_type}=\\{independent}$ \1\&{then}\5 +$\\{cur\_type}\K\\{dependent}$;\2\2\6 +\&{end}\2\par +\U610.\fi + +\M616. \P$\X616:Divide list \|p by $2^n$\X\S$\6 +\&{begin} \37$\|s\K\\{temp\_head}$;\5 +$\\{link}(\\{temp\_head})\K\|p$;\5 +$\|r\K\|p$;\6 +\1\&{repeat} \37\&{if} $\|n>30$ \1\&{then}\5 +$\|w\K0$\6 +\4\&{else} $\|w\K\\{value}(\|r)\mathbin{\&{div}}\\{two\_to\_the}[\|n]$;\2\6 +\&{if} $(\\{abs}(\|w)\L\\{half\_fraction\_threshold})\W(\\{info}(\|r)\I% +\\{null})$ \1\&{then}\6 +\&{begin} \37$\\{link}(\|s)\K\\{link}(\|r)$;\5 +$\\{free\_node}(\|r,\39\\{dep\_node\_size})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{value}(\|r)\K\|w$;\5 +$\|s\K\|r$;\6 +\&{end};\2\6 +$\|r\K\\{link}(\|s)$;\6 +\4\&{until}\5 +$\\{info}(\|s)=\\{null}$;\2\6 +$\|p\K\\{link}(\\{temp\_head})$;\6 +\&{end}\par +\U615.\fi + +\M617. The \\{check\_mem} procedure, which is used only when \MF\ is being +debugged, makes sure that the current dependency lists are well formed. + +\Y\P$\4\X617:Check the list of linear dependencies\X\S$\6 +$\|q\K\\{dep\_head}$;\5 +$\|p\K\\{link}(\|q)$;\6 +\&{while} $\|p\I\\{dep\_head}$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{prev\_dep}(\|p)\I\|q$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"Bad\ PREVDEP\ at\ "})$;\5 +$\\{print\_int}(\|p)$;\6 +\&{end};\2\6 +$\|p\K\\{dep\_list}(\|p)$;\5 +$\|r\K\\{inf\_val}$;\6 +\1\&{repeat} \37\&{if} $\\{value}(\\{info}(\|p))\G\\{value}(\|r)$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"Out\ of\ order\ at\ "})$;\5 +$\\{print\_int}(\|p)$;\6 +\&{end};\2\6 +$\|r\K\\{info}(\|p)$;\5 +$\|q\K\|p$;\5 +$\|p\K\\{link}(\|q)$;\6 +\4\&{until}\5 +$\|r=\\{null}$;\2\6 +\&{end}\2\par +\U180.\fi + +\N618. \[29] Dynamic nonlinear equations. +Variables of numeric type are maintained by the general scheme of +independent, dependent, and known values that we have just studied; +and the components of pair and transform variables are handled in the +same way. But \MF\ also has five other types of values: \&{boolean}, +\&{string}, \&{pen}, \&{path}, and \&{picture}; what about them? + +Equations are allowed between nonlinear quantities, but only in a +simple form. Two variables that haven't yet been assigned values are +either equal to each other, or they're not. + +Before a boolean variable has received a value, its type is \\{unknown% +\_boolean}; +similarly, there are variables whose type is \\{unknown\_string}, \\{unknown% +\_pen}, +\\{unknown\_path}, and \\{unknown\_picture}. In such cases the value is either +\\{null} (which means that no other variables are equivalent to this one), or +it points to another variable of the same undefined type. The pointers in the +latter case form a cycle of nodes, which we shall call a ``ring.'' +Rings of undefined variables may include capsules, which arise as +intermediate results within expressions or as \&{expr} parameters to macros. + +When one member of a ring receives a value, the same value is given to +all the other members. In the case of paths and pictures, this implies +making separate copies of a potentially large data structure; users should +restrain their enthusiasm for such generality, unless they have lots and +lots of memory space. + +\fi + +\M619. The following procedure is called when a capsule node is being +added to a ring (e.g., when an unknown variable is mentioned in an expression). + +\Y\P\4\&{function}\1\ \37$\\{new\_ring\_entry}(\|p:\\{pointer})$: \37% +\\{pointer};\6 +\4\&{var} \37\|q: \37\\{pointer};\C{the new capsule node}\2\6 +\&{begin} \37$\|q\K\\{get\_node}(\\{value\_node\_size})$;\5 +$\\{name\_type}(\|q)\K\\{capsule}$;\5 +$\\{type}(\|q)\K\\{type}(\|p)$;\6 +\&{if} $\\{value}(\|p)=\\{null}$ \1\&{then}\5 +$\\{value}(\|q)\K\|p$\ \&{else} $\\{value}(\|q)\K\\{value}(\|p)$;\2\6 +$\\{value}(\|p)\K\|q$;\5 +$\\{new\_ring\_entry}\K\|q$;\6 +\&{end};\par +\fi + +\M620. Conversely, we might delete a capsule or a variable before it becomes +known. +The following procedure simply detaches a quantity from its ring, +without recycling the storage. + +\Y\P$\4\X268:Declare the recycling subroutines\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{ring\_delete}(\|p:\\{pointer})$;\6 +\4\&{var} \37\|q: \37\\{pointer};\2\6 +\&{begin} \37$\|q\K\\{value}(\|p)$;\6 +\&{if} $\|q\I\\{null}$ \1\&{then}\6 +\&{if} $\|q\I\|p$ \1\&{then}\6 +\&{begin} \37\&{while} $\\{value}(\|q)\I\|p$ \1\&{do}\5 +$\|q\K\\{value}(\|q)$;\2\6 +$\\{value}(\|q)\K\\{value}(\|p)$;\6 +\&{end};\2\2\6 +\&{end};\par +\fi + +\M621. Eventually there might be an equation that assigns values to all of the +variables in a ring. The \\{nonlinear\_eq} subroutine does the necessary +propagation of values. + +If the parameter \\{flush\_p} is \\{true}, node \|p itself needn't receive a +value; it will soon be recycled. + +\Y\P\4\&{procedure}\1\ \37$\\{nonlinear\_eq}(\|v:\\{integer};\,\35\|p:% +\\{pointer};\,\35\\{flush\_p}:\\{boolean})$;\6 +\4\&{var} \37\|t: \37\\{small\_number};\C{the type of ring \|p}\6 +$\|q,\39\|r$: \37\\{pointer};\C{link manipulation registers}\2\6 +\&{begin} \37$\|t\K\\{type}(\|p)-\\{unknown\_tag}$;\5 +$\|q\K\\{value}(\|p)$;\6 +\&{if} $\\{flush\_p}$ \1\&{then}\5 +$\\{type}(\|p)\K\\{vacuous}$\ \&{else} $\|p\K\|q$;\2\6 +\1\&{repeat} \37$\|r\K\\{value}(\|q)$;\5 +$\\{type}(\|q)\K\|t$;\6 +\&{case} $\|t$ \1\&{of}\6 +\4\\{boolean\_type}: \37$\\{value}(\|q)\K\|v$;\6 +\4\\{string\_type}: \37\&{begin} \37$\\{value}(\|q)\K\|v$;\5 +$\\{add\_str\_ref}(\|v)$;\6 +\&{end};\6 +\4\\{pen\_type}: \37\&{begin} \37$\\{value}(\|q)\K\|v$;\5 +$\\{add\_pen\_ref}(\|v)$;\6 +\&{end};\6 +\4\\{path\_type}: \37$\\{value}(\|q)\K\\{copy\_path}(\|v)$;\6 +\4\\{picture\_type}: \37$\\{value}(\|q)\K\\{copy\_edges}(\|v)$;\2\6 +\&{end};\C{there ain't no more cases}\6 +$\|q\K\|r$;\6 +\4\&{until}\5 +$\|q=\|p$;\2\6 +\&{end};\par +\fi + +\M622. If two members of rings are equated, and if they have the same type, +the \\{ring\_merge} procedure is called on to make them equivalent. + +\Y\P\4\&{procedure}\1\ \37$\\{ring\_merge}(\|p,\39\|q:\\{pointer})$;\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37\|r: \37\\{pointer};\C{traverses one list}\2\6 +\&{begin} \37$\|r\K\\{value}(\|p)$;\6 +\&{while} $\|r\I\|p$ \1\&{do}\6 +\&{begin} \37\&{if} $\|r=\|q$ \1\&{then}\6 +\&{begin} \37\X623:Exclaim about a redundant equation\X;\6 +\&{return};\6 +\&{end};\2\6 +$\|r\K\\{value}(\|r)$;\6 +\&{end};\2\6 +$\|r\K\\{value}(\|p)$;\5 +$\\{value}(\|p)\K\\{value}(\|q)$;\5 +$\\{value}(\|q)\K\|r$;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M623. \P$\X623:Exclaim about a redundant equation\X\S$\6 +\&{begin} \37$\\{print\_err}(\.{"Redundant\ equation"})$;\6 +$\\{help2}(\.{"I\ already\ knew\ that\ this\ equation\ was\ true."})$\6 +$(\.{"But\ perhaps\ no\ harm\ has\ been\ done;\ let\'s\ continue."})$;\6 +\\{put\_get\_error};\6 +\&{end}\par +\Us622, 1004\ETs1008.\fi + +\N624. \[30] Introduction to the syntactic routines. +Let's pause a moment now and try to look at the Big Picture. +The \MF\ 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, +while parsing expressions and locating operators and operands. The +semantic routines act as an interpreter responding to these operators, +which may be regarded as commands. And the output routines are +periodically called on to produce compact font descriptions that can be +used for typesetting or for making interim proof drawings. We have +discussed the basic data structures and many of the details of semantic +operations, so we are good and ready to plunge into the part of \MF\ that +actually controls the activities. + +Our current goal is to come to grips with the \\{get\_next} procedure, +which is the keystone of \MF's input mechanism. Each call of \\{get\_next} +sets the value of three variables \\{cur\_cmd}, \\{cur\_mod}, and \\{cur\_sym}, +representing the next input token. +$$\vbox{\halign{#\hfil\cr +\hbox{\\{cur\_cmd} denotes a command code from the long list of codes +given earlier;}\cr +\hbox{\\{cur\_mod} denotes a modifier of the command code;}\cr +\hbox{\\{cur\_sym} is the hash address of the symbolic token that was +just scanned,}\cr +\hbox{\qquad or zero in the case of a numeric or string +or capsule token.}\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 reading some text that the user has inserted online, +and so on. When reading a character file, the characters must be +converted to tokens; comments and blank spaces must +be removed, numeric and string tokens must be evaluated. + +To handle these situations, which might all be present simultaneously, +\MF\ 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. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{cur\_cmd}: \37\\{eight\_bits};\C{current command set by \\{get\_next}}\6 +\4\\{cur\_mod}: \37\\{integer};\C{operand of current command}\6 +\4\\{cur\_sym}: \37\\{halfword};\C{hash address of current symbol}\par +\fi + +\M625. The \\{print\_cmd\_mod} routine prints a symbolic interpretation of a +command code and its modifier. +It consists of a rather tedious sequence of print +commands, and most of it is essentially an inverse to the \\{primitive} +routine that enters a \MF\ primitive into \\{hash} and \\{eqtb}. Therefore +almost +all of this procedure appears elsewhere in the program, together with the +corresponding \\{primitive} calls. + +\Y\P$\4\X625:Declare the procedure called \\{print\_cmd\_mod}\X\S$\6 +\4\&{procedure}\1\ \37$\\{print\_cmd\_mod}(\|c,\39\|m:\\{integer})$;\2\6 +\&{begin} \37\&{case} $\|c$ \1\&{of}\6 +\hbox{\4}\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of primitives% +\X\6 +\4\&{othercases} \37$\\{print}(\.{"[unknown\ command\ code!]"})$\2\6 +\&{endcases};\6 +\&{end};\par +\U227.\fi + +\M626. Here is a procedure that displays a given command in braces, in the +user's transcript file. + +\Y\P\D \37$\\{show\_cur\_cmd\_mod}\S\\{show\_cmd\_mod}(\\{cur\_cmd},\39\\{cur% +\_mod})$\par +\Y\P\4\&{procedure}\1\ \37$\\{show\_cmd\_mod}(\|c,\39\|m:\\{integer})$;\2\6 +\&{begin} \37\\{begin\_diagnostic};\5 +$\\{print\_nl}(\.{"\{"})$;\5 +$\\{print\_cmd\_mod}(\|c,\39\|m)$;\5 +$\\{print\_char}(\.{"\}"})$;\5 +$\\{end\_diagnostic}(\\{false})$;\6 +\&{end};\par +\fi + +\N627. \[31] Input stacks and states. +The state of \MF's input mechanism appears in the input stack, whose +entries are records with five fields, called \\{index}, \\{start}, \\{loc}, +\\{limit}, and \\{name}. The top element of this stack is maintained in a +global variable for which no subscripting needs to be done; the other +elements of the stack appear in an array. Hence the stack is declared thus: + +\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6 +$\\{in\_state\_record}=$\1\5 +\1\&{record} \37\\{index\_field}: \37\\{quarterword};\6 +\4$\\{start\_field},\39\\{loc\_field},\39\\{limit\_field},\39\\{name\_field}$: % +\37\\{halfword};\2\6 +\&{end};\2\par +\fi + +\M628. \P$\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{input\_stack}: \37\&{array} $[0\to\\{stack\_size}]$ \1\&{of}\5 +\\{in\_state\_record};\2\6 +\4\\{input\_ptr}: \37$0\to\\{stack\_size}$;\C{first unused location of \\{input% +\_stack}}\6 +\4\\{max\_in\_stack}: \37$0\to\\{stack\_size}$;\C{largest value of \\{input% +\_ptr} when pushing}\6 +\4\\{cur\_input}: \37\\{in\_state\_record};\C{the ``top'' input state}\par +\fi + +\M629. We've already defined the special variable $\\{loc}\S\\{cur\_input}.% +\\{loc\_field}$ +in our discussion of basic input-output routines. The other components of +\\{cur\_input} are defined in the same way: + +\Y\P\D \37$\\{index}\S\\{cur\_input}.\\{index\_field}$\C{reference for buffer +information}\par +\P\D \37$\\{start}\S\\{cur\_input}.\\{start\_field}$\C{starting position in % +\\{buffer}}\par +\P\D \37$\\{limit}\S\\{cur\_input}.\\{limit\_field}$\C{end of current line in % +\\{buffer}}\par +\P\D \37$\\{name}\S\\{cur\_input}.\\{name\_field}$\C{name of the current file}% +\par +\fi + +\M630. Let's look more closely now at the five control variables +(\\{index},~\\{start},~\\{loc},~\\{limit},~\\{name}), +assuming that \MF\ 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. \MF\ will return to +the other lines when it is finished with the present input file. + +(Incidentally, on a machine with byte-oriented addressing, it would 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. We always have +$\\{loc}\L\\{limit}$. For convenience, $\\{buffer}[\\{limit}]$ has been set to % +\.{"\%"}, so +that the end of a line is easily sensed. + +The \\{name} variable is a string number that designates the name of +the current file, if we are reading a text file. It is 0 if we +are reading from the terminal for normal input, or 1 if we are executing a +\&{readstring} command, or 2 if we are reading a string that was +moved into the buffer by \&{scantokens}. + +\fi + +\M631. 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 font}', we will have $\\{index}=1$ while reading +the file \.{font.mf}. 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. + +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, +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. + +If more information about the input state is needed, it can be +included in small arrays like those shown here. For example, +the current page or segment number in the input file might be +put into a variable \\{page}, maintained for enclosing levels in +`\ignorespaces \\{page\_stack}: \&{array} $[1\to\\{max\_in\_open}]$ \&{of} % +\\{integer}\unskip' +by analogy with \\{line\_stack}. + +\Y\P\D \37$\\{terminal\_input}\S(\\{name}=0)$\C{are we reading from the +terminal?}\par +\P\D \37$\\{cur\_file}\S\\{input\_file}[\\{index}]$\C{the current \\{alpha% +\_file} variable}\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{in\_open}: \37$0\to\\{max\_in\_open}$;\C{the number of lines in the +buffer, less one}\6 +\4\\{open\_parens}: \37$0\to\\{max\_in\_open}$;\C{the number of open text +files}\6 +\4\\{input\_file}: \37\&{array} $[1\to\\{max\_in\_open}]$ \1\&{of}\5 +\\{alpha\_file};\2\6 +\4\\{line}: \37\\{integer};\C{current line number in the current source file}\6 +\4\\{line\_stack}: \37\&{array} $[1\to\\{max\_in\_open}]$ \1\&{of}\5 +\\{integer};\2\par +\fi + +\M632. 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 +$\\{index}>\\{max\_in\_open}$, 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 not defined by +\&{vardef}. Macros defined by \&{vardef} have $\\{name}=\\{null}$; their name +can be deduced by looking at their first two parameters. + +\yskip\hang\\{param\_start}, which takes the place of \\{limit}, tells where +the parameters of the current macro or loop text begin in the \\{param\_stack}. + +\yskip\noindent The \\{token\_type} can take several values, depending on +where the current token list came from: + +\yskip +\indent\\{forever\_text}, if the token list being scanned is the body of +a \&{forever} loop; + +\indent\\{loop\_text}, if the token list being scanned is the body of +a \&{for} or \&{forsuffixes} loop; + +\indent\\{parameter}, if a \&{text} or \&{suffix} parameter is being scanned; + +\indent\\{backed\_up}, if the token list being scanned has been inserted as +`to be read again'. + +\indent\\{inserted}, if the token list being scanned has been inserted as +part of error recovery; + +\indent\\{macro}, if the expansion of a user-defined symbolic token is being +scanned. + +\yskip\noindent +The token list begins with a reference count if and only if $\\{token\_type}=% +\\{macro}$. + +\Y\P\D \37$\\{token\_type}\S\\{index}$\C{type of current token list}\par +\P\D \37$\\{token\_state}\S(\\{index}>\\{max\_in\_open})$\C{are we scanning a +token list?}\par +\P\D \37$\\{file\_state}\S(\\{index}\L\\{max\_in\_open})$\C{are we scanning a +file line?}\par +\P\D \37$\\{param\_start}\S\\{limit}$\C{base of macro parameters in \\{param% +\_stack}}\par +\P\D \37$\\{forever\_text}=\\{max\_in\_open}+1$\C{\\{token\_type} code for loop +texts}\par +\P\D \37$\\{loop\_text}=\\{max\_in\_open}+2$\C{\\{token\_type} code for loop +texts}\par +\P\D \37$\\{parameter}=\\{max\_in\_open}+3$\C{\\{token\_type} code for +parameter texts}\par +\P\D \37$\\{backed\_up}=\\{max\_in\_open}+4$\C{\\{token\_type} code for texts +to be reread}\par +\P\D \37$\\{inserted}=\\{max\_in\_open}+5$\C{\\{token\_type} code for inserted +texts}\par +\P\D \37$\\{macro}=\\{max\_in\_open}+6$\C{\\{token\_type} code for macro +replacement texts}\par +\fi + +\M633. 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 grows at a different rate from the others. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{param\_stack}: \37\&{array} $[0\to\\{param\_size}]$ \1\&{of}\5 +\\{pointer};\C{token list pointers for parameters}\2\6 +\4\\{param\_ptr}: \37$0\to\\{param\_size}$;\C{first unused entry in \\{param% +\_stack}}\6 +\4\\{max\_param\_stack}: \37\\{integer};\C{largest value of \\{param\_ptr}}\par +\fi + +\M634. 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 \MF'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 \\{file\_ptr} contains the lowest level that was +displayed by this procedure. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{file\_ptr}: \37$0\to\\{stack\_size}$;\C{shallowest level shown by \\{show% +\_context}}\par +\fi + +\M635. The status at each level is indicated by printing two lines, where the +first +line indicates what was read so far and the second line shows what remains +to be read. The context is cropped, if necessary, so that the first line +contains at most \\{half\_error\_line} characters, and the second contains +at most \\{error\_line}. Non-current input levels whose \\{token\_type} is +`\\{backed\_up}' are shown only if they have not been fully read. + +\Y\P\4\&{procedure}\1\ \37\\{show\_context};\C{prints where the scanner is}\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37\\{old\_setting}: \37$0\to\\{max\_selector}$;\C{saved \\{selector} +setting}\6 +\X641:Local variables for formatting calculations\X\2\6 +\&{begin} \37$\\{file\_ptr}\K\\{input\_ptr}$;\5 +$\\{input\_stack}[\\{file\_ptr}]\K\\{cur\_input}$;\C{store current state}\6 +\~ \1\&{loop}\ \&{begin} \37$\\{cur\_input}\K\\{input\_stack}[\\{file\_ptr}]$;% +\C{enter into the context}\6 +\X636:Display the current context\X;\6 +\&{if} $\\{file\_state}$ \1\&{then}\6 +\&{if} $(\\{name}>2)\V(\\{file\_ptr}=0)$ \1\&{then}\5 +\&{goto} \37\\{done};\2\2\6 +$\\{decr}(\\{file\_ptr})$;\6 +\&{end};\2\6 +\4\\{done}: \37$\\{cur\_input}\K\\{input\_stack}[\\{input\_ptr}]$;\C{restore +original state}\6 +\&{end};\par +\fi + +\M636. \P$\X636:Display the current context\X\S$\6 +\&{if} $(\\{file\_ptr}=\\{input\_ptr})\V\\{file\_state}\V(\\{token\_type}\I% +\\{backed\_up})\V(\\{loc}\I\\{null})$ \1\&{then}\C{we omit backed-up token +lists that have already been read}\6 +\&{begin} \37$\\{tally}\K0$;\C{get ready to count characters}\6 +$\\{old\_setting}\K\\{selector}$;\6 +\&{if} $\\{file\_state}$ \1\&{then}\6 +\&{begin} \37\X637:Print location of current line\X;\6 +\X644:Pseudoprint the line\X;\6 +\&{end}\6 +\4\&{else} \&{begin} \37\X638:Print type of token list\X;\6 +\X645:Pseudoprint the token list\X;\6 +\&{end};\2\6 +$\\{selector}\K\\{old\_setting}$;\C{stop pseudoprinting}\6 +\X643:Print two lines using the tricky pseudoprinted information\X;\6 +\&{end}\2\par +\U635.\fi + +\M637. This routine should be changed, if necessary, to give the best possible +indication of where the current line resides in the input file. +For example, on some systems it is best to print both a page and line number. + +\Y\P$\4\X637:Print location of current line\X\S$\6 +\&{if} $\\{name}\L1$ \1\&{then}\6 +\&{if} $\\{terminal\_input}\W(\\{file\_ptr}=0)$ \1\&{then}\5 +$\\{print\_nl}(\.{"<*>"})$\6 +\4\&{else} $\\{print\_nl}(\.{"<insert>"})$\2\6 +\4\&{else} \&{if} $\\{name}=2$ \1\&{then}\5 +$\\{print\_nl}(\.{"<scantokens>"})$\6 +\4\&{else} \&{begin} \37$\\{print\_nl}(\.{"l."})$;\5 +$\\{print\_int}(\\{line})$;\6 +\&{end};\2\2\6 +$\\{print\_char}(\.{"\ "})$\par +\U636.\fi + +\M638. \P$\X638:Print type of token list\X\S$\6 +\&{case} $\\{token\_type}$ \1\&{of}\6 +\4\\{forever\_text}: \37$\\{print\_nl}(\.{"<forever>\ "})$;\6 +\4\\{loop\_text}: \37\X639:Print the current loop value\X;\6 +\4\\{parameter}: \37$\\{print\_nl}(\.{"<argument>\ "})$;\6 +\4\\{backed\_up}: \37\&{if} $\\{loc}=\\{null}$ \1\&{then}\5 +$\\{print\_nl}(\.{"<recently\ read>\ "})$\6 +\4\&{else} $\\{print\_nl}(\.{"<to\ be\ read\ again>\ "})$;\2\6 +\4\\{inserted}: \37$\\{print\_nl}(\.{"<inserted\ text>\ "})$;\6 +\4\\{macro}: \37\&{begin} \37\\{print\_ln};\6 +\&{if} $\\{name}\I\\{null}$ \1\&{then}\5 +$\\{slow\_print}(\\{text}(\\{name}))$\6 +\4\&{else} \X640:Print the name of a \&{vardef}'d macro\X;\2\6 +$\\{print}(\.{"->"})$;\6 +\&{end};\6 +\4\&{othercases} \37$\\{print\_nl}(\.{"?"})$\C{this should never happen}\2\6 +\&{endcases}\par +\U636.\fi + +\M639. The parameter that corresponds to a loop text is either a token list +(in the case of \&{forsuffixes}) or a ``capsule'' (in the case of \&{for}). +We'll discuss capsules later; for now, all we need to know is that +the \\{link} field in a capsule parameter is \\{void} and that +$\\{print\_exp}(\|p,0)$ displays the value of capsule~\|p in abbreviated form. + +\Y\P$\4\X639:Print the current loop value\X\S$\6 +\&{begin} \37$\\{print\_nl}(\.{"<for("})$;\5 +$\|p\K\\{param\_stack}[\\{param\_start}]$;\6 +\&{if} $\|p\I\\{null}$ \1\&{then}\6 +\&{if} $\\{link}(\|p)=\\{void}$ \1\&{then}\5 +$\\{print\_exp}(\|p,\390)$\C{we're in a \&{for} loop}\6 +\4\&{else} $\\{show\_token\_list}(\|p,\39\\{null},\3920,\39\\{tally})$;\2\2\6 +$\\{print}(\.{")>\ "})$;\6 +\&{end}\par +\U638.\fi + +\M640. The first two parameters of a macro defined by \&{vardef} will be token +lists representing the macro's prefix and ``at point.'' By putting these +together, we get the macro's full name. + +\Y\P$\4\X640:Print the name of a \&{vardef}'d macro\X\S$\6 +\&{begin} \37$\|p\K\\{param\_stack}[\\{param\_start}]$;\6 +\&{if} $\|p=\\{null}$ \1\&{then}\5 +$\\{show\_token\_list}(\\{param\_stack}[\\{param\_start}+1],\39\\{null},\3920,% +\39\\{tally})$\6 +\4\&{else} \&{begin} \37$\|q\K\|p$;\6 +\&{while} $\\{link}(\|q)\I\\{null}$ \1\&{do}\5 +$\|q\K\\{link}(\|q)$;\2\6 +$\\{link}(\|q)\K\\{param\_stack}[\\{param\_start}+1]$;\5 +$\\{show\_token\_list}(\|p,\39\\{null},\3920,\39\\{tally})$;\5 +$\\{link}(\|q)\K\\{null}$;\6 +\&{end};\2\6 +\&{end}\par +\U638.\fi + +\M641. Now 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 \MF's +tables. So `pseudoprinting' is the answer: We enter a mode of printing +that stores characters into a buffer of length \\{error\_line}, where character +$k+1$ is placed into \hbox{$\\{trick\_buf}[\|k\mathbin{\&{mod}}\\{error% +\_line}]$} if +$\|k<\\{trick\_count}$, otherwise character \|k is dropped. Initially we set +$\\{tally}\K0$ and $\\{trick\_count}\K1000000$; then when we reach the +point where transition from line 1 to line 2 should occur, we +set $\\{first\_count}\K\\{tally}$ and $\\{trick\_count}\K\hbox{max}(\\{error% +\_line},\\{tally}+1+\\{error\_line}-\\{half\_error\_line})$. At the end of the +pseudoprinting, the values of \\{first\_count}, \\{tally}, and +\\{trick\_count} give us all the information we need to print the two lines, +and all of the necessary text is in \\{trick\_buf}. + +Namely, let \|l be the length of the descriptive information that appears +on the first line. The length of the context information gathered for that +line is $\|k=\\{first\_count}$, and the length of the context information +gathered for line~2 is $m=\min(\\{tally}, \\{trick\_count})-k$. If $\|l+\|k\L% +\|h$, +where $\|h=\\{half\_error\_line}$, we print $\\{trick\_buf}[0\to\|k-1]$ after +the +descriptive information on line~1, and set $\|n\K\|l+\|k$; here \|n is the +length of line~1. If $l+k>h$, some cropping is necessary, so we set $\|n\K\|h$ +and print `\.{...}' followed by +$$\hbox{$\\{trick\_buf}[(\|l+\|k-\|h+3)\to\|k-1]$,}$$ +where subscripts of \\{trick\_buf} are circular modulo \\{error\_line}. The +second line consists of \|n~spaces followed by $\\{trick\_buf}[\|k\to(\|k+% +\|m-1)]$, +unless $\|n+\|m>\\{error\_line}$; in the latter case, further cropping is done. +This is easier to program than to explain. + +\Y\P$\4\X641:Local variables for formatting calculations\X\S$\6 +\4\|i: \37$0\to\\{buf\_size}$;\C{index into \\{buffer}}\6 +\4\|l: \37\\{integer};\C{length of descriptive information on line 1}\6 +\4\|m: \37\\{integer};\C{context information gathered for line 2}\6 +\4\|n: \37$0\to\\{error\_line}$;\C{length of line 1}\6 +\4\|p: \37\\{integer};\C{starting or ending place in \\{trick\_buf}}\6 +\4\|q: \37\\{integer};\C{temporary index}\par +\U635.\fi + +\M642. The following code tells the print routines to gather +the desired information. + +\Y\P\D \37$\\{begin\_pseudoprint}\S$\1\6 +\&{begin} \37$\|l\K\\{tally}$;\5 +$\\{tally}\K0$;\5 +$\\{selector}\K\\{pseudo}$;\5 +$\\{trick\_count}\K1000000$;\6 +\&{end}\2\par +\P\D \37$\\{set\_trick\_count}\S$\1\6 +\&{begin} \37$\\{first\_count}\K\\{tally}$;\5 +$\\{trick\_count}\K\\{tally}+1+\\{error\_line}-\\{half\_error\_line}$;\6 +\&{if} $\\{trick\_count}<\\{error\_line}$ \1\&{then}\5 +$\\{trick\_count}\K\\{error\_line}$;\2\6 +\&{end}\2\par +\fi + +\M643. And the following code uses the information after it has been gathered. + +\Y\P$\4\X643:Print two lines using the tricky pseudoprinted information\X\S$\6 +\&{if} $\\{trick\_count}=1000000$ \1\&{then}\5 +\\{set\_trick\_count};\C{\\{set\_trick\_count} must be performed}\2\6 +\&{if} $\\{tally}<\\{trick\_count}$ \1\&{then}\5 +$\|m\K\\{tally}-\\{first\_count}$\6 +\4\&{else} $\|m\K\\{trick\_count}-\\{first\_count}$;\C{context on line 2}\2\6 +\&{if} $\|l+\\{first\_count}\L\\{half\_error\_line}$ \1\&{then}\6 +\&{begin} \37$\|p\K0$;\5 +$\|n\K\|l+\\{first\_count}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{print}(\.{"..."})$;\5 +$\|p\K\|l+\\{first\_count}-\\{half\_error\_line}+3$;\5 +$\|n\K\\{half\_error\_line}$;\6 +\&{end};\2\6 +\&{for} $\|q\K\|p\mathrel{\&{to}}\\{first\_count}-1$ \1\&{do}\5 +$\\{print\_char}(\\{trick\_buf}[\|q\mathbin{\&{mod}}\\{error\_line}])$;\2\6 +\\{print\_ln};\6 +\&{for} $\|q\K1\mathrel{\&{to}}\|n$ \1\&{do}\5 +$\\{print\_char}(\.{"\ "})$;\C{print \|n spaces to begin line~2}\2\6 +\&{if} $\|m+\|n\L\\{error\_line}$ \1\&{then}\5 +$\|p\K\\{first\_count}+\|m$\6 +\4\&{else} $\|p\K\\{first\_count}+(\\{error\_line}-\|n-3)$;\2\6 +\&{for} $\|q\K\\{first\_count}\mathrel{\&{to}}\|p-1$ \1\&{do}\5 +$\\{print\_char}(\\{trick\_buf}[\|q\mathbin{\&{mod}}\\{error\_line}])$;\2\6 +\&{if} $\|m+\|n>\\{error\_line}$ \1\&{then}\5 +$\\{print}(\.{"..."})$\2\par +\U636.\fi + +\M644. But the trick is distracting us from our current goal, which is to +understand the input state. So let's concentrate on the data structures that +are being pseudoprinted as we finish up the \\{show\_context} procedure. + +\Y\P$\4\X644:Pseudoprint the line\X\S$\6 +\\{begin\_pseudoprint};\6 +\&{if} $\\{limit}>0$ \1\&{then}\6 +\&{for} $\|i\K\\{start}\mathrel{\&{to}}\\{limit}-1$ \1\&{do}\6 +\&{begin} \37\&{if} $\|i=\\{loc}$ \1\&{then}\5 +\\{set\_trick\_count};\2\6 +$\\{print}(\\{buffer}[\|i])$;\6 +\&{end}\2\2\par +\U636.\fi + +\M645. \P$\X645:Pseudoprint the token list\X\S$\6 +\\{begin\_pseudoprint};\6 +\&{if} $\\{token\_type}\I\\{macro}$ \1\&{then}\5 +$\\{show\_token\_list}(\\{start},\39\\{loc},\39100000,\390)$\6 +\4\&{else} $\\{show\_macro}(\\{start},\39\\{loc},\39100000)$\2\par +\U636.\fi + +\M646. Here is the missing piece of \\{show\_token\_list} that is activated +when the +token beginning line~2 is about to be shown: + +\Y\P$\4\X646:Do magic computation\X\S$\6 +\\{set\_trick\_count}\par +\U217.\fi + +\N647. \[32] Maintaining the input stacks. +The following subroutines change the input status in commonly needed ways. + +First comes \\{push\_input}, which stores the current state and creates a +new level (having, initially, the same properties as the old). + +\Y\P\D \37$\\{push\_input}\S\hbox{}$\C{enter a new input level, save the old}\6 +\&{begin} \37\&{if} $\\{input\_ptr}>\\{max\_in\_stack}$ \1\&{then}\6 +\&{begin} \37$\\{max\_in\_stack}\K\\{input\_ptr}$;\6 +\&{if} $\\{input\_ptr}=\\{stack\_size}$ \1\&{then}\5 +$\\{overflow}(\.{"input\ stack\ size"},\39\\{stack\_size})$;\2\6 +\&{end};\2\6 +$\\{input\_stack}[\\{input\_ptr}]\K\\{cur\_input}$;\C{stack the record}\6 +$\\{incr}(\\{input\_ptr})$;\6 +\&{end}\par +\fi + +\M648. And of course what goes up must come down. + +\Y\P\D \37$\\{pop\_input}\S\hbox{}$\C{leave an input level, re-enter the old}\6 +\&{begin} \37$\\{decr}(\\{input\_ptr})$;\5 +$\\{cur\_input}\K\\{input\_stack}[\\{input\_ptr}]$;\6 +\&{end}\par +\fi + +\M649. 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}, reset~\\{loc}, and increase the macro's reference count. + +\Y\P\D \37$\\{back\_list}(\#)\S\\{begin\_token\_list}(\#,\39\\{backed\_up})$% +\C{backs up a simple token list}\par +\Y\P\4\&{procedure}\1\ \37$\\{begin\_token\_list}(\|p:\\{pointer};\,\35\|t:% +\\{quarterword})$;\2\6 +\&{begin} \37\\{push\_input};\5 +$\\{start}\K\|p$;\5 +$\\{token\_type}\K\|t$;\5 +$\\{param\_start}\K\\{param\_ptr}$;\5 +$\\{loc}\K\|p$;\6 +\&{end};\par +\fi + +\M650. When a token list has been fully scanned, the following computations +should be done as we leave that level of input. + +\Y\P\4\&{procedure}\1\ \37\\{end\_token\_list};\C{leave a token-list input +level}\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37\|p: \37\\{pointer};\C{temporary register}\2\6 +\&{begin} \37\&{if} $\\{token\_type}\G\\{backed\_up}$ \1\&{then}\C{token list +to be deleted}\6 +\&{if} $\\{token\_type}\L\\{inserted}$ \1\&{then}\6 +\&{begin} \37$\\{flush\_token\_list}(\\{start})$;\5 +\&{goto} \37\\{done};\6 +\&{end}\6 +\4\&{else} $\\{delete\_mac\_ref}(\\{start})$;\C{update reference count}\2\2\6 +\&{while} $\\{param\_ptr}>\\{param\_start}$ \1\&{do}\C{parameters must be +flushed}\6 +\&{begin} \37$\\{decr}(\\{param\_ptr})$;\5 +$\|p\K\\{param\_stack}[\\{param\_ptr}]$;\6 +\&{if} $\|p\I\\{null}$ \1\&{then}\6 +\&{if} $\\{link}(\|p)=\\{void}$ \1\&{then}\C{it's an \&{expr} parameter}\6 +\&{begin} \37$\\{recycle\_value}(\|p)$;\5 +$\\{free\_node}(\|p,\39\\{value\_node\_size})$;\6 +\&{end}\6 +\4\&{else} $\\{flush\_token\_list}(\|p)$;\C{it's a \&{suffix} or \&{text} +parameter}\2\2\6 +\&{end};\2\6 +\4\\{done}: \37\\{pop\_input};\5 +\\{check\_interrupt};\6 +\&{end};\par +\fi + +\M651. The contents of $\\{cur\_cmd},\\{cur\_mod},\\{cur\_sym}$ are placed into +an equivalent +token by the \\{cur\_tok} routine. + +\Y\P\hbox{\4}\X855:Declare the procedure called \\{make\_exp\_copy}\X\6 +\4\&{function}\1\ \37\\{cur\_tok}: \37\\{pointer};\6 +\4\&{var} \37\|p: \37\\{pointer};\C{a new token node}\6 +\\{save\_type}: \37\\{small\_number};\C{\\{cur\_type} to be restored}\6 +\\{save\_exp}: \37\\{integer};\C{\\{cur\_exp} to be restored}\2\6 +\&{begin} \37\&{if} $\\{cur\_sym}=0$ \1\&{then}\6 +\&{if} $\\{cur\_cmd}=\\{capsule\_token}$ \1\&{then}\6 +\&{begin} \37$\\{save\_type}\K\\{cur\_type}$;\5 +$\\{save\_exp}\K\\{cur\_exp}$;\5 +$\\{make\_exp\_copy}(\\{cur\_mod})$;\5 +$\|p\K\\{stash\_cur\_exp}$;\5 +$\\{link}(\|p)\K\\{null}$;\5 +$\\{cur\_type}\K\\{save\_type}$;\5 +$\\{cur\_exp}\K\\{save\_exp}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|p\K\\{get\_node}(\\{token\_node\_size})$;\5 +$\\{value}(\|p)\K\\{cur\_mod}$;\5 +$\\{name\_type}(\|p)\K\\{token}$;\6 +\&{if} $\\{cur\_cmd}=\\{numeric\_token}$ \1\&{then}\5 +$\\{type}(\|p)\K\\{known}$\6 +\4\&{else} $\\{type}(\|p)\K\\{string\_type}$;\2\6 +\&{end}\2\6 +\4\&{else} \&{begin} \37$\\{fast\_get\_avail}(\|p)$;\5 +$\\{info}(\|p)\K\\{cur\_sym}$;\6 +\&{end};\2\6 +$\\{cur\_tok}\K\|p$;\6 +\&{end};\par +\fi + +\M652. Sometimes \MF\ 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. +If $\\{cur\_sym}\I0$, the values of \\{cur\_cmd} and \\{cur\_mod} are +irrelevant. + +\Y\P\4\&{procedure}\1\ \37\\{back\_input};\C{undoes one token of input}\6 +\4\&{var} \37\|p: \37\\{pointer};\C{a token list of length one}\2\6 +\&{begin} \37$\|p\K\\{cur\_tok}$;\6 +\&{while} $\\{token\_state}\W(\\{loc}=\\{null})$ \1\&{do}\5 +\\{end\_token\_list};\C{conserve stack space}\2\6 +$\\{back\_list}(\|p)$;\6 +\&{end};\par +\fi + +\M653. The \\{back\_error} routine is used when we want to restore or replace +an +offending token just before issuing an error message. We disable interrupts +during the call of \\{back\_input} so that the help message won't be lost. + +\Y\P\4\&{procedure}\1\ \37\\{back\_error};\C{back up one token and call % +\\{error}}\2\6 +\&{begin} \37$\\{OK\_to\_interrupt}\K\\{false}$;\5 +\\{back\_input};\5 +$\\{OK\_to\_interrupt}\K\\{true}$;\5 +\\{error};\6 +\&{end};\7 +\4\&{procedure}\1\ \37\\{ins\_error};\C{back up one inserted token and call % +\\{error}}\2\6 +\&{begin} \37$\\{OK\_to\_interrupt}\K\\{false}$;\5 +\\{back\_input};\5 +$\\{token\_type}\K\\{inserted}$;\5 +$\\{OK\_to\_interrupt}\K\\{true}$;\5 +\\{error};\6 +\&{end};\par +\fi + +\M654. The \\{begin\_file\_reading} procedure starts a new level of input for +lines +of characters to be read from a file, or as an insertion from the +terminal. It does not take care of opening the file, nor does it set \\{loc} +or \\{limit} or \\{line}. + +\Y\P\4\&{procedure}\1\ \37\\{begin\_file\_reading};\2\6 +\&{begin} \37\&{if} $\\{in\_open}=\\{max\_in\_open}$ \1\&{then}\5 +$\\{overflow}(\.{"text\ input\ levels"},\39\\{max\_in\_open})$;\2\6 +\&{if} $\\{first}=\\{buf\_size}$ \1\&{then}\5 +$\\{overflow}(\.{"buffer\ size"},\39\\{buf\_size})$;\2\6 +$\\{incr}(\\{in\_open})$;\5 +\\{push\_input};\5 +$\\{index}\K\\{in\_open}$;\5 +$\\{line\_stack}[\\{index}]\K\\{line}$;\5 +$\\{start}\K\\{first}$;\5 +$\\{name}\K0$;\C{\\{terminal\_input} is now \\{true}}\6 +\&{end};\par +\fi + +\M655. Conversely, the variables must be downdated when such a level of input +is finished: + +\Y\P\4\&{procedure}\1\ \37\\{end\_file\_reading};\2\6 +\&{begin} \37$\\{first}\K\\{start}$;\5 +$\\{line}\K\\{line\_stack}[\\{index}]$;\6 +\&{if} $\\{index}\I\\{in\_open}$ \1\&{then}\5 +$\\{confusion}(\.{"endinput"})$;\2\6 +\&{if} $\\{name}>2$ \1\&{then}\5 +$\\{a\_close}(\\{cur\_file})$;\C{forget it}\2\6 +\\{pop\_input};\5 +$\\{decr}(\\{in\_open})$;\6 +\&{end};\par +\fi + +\M656. In order to keep the stack from overflowing during a long sequence of +inserted `\.{show}' commands, the following routine removes completed +error-inserted lines from memory. + +\Y\P\4\&{procedure}\1\ \37\\{clear\_for\_error\_prompt};\2\6 +\&{begin} \37\&{while} $\\{file\_state}\W\\{terminal\_input}\W\30(\\{input% +\_ptr}>0)\W(\\{loc}=\\{limit})$ \1\&{do}\5 +\\{end\_file\_reading};\2\6 +\\{print\_ln};\5 +\\{clear\_terminal};\6 +\&{end};\par +\fi + +\M657. To get \MF's whole input mechanism going, we perform the following +actions. + +\Y\P$\4\X657:Initialize the input routines\X\S$\6 +\&{begin} \37$\\{input\_ptr}\K0$;\5 +$\\{max\_in\_stack}\K0$;\5 +$\\{in\_open}\K0$;\5 +$\\{open\_parens}\K0$;\5 +$\\{max\_buf\_stack}\K0$;\5 +$\\{param\_ptr}\K0$;\5 +$\\{max\_param\_stack}\K0$;\5 +$\\{first}\K1$;\5 +$\\{start}\K1$;\5 +$\\{index}\K0$;\5 +$\\{line}\K0$;\5 +$\\{name}\K0$;\5 +$\\{force\_eof}\K\\{false}$;\6 +\&{if} $\R\\{init\_terminal}$ \1\&{then}\5 +\&{goto} \37\\{final\_end};\2\6 +$\\{limit}\K\\{last}$;\5 +$\\{first}\K\\{last}+1$;\C{\\{init\_terminal} has set \\{loc} and \\{last}}\6 +\&{end};\par +\A660. +\U1211.\fi + +\N658. \[33] Getting the next token. +The heart of \MF'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; it really acts as \MF's +eyes and mouth, reading the source files and gobbling them up. And it also +helps \MF\ 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\_mod} to that token's command code and modifier. Furthermore, if +the input token is a symbolic token, that token's \\{hash} address +is stored in \\{cur\_sym}; otherwise \\{cur\_sym} 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. + +\fi + +\M659. Before getting into \\{get\_next}, we need to consider a mechanism by +which +\MF\ helps keep errors from propagating too far. Whenever the program goes +into a mode where it keeps calling \\{get\_next} repeatedly until a certain +condition is met, it sets \\{scanner\_status} to some value other than % +\\{normal}. +Then if an input file ends, or if an `\&{outer}' symbol appears, +an appropriate error recovery will be possible. + +The global variable \\{warning\_info} helps in this error recovery by providing +additional information. For example, \\{warning\_info} might indicate the +name of a macro whose replacement text is being scanned. + +\Y\P\D \37$\\{normal}=0$\C{\\{scanner\_status} at ``quiet times''}\par +\P\D \37$\\{skipping}=1$\C{\\{scanner\_status} when false conditional text is +being skipped}\par +\P\D \37$\\{flushing}=2$\C{\\{scanner\_status} when junk after a statement is +being ignored}\par +\P\D \37$\\{absorbing}=3$\C{\\{scanner\_status} when a \&{text} parameter is +being scanned}\par +\P\D \37$\\{var\_defining}=4$\C{\\{scanner\_status} when a \&{vardef} is being +scanned}\par +\P\D \37$\\{op\_defining}=5$\C{\\{scanner\_status} when a macro \&{def} is +being scanned}\par +\P\D \37$\\{loop\_defining}=6$\C{\\{scanner\_status} when a \&{for} loop is +being scanned}\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{scanner\_status}: \37$\\{normal}\to\\{loop\_defining}$;\C{are we scanning +at high speed?}\6 +\4\\{warning\_info}: \37\\{integer};\C{if so, what else do we need to know, +in case an error occurs?}\par +\fi + +\M660. \P$\X657:Initialize the input routines\X\mathrel{+}\S$\6 +$\\{scanner\_status}\K\\{normal}$;\par +\fi + +\M661. The following subroutine +is called when an `\&{outer}' symbolic token has been scanned or +when the end of a file has been reached. These two cases are distinguished +by \\{cur\_sym}, which is zero at the end of a file. + +\Y\P\4\&{function}\1\ \37\\{check\_outer\_validity}: \37\\{boolean};\6 +\4\&{var} \37\|p: \37\\{pointer};\C{points to inserted token list}\2\6 +\&{begin} \37\&{if} $\\{scanner\_status}=\\{normal}$ \1\&{then}\5 +$\\{check\_outer\_validity}\K\\{true}$\6 +\4\&{else} \&{begin} \37$\\{deletions\_allowed}\K\\{false}$;\5 +\X662:Back up an outer symbolic token so that it can be reread\X;\6 +\&{if} $\\{scanner\_status}>\\{skipping}$ \1\&{then}\5 +\X663:Tell the user what has run away and try to recover\X\6 +\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Incomplete\ if;\ all\ text\ was\ +ignored\ after\ line\ "})$;\5 +$\\{print\_int}(\\{warning\_info})$;\6 +$\\{help3}(\.{"A\ forbidden\ \`outer\'\ token\ occurred\ in\ skipped\ text."})$% +\6 +$(\.{"This\ kind\ of\ error\ happens\ when\ you\ say\ \`if...\'\ and\ +forget"})$\6 +$(\.{"the\ matching\ \`fi\'.\ I\'ve\ inserted\ a\ \`fi\';\ this\ might\ +work."})$;\6 +\&{if} $\\{cur\_sym}=0$ \1\&{then}\5 +$\\{help\_line}[2]\K\30\.{"The\ file\ ended\ while\ I\ was\ skipping\ +conditional\ text."}$;\2\6 +$\\{cur\_sym}\K\\{frozen\_fi}$;\5 +\\{ins\_error};\6 +\&{end};\2\6 +$\\{deletions\_allowed}\K\\{true}$;\5 +$\\{check\_outer\_validity}\K\\{false}$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M662. \P$\X662:Back up an outer symbolic token so that it can be reread\X\S$\6 +\&{if} $\\{cur\_sym}\I0$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{get\_avail}$;\5 +$\\{info}(\|p)\K\\{cur\_sym}$;\5 +$\\{back\_list}(\|p)$;\C{prepare to read the symbolic token again}\6 +\&{end}\2\par +\U661.\fi + +\M663. \P$\X663:Tell the user what has run away and try to recover\X\S$\6 +\&{begin} \37\\{runaway};\C{print the definition-so-far}\6 +\&{if} $\\{cur\_sym}=0$ \1\&{then}\5 +$\\{print\_err}(\.{"File\ ended"})$\6 +\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Forbidden\ token\ found"})$;\6 +\&{end};\2\6 +$\\{print}(\.{"\ while\ scanning\ "})$;\5 +$\\{help4}(\.{"I\ suspect\ you\ have\ forgotten\ an\ \`enddef\',"})$\6 +$(\.{"causing\ me\ to\ read\ past\ where\ you\ wanted\ me\ to\ stop."})$\6 +$(\.{"I\'ll\ try\ to\ recover;\ but\ if\ the\ error\ is\ serious,"})$\6 +$(\.{"you\'d\ better\ type\ \`E\'\ or\ \`X\'\ now\ and\ fix\ your\ file."})$;\6 +\&{case} $\\{scanner\_status}$ \1\&{of}\6 +\hbox{\4}\X664:Complete the error message, and set \\{cur\_sym} to a token that +might help recover from the error\X\2\6 +\&{end};\C{there are no other cases}\6 +\\{ins\_error};\6 +\&{end}\par +\U661.\fi + +\M664. As we consider various kinds of errors, it is also appropriate to +change the first line of the help message just given; $\\{help\_line}[3]$ +points to the string that might be changed. + +\Y\P$\4\X664:Complete the error message, and set \\{cur\_sym} to a token that +might help recover from the error\X\S$\6 +\4\\{flushing}: \37\&{begin} \37$\\{print}(\.{"to\ the\ end\ of\ the\ +statement"})$;\5 +$\\{help\_line}[3]\K\.{"A\ previous\ error\ seems\ to\ have\ propagated,"}$;\5 +$\\{cur\_sym}\K\\{frozen\_semicolon}$;\6 +\&{end};\6 +\4\\{absorbing}: \37\&{begin} \37$\\{print}(\.{"a\ text\ argument"})$;\5 +$\\{help\_line}[3]\K\.{"It\ seems\ that\ a\ right\ delimiter\ was\ left\ +out,"}$;\6 +\&{if} $\\{warning\_info}=0$ \1\&{then}\5 +$\\{cur\_sym}\K\\{frozen\_end\_group}$\6 +\4\&{else} \&{begin} \37$\\{cur\_sym}\K\\{frozen\_right\_delimiter}$;\5 +$\\{equiv}(\\{frozen\_right\_delimiter})\K\\{warning\_info}$;\6 +\&{end};\2\6 +\&{end};\6 +\4$\\{var\_defining},\39\\{op\_defining}$: \37\&{begin} \37$\\{print}(\.{"the\ +definition\ of\ "})$;\6 +\&{if} $\\{scanner\_status}=\\{op\_defining}$ \1\&{then}\5 +$\\{slow\_print}(\\{text}(\\{warning\_info}))$\6 +\4\&{else} $\\{print\_variable\_name}(\\{warning\_info})$;\2\6 +$\\{cur\_sym}\K\\{frozen\_end\_def}$;\6 +\&{end};\6 +\4\\{loop\_defining}: \37\&{begin} \37$\\{print}(\.{"the\ text\ of\ a\ "})$;\5 +$\\{slow\_print}(\\{text}(\\{warning\_info}))$;\5 +$\\{print}(\.{"\ loop"})$;\5 +$\\{help\_line}[3]\K\.{"I\ suspect\ you\ have\ forgotten\ an\ \`endfor\',"}$;\5 +$\\{cur\_sym}\K\\{frozen\_end\_for}$;\6 +\&{end};\par +\U663.\fi + +\M665. The \\{runaway} procedure displays the first part of the text that +occurred +when \MF\ began its special \\{scanner\_status}, if that text has been saved. + +\Y\P$\4\X665:Declare the procedure called \\{runaway}\X\S$\6 +\4\&{procedure}\1\ \37\\{runaway};\2\6 +\&{begin} \37\&{if} $\\{scanner\_status}>\\{flushing}$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"Runaway\ "})$;\6 +\&{case} $\\{scanner\_status}$ \1\&{of}\6 +\4\\{absorbing}: \37$\\{print}(\.{"text?"})$;\6 +\4$\\{var\_defining},\39\\{op\_defining}$: \37$\\{print}(\.{"definition?"})$;\6 +\4\\{loop\_defining}: \37$\\{print}(\.{"loop?"})$;\2\6 +\&{end};\C{there are no other cases}\6 +\\{print\_ln};\5 +$\\{show\_token\_list}(\\{link}(\\{hold\_head}),\39\\{null},\39\\{error% +\_line}-10,\390)$;\6 +\&{end};\2\6 +\&{end};\par +\U162.\fi + +\M666. We need to mention a procedure that may be called by \\{get\_next}. + +\Y\P\4\&{procedure}\1\ \37\\{firm\_up\_the\_line};\5 +\\{forward};\par +\fi + +\M667. And now we're ready to take the plunge into \\{get\_next} itself. + +\Y\P\D \37$\\{switch}=25$\C{a label in \\{get\_next}}\par +\P\D \37$\\{start\_numeric\_token}=85$\C{another}\par +\P\D \37$\\{start\_decimal\_token}=86$\C{and another}\par +\P\D \37$\\{fin\_numeric\_token}=87$\C{and still another, although \&{goto} is +considered harmful}\par +\Y\P\4\&{procedure}\1\ \37\\{get\_next};\C{sets \\{cur\_cmd}, \\{cur\_mod}, % +\\{cur\_sym} to next token}\6 +\4\&{label} \37$\\{restart},\39$\C{go here to get the next input token}\6 +$\\{exit},\39$\C{go here when the next input token has been got}\6 +$\\{found},\39$\C{go here when the end of a symbolic token has been found}\6 +$\\{switch},\39$\C{go here to branch on the class of an input character}\6 +$\\{start\_numeric\_token},\39\\{start\_decimal\_token},\39\\{fin\_numeric% +\_token},\39\\{done}$;\C{go here at crucial stages when scanning a number}\6 +\4\&{var} \37\|k: \37$0\to\\{buf\_size}$;\C{an index into \\{buffer}}\6 +\|c: \37\\{ASCII\_code};\C{the current character in the buffer}\6 +\\{class}: \37\\{ASCII\_code};\C{its class number}\6 +$\|n,\39\|f$: \37\\{integer};\C{registers for decimal-to-binary conversion}\2\6 +\&{begin} \37\\{restart}: \37$\\{cur\_sym}\K0$;\6 +\&{if} $\\{file\_state}$ \1\&{then}\5 +\X669:Input from external file; \&{goto} \\{restart} if no input found, or % +\&{return} if a non-symbolic token is found\X\6 +\4\&{else} \X676:Input from token list; \&{goto} \\{restart} if end of list or +if a parameter needs to be expanded, or \&{return} if a non-symbolic token is +found\X;\2\6 +\X668:Finish getting the symbolic token in \\{cur\_sym}; \&{goto} \\{restart} +if it is illegal\X;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M668. When a symbolic token is declared to be `\&{outer}', its command code +is increased by \\{outer\_tag}. + +\Y\P$\4\X668:Finish getting the symbolic token in \\{cur\_sym}; \&{goto} % +\\{restart} if it is illegal\X\S$\6 +$\\{cur\_cmd}\K\\{eq\_type}(\\{cur\_sym})$;\5 +$\\{cur\_mod}\K\\{equiv}(\\{cur\_sym})$;\6 +\&{if} $\\{cur\_cmd}\G\\{outer\_tag}$ \1\&{then}\6 +\&{if} $\\{check\_outer\_validity}$ \1\&{then}\5 +$\\{cur\_cmd}\K\\{cur\_cmd}-\\{outer\_tag}$\6 +\4\&{else} \&{goto} \37\\{restart}\2\2\par +\U667.\fi + +\M669. A percent sign appears in $\\{buffer}[\\{limit}]$; this makes it +unnecessary +to have a special test for end-of-line. + +\Y\P$\4\X669:Input from external file; \&{goto} \\{restart} if no input found, +or \&{return} if a non-symbolic token is found\X\S$\6 +\&{begin} \37\\{switch}: \37$\|c\K\\{buffer}[\\{loc}]$;\5 +$\\{incr}(\\{loc})$;\5 +$\\{class}\K\\{char\_class}[\|c]$;\6 +\&{case} $\\{class}$ \1\&{of}\6 +\4\\{digit\_class}: \37\&{goto} \37\\{start\_numeric\_token};\6 +\4\\{period\_class}: \37\&{begin} \37$\\{class}\K\\{char\_class}[\\{buffer}[% +\\{loc}]]$;\6 +\&{if} $\\{class}>\\{period\_class}$ \1\&{then}\5 +\&{goto} \37\\{switch}\6 +\4\&{else} \&{if} $\\{class}<\\{period\_class}$ \1\&{then}\C{$\\{class}=% +\\{digit\_class}$}\6 +\&{begin} \37$\|n\K0$;\5 +\&{goto} \37\\{start\_decimal\_token};\6 +\&{end};\2\2\6 +\&{end};\6 +\4\\{space\_class}: \37\&{goto} \37\\{switch};\6 +\4\\{percent\_class}: \37\&{begin} \37\X679:Move to next line of file, or % +\&{goto} \\{restart} if there is no next line\X;\6 +\\{check\_interrupt};\5 +\&{goto} \37\\{switch};\6 +\&{end};\6 +\4\\{string\_class}: \37\X671:Get a string token and \&{return}\X;\6 +\4\\{isolated\_classes}: \37\&{begin} \37$\|k\K\\{loc}-1$;\5 +\&{goto} \37\\{found};\6 +\&{end};\6 +\4\\{invalid\_class}: \37\X670:Decry the invalid character and \&{goto} % +\\{restart}\X;\6 +\4\&{othercases} \37\\{do\_nothing}\C{letters, etc.}\2\6 +\&{endcases};\6 +$\|k\K\\{loc}-1$;\6 +\&{while} $\\{char\_class}[\\{buffer}[\\{loc}]]=\\{class}$ \1\&{do}\5 +$\\{incr}(\\{loc})$;\2\6 +\&{goto} \37\\{found};\6 +\4\\{start\_numeric\_token}: \37\X673:Get the integer part \|n of a numeric +token; set $\|f\K0$ and \&{goto} \\{fin\_numeric\_token} if there is no decimal +point\X;\6 +\4\\{start\_decimal\_token}: \37\X674:Get the fraction part \|f of a numeric +token\X;\6 +\4\\{fin\_numeric\_token}: \37\X675:Pack the numeric and fraction parts of a +numeric token and \&{return}\X;\6 +\4\\{found}: \37$\\{cur\_sym}\K\\{id\_lookup}(\|k,\39\\{loc}-\|k)$;\6 +\&{end}\par +\U667.\fi + +\M670. We go to \\{restart} instead of to \\{switch}, because \\{state} might +equal +\\{token\_list} after the error has been dealt with +(cf.\ \\{clear\_for\_error\_prompt}). + +\Y\P$\4\X670:Decry the invalid character and \&{goto} \\{restart}\X\S$\6 +\&{begin} \37$\\{print\_err}(\.{"Text\ line\ contains\ an\ invalid\ +character"})$;\5 +$\\{help2}(\.{"A\ funny\ symbol\ that\ I\ can\'t\ read\ has\ just\ been\ +input."})$\6 +$(\.{"Continue,\ and\ I\'ll\ forget\ that\ it\ ever\ happened."})$;\6 +$\\{deletions\_allowed}\K\\{false}$;\5 +\\{error};\5 +$\\{deletions\_allowed}\K\\{true}$;\5 +\&{goto} \37\\{restart};\6 +\&{end}\par +\U669.\fi + +\M671. \P$\X671:Get a string token and \&{return}\X\S$\6 +\&{begin} \37\&{if} $\\{buffer}[\\{loc}]=\.{""}\.{""}$ \1\&{then}\5 +$\\{cur\_mod}\K\.{""}$\6 +\4\&{else} \&{begin} \37$\|k\K\\{loc}$;\5 +$\\{buffer}[\\{limit}+1]\K\.{""}\.{""}$;\6 +\1\&{repeat} \37$\\{incr}(\\{loc})$;\6 +\4\&{until}\5 +$\\{buffer}[\\{loc}]=\.{""}\.{""}$;\2\6 +\&{if} $\\{loc}>\\{limit}$ \1\&{then}\5 +\X672:Decry the missing string delimiter and \&{goto} \\{restart}\X;\2\6 +\&{if} $(\\{loc}=\|k+1)\W(\\{length}(\\{buffer}[\|k])=1)$ \1\&{then}\5 +$\\{cur\_mod}\K\\{buffer}[\|k]$\6 +\4\&{else} \&{begin} \37$\\{str\_room}(\\{loc}-\|k)$;\6 +\1\&{repeat} \37$\\{append\_char}(\\{buffer}[\|k])$;\5 +$\\{incr}(\|k)$;\6 +\4\&{until}\5 +$\|k=\\{loc}$;\2\6 +$\\{cur\_mod}\K\\{make\_string}$;\6 +\&{end};\2\6 +\&{end};\2\6 +$\\{incr}(\\{loc})$;\5 +$\\{cur\_cmd}\K\\{string\_token}$;\5 +\&{return};\6 +\&{end}\par +\U669.\fi + +\M672. We go to \\{restart} after this error message, not to \\{switch}, +because the \\{clear\_for\_error\_prompt} routine might have reinstated +\\{token\_state} after \\{error} has finished. + +\Y\P$\4\X672:Decry the missing string delimiter and \&{goto} \\{restart}\X\S$\6 +\&{begin} \37$\\{loc}\K\\{limit}$;\C{the next character to be read on this line +will be \.{"\%"}}\6 +$\\{print\_err}(\.{"Incomplete\ string\ token\ has\ been\ flushed"})$;\5 +$\\{help3}(\.{"Strings\ should\ finish\ on\ the\ same\ line\ as\ they\ +began."})$\6 +$(\.{"I\'ve\ deleted\ the\ partial\ string;\ you\ might\ want\ to"})$\6 +$(\.{"insert\ another\ by\ typing,\ e.g.,\ \`I"}\.{"new\ string"}\.{"\'."})$;\6 +$\\{deletions\_allowed}\K\\{false}$;\5 +\\{error};\5 +$\\{deletions\_allowed}\K\\{true}$;\5 +\&{goto} \37\\{restart};\6 +\&{end}\par +\U671.\fi + +\M673. \P$\X673:Get the integer part \|n of a numeric token; set $\|f\K0$ and % +\&{goto} \\{fin\_numeric\_token} if there is no decimal point\X\S$\6 +$\|n\K\|c-\.{"0"}$;\6 +\&{while} $\\{char\_class}[\\{buffer}[\\{loc}]]=\\{digit\_class}$ \1\&{do}\6 +\&{begin} \37\&{if} $\|n<4096$ \1\&{then}\5 +$\|n\K10\ast\|n+\\{buffer}[\\{loc}]-\.{"0"}$;\2\6 +$\\{incr}(\\{loc})$;\6 +\&{end};\2\6 +\&{if} $\\{buffer}[\\{loc}]=\.{"."}$ \1\&{then}\6 +\&{if} $\\{char\_class}[\\{buffer}[\\{loc}+1]]=\\{digit\_class}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\2\6 +$\|f\K0$;\5 +\&{goto} \37\\{fin\_numeric\_token};\6 +\4\\{done}: \37$\\{incr}(\\{loc})$\par +\U669.\fi + +\M674. \P$\X674:Get the fraction part \|f of a numeric token\X\S$\6 +$\|k\K0$;\6 +\1\&{repeat} \37\&{if} $\|k<17$ \1\&{then}\C{digits for $\|k\G17$ cannot affect +the result}\6 +\&{begin} \37$\\{dig}[\|k]\K\\{buffer}[\\{loc}]-\.{"0"}$;\5 +$\\{incr}(\|k)$;\6 +\&{end};\2\6 +$\\{incr}(\\{loc})$;\6 +\4\&{until}\5 +$\\{char\_class}[\\{buffer}[\\{loc}]]\I\\{digit\_class}$;\2\6 +$\|f\K\\{round\_decimals}(\|k)$;\6 +\&{if} $\|f=\\{unity}$ \1\&{then}\6 +\&{begin} \37$\\{incr}(\|n)$;\5 +$\|f\K0$;\6 +\&{end}\2\par +\U669.\fi + +\M675. \P$\X675:Pack the numeric and fraction parts of a numeric token and % +\&{return}\X\S$\6 +\&{if} $\|n<4096$ \1\&{then}\5 +$\\{cur\_mod}\K\|n\ast\\{unity}+\|f$\6 +\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Enormous\ number\ has\ been\ +reduced"})$;\5 +$\\{help2}(\.{"I\ can\'t\ handle\ numbers\ bigger\ than\ about\ 4095.99998;"})$% +\6 +$(\.{"so\ I\'ve\ changed\ your\ constant\ to\ that\ maximum\ amount."})$;\6 +$\\{deletions\_allowed}\K\\{false}$;\5 +\\{error};\5 +$\\{deletions\_allowed}\K\\{true}$;\5 +$\\{cur\_mod}\K\O{1777777777}$;\6 +\&{end};\2\6 +$\\{cur\_cmd}\K\\{numeric\_token}$;\5 +\&{return}\par +\U669.\fi + +\M676. Let's consider now what happens when \\{get\_next} is looking at a token +list. + +\Y\P$\4\X676:Input from token list; \&{goto} \\{restart} if end of list or if a +parameter needs to be expanded, or \&{return} if a non-symbolic token is found% +\X\S$\6 +\&{if} $\\{loc}\G\\{hi\_mem\_min}$ \1\&{then}\C{one-word token}\6 +\&{begin} \37$\\{cur\_sym}\K\\{info}(\\{loc})$;\5 +$\\{loc}\K\\{link}(\\{loc})$;\C{move to next}\6 +\&{if} $\\{cur\_sym}\G\\{expr\_base}$ \1\&{then}\6 +\&{if} $\\{cur\_sym}\G\\{suffix\_base}$ \1\&{then}\5 +\X677:Insert a suffix or text parameter and \&{goto} \\{restart}\X\6 +\4\&{else} \&{begin} \37$\\{cur\_cmd}\K\\{capsule\_token}$;\5 +$\\{cur\_mod}\K\\{param\_stack}[\\{param\_start}+\\{cur\_sym}-(\\{expr% +\_base})]$;\5 +$\\{cur\_sym}\K0$;\5 +\&{return};\6 +\&{end};\2\2\6 +\&{end}\6 +\4\&{else} \&{if} $\\{loc}>\\{null}$ \1\&{then}\5 +\X678:Get a stored numeric or string or capsule token and \&{return}\X\6 +\4\&{else} \&{begin} \37\C{we are done with this token list}\6 +\\{end\_token\_list};\5 +\&{goto} \37\\{restart};\C{resume previous level}\6 +\&{end}\2\2\par +\U667.\fi + +\M677. \P$\X677:Insert a suffix or text parameter and \&{goto} \\{restart}\X\S$% +\6 +\&{begin} \37\&{if} $\\{cur\_sym}\G\\{text\_base}$ \1\&{then}\5 +$\\{cur\_sym}\K\\{cur\_sym}-\\{param\_size}$;\C{$\\{param\_size}=\\{text% +\_base}-\\{suffix\_base}$}\2\6 +$\\{begin\_token\_list}(\\{param\_stack}[\\{param\_start}+\\{cur\_sym}-(% +\\{suffix\_base})],\39\\{parameter})$;\5 +\&{goto} \37\\{restart};\6 +\&{end}\par +\U676.\fi + +\M678. \P$\X678:Get a stored numeric or string or capsule token and \&{return}% +\X\S$\6 +\&{begin} \37\&{if} $\\{name\_type}(\\{loc})=\\{token}$ \1\&{then}\6 +\&{begin} \37$\\{cur\_mod}\K\\{value}(\\{loc})$;\6 +\&{if} $\\{type}(\\{loc})=\\{known}$ \1\&{then}\5 +$\\{cur\_cmd}\K\\{numeric\_token}$\6 +\4\&{else} \&{begin} \37$\\{cur\_cmd}\K\\{string\_token}$;\5 +$\\{add\_str\_ref}(\\{cur\_mod})$;\6 +\&{end};\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{cur\_mod}\K\\{loc}$;\5 +$\\{cur\_cmd}\K\\{capsule\_token}$;\6 +\&{end};\2\6 +$\\{loc}\K\\{link}(\\{loc})$;\5 +\&{return};\6 +\&{end}\par +\U676.\fi + +\M679. All of the easy branches of \\{get\_next} have now been taken care of. +There is one more branch. + +\Y\P$\4\X679:Move to next line of file, or \&{goto} \\{restart} if there is no +next line\X\S$\6 +\&{if} $\\{name}>2$ \1\&{then}\5 +\X681:Read next line of file into \\{buffer}, or \&{goto} \\{restart} if the +file has ended\X\6 +\4\&{else} \&{begin} \37\&{if} $\\{input\_ptr}>0$ \1\&{then}\C{text was +inserted during error recovery or by \&{scantokens}}\6 +\&{begin} \37\\{end\_file\_reading};\5 +\&{goto} \37\\{restart};\C{resume previous level}\6 +\&{end};\2\6 +\&{if} $\\{selector}<\\{log\_only}$ \1\&{then}\5 +\\{open\_log\_file};\2\6 +\&{if} $\\{interaction}>\\{nonstop\_mode}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{limit}=\\{start}$ \1\&{then}\C{previous line was empty}% +\6 +$\\{print\_nl}(\.{"(Please\ type\ a\ command\ or\ say\ \`end\')"})$;\2\6 +\\{print\_ln};\5 +$\\{first}\K\\{start}$;\5 +$\\{prompt\_input}(\.{"*"})$;\C{input on-line into \\{buffer}}\6 +$\\{limit}\K\\{last}$;\5 +$\\{buffer}[\\{limit}]\K\.{"\%"}$;\5 +$\\{first}\K\\{limit}+1$;\5 +$\\{loc}\K\\{start}$;\6 +\&{end}\6 +\4\&{else} $\\{fatal\_error}(\.{"***\ (job\ aborted,\ no\ legal\ end\ +found)"})$;\C{nonstop mode, which is intended for overnight batch processing, + never waits for on-line input}\2\6 +\&{end}\2\par +\U669.\fi + +\M680. The global variable \\{force\_eof} is normally \\{false}; it is set % +\\{true} +by an \&{endinput} command. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{force\_eof}: \37\\{boolean};\C{should the next \&{input} be aborted +early?}\par +\fi + +\M681. \P$\X681:Read next line of file into \\{buffer}, or \&{goto} \\{restart} +if the file has ended\X\S$\6 +\&{begin} \37$\\{incr}(\\{line})$;\5 +$\\{first}\K\\{start}$;\6 +\&{if} $\R\\{force\_eof}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{input\_ln}(\\{cur\_file},\39\\{true})$ \1\&{then}\C{not +end of file}\6 +\\{firm\_up\_the\_line}\C{this sets \\{limit}}\6 +\4\&{else} $\\{force\_eof}\K\\{true}$;\2\6 +\&{end};\2\6 +\&{if} $\\{force\_eof}$ \1\&{then}\6 +\&{begin} \37$\\{print\_char}(\.{")"})$;\5 +$\\{decr}(\\{open\_parens})$;\5 +\\{update\_terminal};\C{show user that file has been read}\6 +$\\{force\_eof}\K\\{false}$;\5 +\\{end\_file\_reading};\C{resume previous level}\6 +\&{if} $\\{check\_outer\_validity}$ \1\&{then}\5 +\&{goto} \37\\{restart}\ \&{else} \&{goto} \37\\{restart};\2\6 +\&{end};\2\6 +$\\{buffer}[\\{limit}]\K\.{"\%"}$;\5 +$\\{first}\K\\{limit}+1$;\5 +$\\{loc}\K\\{start}$;\C{ready to read}\6 +\&{end}\par +\U679.\fi + +\M682. 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 `\.{=>}'. +\MF\ waits for a response. If the response is null (i.e., if nothing is +typed except perhaps a few blank spaces), the original +line is accepted as it stands; otherwise the line typed is +used instead of the line in the file. + +\Y\P\4\&{procedure}\1\ \37\\{firm\_up\_the\_line};\6 +\4\&{var} \37\|k: \37$0\to\\{buf\_size}$;\C{an index into \\{buffer}}\2\6 +\&{begin} \37$\\{limit}\K\\{last}$;\6 +\&{if} $\\{internal}[\\{pausing}]>0$ \1\&{then}\6 +\&{if} $\\{interaction}>\\{nonstop\_mode}$ \1\&{then}\6 +\&{begin} \37\\{wake\_up\_terminal};\5 +\\{print\_ln};\6 +\&{if} $\\{start}<\\{limit}$ \1\&{then}\6 +\&{for} $\|k\K\\{start}\mathrel{\&{to}}\\{limit}-1$ \1\&{do}\5 +$\\{print}(\\{buffer}[\|k])$;\2\2\6 +$\\{first}\K\\{limit}$;\5 +$\\{prompt\_input}(\.{"=>"})$;\C{wait for user response}\6 +\&{if} $\\{last}>\\{first}$ \1\&{then}\6 +\&{begin} \37\&{for} $\|k\K\\{first}\mathrel{\&{to}}\\{last}-1$ \1\&{do}\C{move +line down in buffer}\6 +$\\{buffer}[\|k+\\{start}-\\{first}]\K\\{buffer}[\|k]$;\2\6 +$\\{limit}\K\\{start}+\\{last}-\\{first}$;\6 +\&{end};\2\6 +\&{end};\2\2\6 +\&{end};\par +\fi + +\N683. \[34] Scanning macro definitions. +\MF\ has a variety of ways to tuck tokens away into token lists for later +use: Macros can be defined with \&{def}, \&{vardef}, \&{primarydef}, etc.; +repeatable code can be defined with \&{for}, \&{forever}, \&{forsuffixes}. +All such operations are handled by the routines in this part of the program. + +The modifier part of each command code is zero for the ``ending delimiters'' +like \&{enddef} and \&{endfor}. + +\Y\P\D \37$\\{start\_def}=1$\C{command modifier for \&{def}}\par +\P\D \37$\\{var\_def}=2$\C{command modifier for \&{vardef}}\par +\P\D \37$\\{end\_def}=0$\C{command modifier for \&{enddef}}\par +\P\D \37$\\{start\_forever}=1$\C{command modifier for \&{forever}}\par +\P\D \37$\\{end\_for}=0$\C{command modifier for \&{endfor}}\par +\Y\P$\4\X192:Put each of \MF's primitives into the hash table\X\mathrel{+}\S$\6 +$\\{primitive}(\.{"def"},\39\\{macro\_def},\39\\{start\_def})$;\6 +$\\{primitive}(\.{"vardef"},\39\\{macro\_def},\39\\{var\_def})$;\6 +$\\{primitive}(\.{"primarydef"},\39\\{macro\_def},\39\\{secondary\_primary% +\_macro})$;\6 +$\\{primitive}(\.{"secondarydef"},\39\\{macro\_def},\39\\{tertiary\_secondary% +\_macro})$;\6 +$\\{primitive}(\.{"tertiarydef"},\39\\{macro\_def},\39\\{expression\_tertiary% +\_macro})$;\6 +$\\{primitive}(\.{"enddef"},\39\\{macro\_def},\39\\{end\_def})$;\5 +$\\{eqtb}[\\{frozen\_end\_def}]\K\\{eqtb}[\\{cur\_sym}]$;\7 +$\\{primitive}(\.{"for"},\39\\{iteration},\39\\{expr\_base})$;\6 +$\\{primitive}(\.{"forsuffixes"},\39\\{iteration},\39\\{suffix\_base})$;\6 +$\\{primitive}(\.{"forever"},\39\\{iteration},\39\\{start\_forever})$;\6 +$\\{primitive}(\.{"endfor"},\39\\{iteration},\39\\{end\_for})$;\5 +$\\{eqtb}[\\{frozen\_end\_for}]\K\\{eqtb}[\\{cur\_sym}]$;\par +\fi + +\M684. \P$\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of +primitives\X\mathrel{+}\S$\6 +\4\\{macro\_def}: \37\&{if} $\|m\L\\{var\_def}$ \1\&{then}\6 +\&{if} $\|m=\\{start\_def}$ \1\&{then}\5 +$\\{print}(\.{"def"})$\6 +\4\&{else} \&{if} $\|m<\\{start\_def}$ \1\&{then}\5 +$\\{print}(\.{"enddef"})$\6 +\4\&{else} $\\{print}(\.{"vardef"})$\2\2\6 +\4\&{else} \&{if} $\|m=\\{secondary\_primary\_macro}$ \1\&{then}\5 +$\\{print}(\.{"primarydef"})$\6 +\4\&{else} \&{if} $\|m=\\{tertiary\_secondary\_macro}$ \1\&{then}\5 +$\\{print}(\.{"secondarydef"})$\6 +\4\&{else} $\\{print}(\.{"tertiarydef"})$;\2\2\2\6 +\4\\{iteration}: \37\&{if} $\|m\L\\{start\_forever}$ \1\&{then}\6 +\&{if} $\|m=\\{start\_forever}$ \1\&{then}\5 +$\\{print}(\.{"forever"})$\ \&{else} $\\{print}(\.{"endfor"})$\2\6 +\4\&{else} \&{if} $\|m=\\{expr\_base}$ \1\&{then}\5 +$\\{print}(\.{"for"})$\ \&{else} $\\{print}(\.{"forsuffixes"})$;\2\2\par +\fi + +\M685. Different macro-absorbing operations have different syntaxes, but they +also have a lot in common. There is a list of special symbols that are to +be replaced by parameter tokens; there is a special command code that +ends the definition; the quotation conventions are identical. Therefore +it makes sense to have most of the work done by a single subroutine. That +subroutine is called \\{scan\_toks}. + +The first parameter to \\{scan\_toks} is the command code that will +terminate scanning (either \\{macro\_def}, \\{loop\_repeat}, or \\{iteration}). + +The second parameter, \\{subst\_list}, points to a (possibly empty) list +of two-word nodes whose \\{info} and \\{value} fields specify symbol tokens +before and after replacement. The list will be returned to free storage +by \\{scan\_toks}. + +The third parameter is simply appended to the token list that is built. +And the final parameter tells how many of the special operations +\.{\#\AT!}, \.{\AT!}, and \.{\AT!\#} are to be replaced by suffix parameters. +When such parameters are present, they are called \.{(SUFFIX0)}, +\.{(SUFFIX1)}, and \.{(SUFFIX2)}. + +\Y\P\4\&{function}\1\ \37$\\{scan\_toks}(\\{terminator}:\\{command\_code};\,% +\35\\{subst\_list},\39\\{tail\_end}:\\{pointer};\,\35\\{suffix\_count}:\\{small% +\_number})$: \37\\{pointer};\6 +\4\&{label} \37$\\{done},\39\\{found}$;\6 +\4\&{var} \37\|p: \37\\{pointer};\C{tail of the token list being built}\6 +\|q: \37\\{pointer};\C{temporary for link management}\6 +\\{balance}: \37\\{integer};\C{left delimiters minus right delimiters}\2\6 +\&{begin} \37$\|p\K\\{hold\_head}$;\5 +$\\{balance}\K1$;\5 +$\\{link}(\\{hold\_head})\K\\{null}$;\6 +\~ \1\&{loop}\ \&{begin} \37\\{get\_next};\6 +\&{if} $\\{cur\_sym}>0$ \1\&{then}\6 +\&{begin} \37\X686:Substitute for \\{cur\_sym}, if it's on the \\{subst\_list}% +\X;\6 +\&{if} $\\{cur\_cmd}=\\{terminator}$ \1\&{then}\5 +\X687:Adjust the balance; \&{goto} \\{done} if it's zero\X\6 +\4\&{else} \&{if} $\\{cur\_cmd}=\\{macro\_special}$ \1\&{then}\5 +\X690:Handle quoted symbols, \.{\#\AT!}, \.{\AT!}, or \.{\AT!\#}\X;\2\2\6 +\&{end};\2\6 +$\\{link}(\|p)\K\\{cur\_tok}$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +\4\\{done}: \37$\\{link}(\|p)\K\\{tail\_end}$;\5 +$\\{flush\_node\_list}(\\{subst\_list})$;\5 +$\\{scan\_toks}\K\\{link}(\\{hold\_head})$;\6 +\&{end};\par +\fi + +\M686. \P$\X686:Substitute for \\{cur\_sym}, if it's on the \\{subst\_list}\X% +\S$\6 +\&{begin} \37$\|q\K\\{subst\_list}$;\6 +\&{while} $\|q\I\\{null}$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{info}(\|q)=\\{cur\_sym}$ \1\&{then}\6 +\&{begin} \37$\\{cur\_sym}\K\\{value}(\|q)$;\5 +$\\{cur\_cmd}\K\\{relax}$;\5 +\&{goto} \37\\{found};\6 +\&{end};\2\6 +$\|q\K\\{link}(\|q)$;\6 +\&{end};\2\6 +\4\\{found}: \37\&{end}\par +\U685.\fi + +\M687. \P$\X687:Adjust the balance; \&{goto} \\{done} if it's zero\X\S$\6 +\&{if} $\\{cur\_mod}>0$ \1\&{then}\5 +$\\{incr}(\\{balance})$\6 +\4\&{else} \&{begin} \37$\\{decr}(\\{balance})$;\6 +\&{if} $\\{balance}=0$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +\&{end}\2\par +\U685.\fi + +\M688. Four commands are intended to be used only within macro texts: % +\&{quote}, +\.{\#\AT!}, \.{\AT!}, and \.{\AT!\#}. They are variants of a single command +code called \\{macro\_special}. + +\Y\P\D \37$\\{quote}=0$\C{\\{macro\_special} modifier for \&{quote}}\par +\P\D \37$\\{macro\_prefix}=1$\C{\\{macro\_special} modifier for \.{\#\AT!}}\par +\P\D \37$\\{macro\_at}=2$\C{\\{macro\_special} modifier for \.{\AT!}}\par +\P\D \37$\\{macro\_suffix}=3$\C{\\{macro\_special} modifier for \.{\AT!\#}}\par +\Y\P$\4\X192:Put each of \MF's primitives into the hash table\X\mathrel{+}\S$\6 +$\\{primitive}(\.{"quote"},\39\\{macro\_special},\39\\{quote})$;\6 +$\\{primitive}(\.{"\#@"},\39\\{macro\_special},\39\\{macro\_prefix})$;\6 +$\\{primitive}(\.{"@"},\39\\{macro\_special},\39\\{macro\_at})$;\6 +$\\{primitive}(\.{"@\#"},\39\\{macro\_special},\39\\{macro\_suffix})$;\par +\fi + +\M689. \P$\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of +primitives\X\mathrel{+}\S$\6 +\4\\{macro\_special}: \37\&{case} $\|m$ \1\&{of}\6 +\4\\{macro\_prefix}: \37$\\{print}(\.{"\#@"})$;\6 +\4\\{macro\_at}: \37$\\{print\_char}(\.{"@"})$;\6 +\4\\{macro\_suffix}: \37$\\{print}(\.{"@\#"})$;\6 +\4\&{othercases} \37$\\{print}(\.{"quote"})$\2\6 +\&{endcases};\par +\fi + +\M690. \P$\X690:Handle quoted symbols, \.{\#\AT!}, \.{\AT!}, or \.{\AT!\#}\X\S$% +\6 +\&{begin} \37\&{if} $\\{cur\_mod}=\\{quote}$ \1\&{then}\5 +\\{get\_next}\6 +\4\&{else} \&{if} $\\{cur\_mod}\L\\{suffix\_count}$ \1\&{then}\5 +$\\{cur\_sym}\K\\{suffix\_base}-1+\\{cur\_mod}$;\2\2\6 +\&{end}\par +\U685.\fi + +\M691. Here is a routine that's used whenever a token will be redefined. If +the user's token is unredefinable, the `\\{frozen\_inaccessible}' token is +substituted; the latter is redefinable but essentially impossible to use, +hence \MF's tables won't get fouled up. + +\Y\P\4\&{procedure}\1\ \37\\{get\_symbol};\C{sets \\{cur\_sym} to a safe +symbol}\6 +\4\&{label} \37\\{restart};\2\6 +\&{begin} \37\\{restart}: \37\\{get\_next};\6 +\&{if} $(\\{cur\_sym}=0)\V(\\{cur\_sym}>\\{frozen\_inaccessible})$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"Missing\ symbolic\ token\ inserted"})$;\5 +$\\{help3}(\.{"Sorry:\ You\ can\'t\ redefine\ a\ number,\ string,\ or\ +expr."})$\6 +$(\.{"I\'ve\ inserted\ an\ inaccessible\ symbol\ so\ that\ your"})$\6 +$(\.{"definition\ will\ be\ completed\ without\ mixing\ me\ up\ too\ +badly."})$;\6 +\&{if} $\\{cur\_sym}>0$ \1\&{then}\5 +$\\{help\_line}[2]\K\.{"Sorry:\ You\ can\'t\ redefine\ my\ error-recovery\ +tokens."}$\6 +\4\&{else} \&{if} $\\{cur\_cmd}=\\{string\_token}$ \1\&{then}\5 +$\\{delete\_str\_ref}(\\{cur\_mod})$;\2\2\6 +$\\{cur\_sym}\K\\{frozen\_inaccessible}$;\5 +\\{ins\_error};\5 +\&{goto} \37\\{restart};\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M692. Before we actually redefine a symbolic token, we need to clear away its +former value, if it was a variable. The following stronger version of +\\{get\_symbol} does that. + +\Y\P\4\&{procedure}\1\ \37\\{get\_clear\_symbol};\2\6 +\&{begin} \37\\{get\_symbol};\5 +$\\{clear\_symbol}(\\{cur\_sym},\39\\{false})$;\6 +\&{end};\par +\fi + +\M693. Here's another little subroutine; it checks that an equals sign +or assignment sign comes along at the proper place in a macro definition. + +\Y\P\4\&{procedure}\1\ \37\\{check\_equals};\2\6 +\&{begin} \37\&{if} $\\{cur\_cmd}\I\\{equals}$ \1\&{then}\6 +\&{if} $\\{cur\_cmd}\I\\{assignment}$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\.{"="})$;\6 +$\\{help5}(\.{"The\ next\ thing\ in\ this\ \`def\'\ should\ have\ been\ \`=% +\',"})$\6 +$(\.{"because\ I\'ve\ already\ looked\ at\ the\ definition\ heading."})$\6 +$(\.{"But\ don\'t\ worry;\ I\'ll\ pretend\ that\ an\ equals\ sign"})$\6 +$(\.{"was\ present.\ Everything\ from\ here\ to\ \`enddef\'"})$\6 +$(\.{"will\ be\ the\ replacement\ text\ of\ this\ macro."})$;\5 +\\{back\_error};\6 +\&{end};\2\2\6 +\&{end};\par +\fi + +\M694. A \&{primarydef}, \&{secondarydef}, or \&{tertiarydef} is rather easily +handled now that we have \\{scan\_toks}. In this case there are +two parameters, which will be \.{EXPR0} and \.{EXPR1} (i.e., +\\{expr\_base} and $\\{expr\_base}+1$). + +\Y\P\4\&{procedure}\1\ \37\\{make\_op\_def};\6 +\4\&{var} \37\|m: \37\\{command\_code};\C{the type of definition}\6 +$\|p,\39\|q,\39\|r$: \37\\{pointer};\C{for list manipulation}\2\6 +\&{begin} \37$\|m\K\\{cur\_mod}$;\6 +\\{get\_symbol};\5 +$\|q\K\\{get\_node}(\\{token\_node\_size})$;\5 +$\\{info}(\|q)\K\\{cur\_sym}$;\5 +$\\{value}(\|q)\K\\{expr\_base}$;\6 +\\{get\_clear\_symbol};\5 +$\\{warning\_info}\K\\{cur\_sym}$;\6 +\\{get\_symbol};\5 +$\|p\K\\{get\_node}(\\{token\_node\_size})$;\5 +$\\{info}(\|p)\K\\{cur\_sym}$;\5 +$\\{value}(\|p)\K\\{expr\_base}+1$;\5 +$\\{link}(\|p)\K\|q$;\6 +\\{get\_next};\5 +\\{check\_equals};\6 +$\\{scanner\_status}\K\\{op\_defining}$;\5 +$\|q\K\\{get\_avail}$;\5 +$\\{ref\_count}(\|q)\K\\{null}$;\5 +$\|r\K\\{get\_avail}$;\5 +$\\{link}(\|q)\K\|r$;\5 +$\\{info}(\|r)\K\\{general\_macro}$;\5 +$\\{link}(\|r)\K\\{scan\_toks}(\\{macro\_def},\39\|p,\39\\{null},\390)$;\5 +$\\{scanner\_status}\K\\{normal}$;\5 +$\\{eq\_type}(\\{warning\_info})\K\|m$;\5 +$\\{equiv}(\\{warning\_info})\K\|q$;\5 +\\{get\_x\_next};\6 +\&{end};\par +\fi + +\M695. Parameters to macros are introduced by the keywords \&{expr}, +\&{suffix}, \&{text}, \&{primary}, \&{secondary}, and \&{tertiary}. + +\Y\P$\4\X192:Put each of \MF's primitives into the hash table\X\mathrel{+}\S$\6 +$\\{primitive}(\.{"expr"},\39\\{param\_type},\39\\{expr\_base})$;\6 +$\\{primitive}(\.{"suffix"},\39\\{param\_type},\39\\{suffix\_base})$;\6 +$\\{primitive}(\.{"text"},\39\\{param\_type},\39\\{text\_base})$;\6 +$\\{primitive}(\.{"primary"},\39\\{param\_type},\39\\{primary\_macro})$;\6 +$\\{primitive}(\.{"secondary"},\39\\{param\_type},\39\\{secondary\_macro})$;\6 +$\\{primitive}(\.{"tertiary"},\39\\{param\_type},\39\\{tertiary\_macro})$;\par +\fi + +\M696. \P$\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of +primitives\X\mathrel{+}\S$\6 +\4\\{param\_type}: \37\&{if} $\|m\G\\{expr\_base}$ \1\&{then}\6 +\&{if} $\|m=\\{expr\_base}$ \1\&{then}\5 +$\\{print}(\.{"expr"})$\6 +\4\&{else} \&{if} $\|m=\\{suffix\_base}$ \1\&{then}\5 +$\\{print}(\.{"suffix"})$\6 +\4\&{else} $\\{print}(\.{"text"})$\2\2\6 +\4\&{else} \&{if} $\|m<\\{secondary\_macro}$ \1\&{then}\5 +$\\{print}(\.{"primary"})$\6 +\4\&{else} \&{if} $\|m=\\{secondary\_macro}$ \1\&{then}\5 +$\\{print}(\.{"secondary"})$\6 +\4\&{else} $\\{print}(\.{"tertiary"})$;\2\2\2\par +\fi + +\M697. Let's turn next to the more complex processing associated with \&{def} +and \&{vardef}. When the following procedure is called, \\{cur\_mod} +should be either \\{start\_def} or \\{var\_def}. + +\Y\P\hbox{\4}\X1032:Declare the procedure called \\{check\_delimiter}\X\6 +\hbox{\4}\X1011:Declare the function called \\{scan\_declared\_variable}\X\6 +\4\&{procedure}\1\ \37\\{scan\_def};\6 +\4\&{var} \37\|m: \37$\\{start\_def}\to\\{var\_def}$;\C{the type of definition}% +\6 +\|n: \37$0\to3$;\C{the number of special suffix parameters}\6 +\|k: \37$0\to\\{param\_size}$;\C{the total number of parameters}\6 +\|c: \37$\\{general\_macro}\to\\{text\_macro}$;\C{the kind of macro we're +defining}\6 +\|r: \37\\{pointer};\C{parameter-substitution list}\6 +\|q: \37\\{pointer};\C{tail of the macro token list}\6 +\|p: \37\\{pointer};\C{temporary storage}\6 +\\{base}: \37\\{halfword};\C{\\{expr\_base}, \\{suffix\_base}, or \\{text% +\_base}}\6 +$\\{l\_delim},\39\\{r\_delim}$: \37\\{pointer};\C{matching delimiters}\2\6 +\&{begin} \37$\|m\K\\{cur\_mod}$;\5 +$\|c\K\\{general\_macro}$;\5 +$\\{link}(\\{hold\_head})\K\\{null}$;\6 +$\|q\K\\{get\_avail}$;\5 +$\\{ref\_count}(\|q)\K\\{null}$;\5 +$\|r\K\\{null}$;\6 +\X700:Scan the token or variable to be defined; set \|n, \\{scanner\_status}, +and \\{warning\_info}\X;\6 +$\|k\K\|n$;\6 +\&{if} $\\{cur\_cmd}=\\{left\_delimiter}$ \1\&{then}\5 +\X703:Absorb delimited parameters, putting them into lists \|q and \|r\X;\2\6 +\&{if} $\\{cur\_cmd}=\\{param\_type}$ \1\&{then}\5 +\X705:Absorb undelimited parameters, putting them into list \|r\X;\2\6 +\\{check\_equals};\5 +$\|p\K\\{get\_avail}$;\5 +$\\{info}(\|p)\K\|c$;\5 +$\\{link}(\|q)\K\|p$;\5 +\X698:Attach the replacement text to the tail of node \|p\X;\6 +$\\{scanner\_status}\K\\{normal}$;\5 +\\{get\_x\_next};\6 +\&{end};\par +\fi + +\M698. We don't put `\\{frozen\_end\_group}' into the replacement text of +a \&{vardef}, because the user may want to redefine `\.{endgroup}'. + +\Y\P$\4\X698:Attach the replacement text to the tail of node \|p\X\S$\6 +\&{if} $\|m=\\{start\_def}$ \1\&{then}\5 +$\\{link}(\|p)\K\\{scan\_toks}(\\{macro\_def},\39\|r,\39\\{null},\39\|n)$\6 +\4\&{else} \&{begin} \37$\|q\K\\{get\_avail}$;\5 +$\\{info}(\|q)\K\\{bg\_loc}$;\5 +$\\{link}(\|p)\K\|q$;\5 +$\|p\K\\{get\_avail}$;\5 +$\\{info}(\|p)\K\\{eg\_loc}$;\5 +$\\{link}(\|q)\K\\{scan\_toks}(\\{macro\_def},\39\|r,\39\|p,\39\|n)$;\6 +\&{end};\2\6 +\&{if} $\\{warning\_info}=\\{bad\_vardef}$ \1\&{then}\5 +$\\{flush\_token\_list}(\\{value}(\\{bad\_vardef}))$\2\par +\U697.\fi + +\M699. \P$\X13:Global variables\X\mathrel{+}\S$\6 +\4$\\{bg\_loc},\39\\{eg\_loc}$: \37$1\to\\{hash\_end}$;\C{hash addresses of `% +\.{begingroup}' and `\.{endgroup}'}\par +\fi + +\M700. \P$\X700:Scan the token or variable to be defined; set \|n, \\{scanner% +\_status}, and \\{warning\_info}\X\S$\6 +\&{if} $\|m=\\{start\_def}$ \1\&{then}\6 +\&{begin} \37\\{get\_clear\_symbol};\5 +$\\{warning\_info}\K\\{cur\_sym}$;\5 +\\{get\_next};\5 +$\\{scanner\_status}\K\\{op\_defining}$;\5 +$\|n\K0$;\5 +$\\{eq\_type}(\\{warning\_info})\K\\{defined\_macro}$;\5 +$\\{equiv}(\\{warning\_info})\K\|q$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|p\K\\{scan\_declared\_variable}$;\5 +$\\{flush\_variable}(\\{equiv}(\\{info}(\|p)),\39\\{link}(\|p),\39\\{true})$;\5 +$\\{warning\_info}\K\\{find\_variable}(\|p)$;\5 +$\\{flush\_list}(\|p)$;\6 +\&{if} $\\{warning\_info}=\\{null}$ \1\&{then}\5 +\X701:Change to `\.{a bad variable}'\X;\2\6 +$\\{scanner\_status}\K\\{var\_defining}$;\5 +$\|n\K2$;\6 +\&{if} $\\{cur\_cmd}=\\{macro\_special}$ \1\&{then}\6 +\&{if} $\\{cur\_mod}=\\{macro\_suffix}$ \1\&{then}\C{\.{\AT!\#}}\6 +\&{begin} \37$\|n\K3$;\5 +\\{get\_next};\6 +\&{end};\2\2\6 +$\\{type}(\\{warning\_info})\K\\{unsuffixed\_macro}-2+\|n$;\5 +$\\{value}(\\{warning\_info})\K\|q$;\6 +\&{end}\C{$\\{suffixed\_macro}=\\{unsuffixed\_macro}+1$}\2\par +\U697.\fi + +\M701. \P$\X701:Change to `\.{a bad variable}'\X\S$\6 +\&{begin} \37$\\{print\_err}(\.{"This\ variable\ already\ starts\ with\ a\ +macro"})$;\5 +$\\{help2}(\.{"After\ \`vardef\ a\'\ you\ can\'t\ say\ \`vardef\ a.b\'."})$\6 +$(\.{"So\ I\'ll\ have\ to\ discard\ this\ definition."})$;\5 +\\{error};\5 +$\\{warning\_info}\K\\{bad\_vardef}$;\6 +\&{end}\par +\U700.\fi + +\M702. \P$\X176:Initialize table entries (done by \.{INIMF} only)\X\mathrel{+}% +\S$\6 +$\\{name\_type}(\\{bad\_vardef})\K\\{root}$;\5 +$\\{link}(\\{bad\_vardef})\K\\{frozen\_bad\_vardef}$;\5 +$\\{equiv}(\\{frozen\_bad\_vardef})\K\\{bad\_vardef}$;\5 +$\\{eq\_type}(\\{frozen\_bad\_vardef})\K\\{tag\_token}$;\par +\fi + +\M703. \P$\X703:Absorb delimited parameters, putting them into lists \|q and % +\|r\X\S$\6 +\1\&{repeat} \37$\\{l\_delim}\K\\{cur\_sym}$;\5 +$\\{r\_delim}\K\\{cur\_mod}$;\5 +\\{get\_next};\6 +\&{if} $(\\{cur\_cmd}=\\{param\_type})\W(\\{cur\_mod}\G\\{expr\_base})$ \1% +\&{then}\5 +$\\{base}\K\\{cur\_mod}$\6 +\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Missing\ parameter\ type;\ \`expr\'% +\ will\ be\ assumed"})$;\5 +$\\{help1}(\.{"You\ should\'ve\ had\ \`expr\'\ or\ \`suffix\'\ or\ \`text\'\ +here."})$;\5 +\\{back\_error};\5 +$\\{base}\K\\{expr\_base}$;\6 +\&{end};\2\6 +\X704:Absorb parameter tokens for type \\{base}\X;\6 +$\\{check\_delimiter}(\\{l\_delim},\39\\{r\_delim})$;\5 +\\{get\_next};\6 +\4\&{until}\5 +$\\{cur\_cmd}\I\\{left\_delimiter}$\2\par +\U697.\fi + +\M704. \P$\X704:Absorb parameter tokens for type \\{base}\X\S$\6 +\1\&{repeat} \37$\\{link}(\|q)\K\\{get\_avail}$;\5 +$\|q\K\\{link}(\|q)$;\5 +$\\{info}(\|q)\K\\{base}+\|k$;\6 +\\{get\_symbol};\5 +$\|p\K\\{get\_node}(\\{token\_node\_size})$;\5 +$\\{value}(\|p)\K\\{base}+\|k$;\5 +$\\{info}(\|p)\K\\{cur\_sym}$;\6 +\&{if} $\|k=\\{param\_size}$ \1\&{then}\5 +$\\{overflow}(\.{"parameter\ stack\ size"},\39\\{param\_size})$;\2\6 +$\\{incr}(\|k)$;\5 +$\\{link}(\|p)\K\|r$;\5 +$\|r\K\|p$;\5 +\\{get\_next};\6 +\4\&{until}\5 +$\\{cur\_cmd}\I\\{comma}$\2\par +\U703.\fi + +\M705. \P$\X705:Absorb undelimited parameters, putting them into list \|r\X\S$\6 +\&{begin} \37$\|p\K\\{get\_node}(\\{token\_node\_size})$;\6 +\&{if} $\\{cur\_mod}<\\{expr\_base}$ \1\&{then}\6 +\&{begin} \37$\|c\K\\{cur\_mod}$;\5 +$\\{value}(\|p)\K\\{expr\_base}+\|k$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{value}(\|p)\K\\{cur\_mod}+\|k$;\6 +\&{if} $\\{cur\_mod}=\\{expr\_base}$ \1\&{then}\5 +$\|c\K\\{expr\_macro}$\6 +\4\&{else} \&{if} $\\{cur\_mod}=\\{suffix\_base}$ \1\&{then}\5 +$\|c\K\\{suffix\_macro}$\6 +\4\&{else} $\|c\K\\{text\_macro}$;\2\2\6 +\&{end};\2\6 +\&{if} $\|k=\\{param\_size}$ \1\&{then}\5 +$\\{overflow}(\.{"parameter\ stack\ size"},\39\\{param\_size})$;\2\6 +$\\{incr}(\|k)$;\5 +\\{get\_symbol};\5 +$\\{info}(\|p)\K\\{cur\_sym}$;\5 +$\\{link}(\|p)\K\|r$;\5 +$\|r\K\|p$;\5 +\\{get\_next};\6 +\&{if} $\|c=\\{expr\_macro}$ \1\&{then}\6 +\&{if} $\\{cur\_cmd}=\\{of\_token}$ \1\&{then}\6 +\&{begin} \37$\|c\K\\{of\_macro}$;\5 +$\|p\K\\{get\_node}(\\{token\_node\_size})$;\6 +\&{if} $\|k=\\{param\_size}$ \1\&{then}\5 +$\\{overflow}(\.{"parameter\ stack\ size"},\39\\{param\_size})$;\2\6 +$\\{value}(\|p)\K\\{expr\_base}+\|k$;\5 +\\{get\_symbol};\5 +$\\{info}(\|p)\K\\{cur\_sym}$;\5 +$\\{link}(\|p)\K\|r$;\5 +$\|r\K\|p$;\5 +\\{get\_next};\6 +\&{end};\2\2\6 +\&{end}\par +\U697.\fi + +\N706. \[35] Expanding the next token. +Only a few command codes $<\\{min\_command}$ can possibly be returned by +\\{get\_next}; in increasing order, they are +\\{if\_test}, \\{fi\_or\_else}, \\{input}, \\{iteration}, \\{repeat\_loop}, +\\{exit\_test}, \\{relax}, \\{scan\_tokens}, \\{expand\_after}, and \\{defined% +\_macro}. + +\MF\ usually gets the next token of input by saying \\{get\_x\_next}. This is +like \\{get\_next} except that it keeps getting more tokens until +finding $\\{cur\_cmd}\G\\{min\_command}$. In other words, \\{get\_x\_next} +expands +macros and removes conditionals or iterations or input instructions that +might be present. + +It follows that \\{get\_x\_next} might invoke itself recursively. In fact, +there is massive recursion, since macro expansion can involve the +scanning of arbitrarily complex expressions, which in turn involve +macro expansion and conditionals, etc. + +Therefore it's necessary to declare a whole bunch of \\{forward} +procedures at this point, and to insert some other procedures +that will be invoked by \\{get\_x\_next}. + +\Y\P\4\&{procedure}\1\ \37\\{scan\_primary};\5 +\\{forward}; \hbox{\2} \6 +\4\&{procedure}\1\ \37\\{scan\_secondary};\5 +\\{forward}; \hbox{\2} \6 +\4\&{procedure}\1\ \37\\{scan\_tertiary};\5 +\\{forward}; \hbox{\2} \6 +\4\&{procedure}\1\ \37\\{scan\_expression};\5 +\\{forward}; \hbox{\2} \6 +\4\&{procedure}\1\ \37\\{scan\_suffix};\5 +\\{forward};\5 +\hbox{\2}\6 +\hbox{\4}\X720:Declare the procedure called \\{macro\_call}\X\6 +\4\&{procedure}\1\ \37\\{get\_boolean};\5 +\\{forward}; \hbox{\2} \6 +\4\&{procedure}\1\ \37\\{pass\_text};\5 +\\{forward}; \hbox{\2} \6 +\4\&{procedure}\1\ \37\\{conditional};\5 +\\{forward}; \hbox{\2} \6 +\4\&{procedure}\1\ \37\\{start\_input};\5 +\\{forward}; \hbox{\2} \6 +\4\&{procedure}\1\ \37\\{begin\_iteration};\5 +\\{forward}; \hbox{\2} \6 +\4\&{procedure}\1\ \37\\{resume\_iteration};\5 +\\{forward}; \hbox{\2} \6 +\4\&{procedure}\1\ \37\\{stop\_iteration};\5 +\\{forward};\5 +\hbox{\2}\par +\fi + +\M707. An auxiliary subroutine called \\{expand} is used by \\{get\_x\_next} +when it has to do exotic expansion commands. + +\Y\P\4\&{procedure}\1\ \37\\{expand};\6 +\4\&{var} \37\|p: \37\\{pointer};\C{for list manipulation}\6 +\|k: \37\\{integer};\C{something that we hope is $\L\\{buf\_size}$}\6 +\|j: \37\\{pool\_pointer};\C{index into \\{str\_pool}}\2\6 +\&{begin} \37\&{if} $\\{internal}[\\{tracing\_commands}]>\\{unity}$ \1\&{then}\6 +\&{if} $\\{cur\_cmd}\I\\{defined\_macro}$ \1\&{then}\5 +\\{show\_cur\_cmd\_mod};\2\2\6 +\&{case} $\\{cur\_cmd}$ \1\&{of}\6 +\4\\{if\_test}: \37\\{conditional};\C{this procedure is discussed in Part 36 +below}\6 +\4\\{fi\_or\_else}: \37\X751:Terminate the current conditional and skip to % +\&{fi}\X;\6 +\4\\{input}: \37\X711:Initiate or terminate input from a file\X;\6 +\4\\{iteration}: \37\&{if} $\\{cur\_mod}=\\{end\_for}$ \1\&{then}\5 +\X708:Scold the user for having an extra \&{endfor}\X\6 +\4\&{else} \\{begin\_iteration};\C{this procedure is discussed in Part 37 +below}\2\6 +\4\\{repeat\_loop}: \37\X712:Repeat a loop\X;\6 +\4\\{exit\_test}: \37\X713:Exit a loop if the proper time has come\X;\6 +\4\\{relax}: \37\\{do\_nothing};\6 +\4\\{expand\_after}: \37\X715:Expand the token after the next token\X;\6 +\4\\{scan\_tokens}: \37\X716:Put a string into the input buffer\X;\6 +\4\\{defined\_macro}: \37$\\{macro\_call}(\\{cur\_mod},\39\\{null},\39\\{cur% +\_sym})$;\2\6 +\&{end};\C{there are no other cases}\6 +\&{end};\par +\fi + +\M708. \P$\X708:Scold the user for having an extra \&{endfor}\X\S$\6 +\&{begin} \37$\\{print\_err}(\.{"Extra\ \`endfor\'"})$;\5 +$\\{help2}(\.{"I\'m\ not\ currently\ working\ on\ a\ for\ loop,"})$\6 +$(\.{"so\ I\ had\ better\ not\ try\ to\ end\ anything."})$;\6 +\\{error};\6 +\&{end}\par +\U707.\fi + +\M709. The processing of \&{input} involves the \\{start\_input} subroutine, +which will be declared later; the processing of \&{endinput} is trivial. + +\Y\P$\4\X192:Put each of \MF's primitives into the hash table\X\mathrel{+}\S$\6 +$\\{primitive}(\.{"input"},\39\\{input},\390)$;\6 +$\\{primitive}(\.{"endinput"},\39\\{input},\391)$;\par +\fi + +\M710. \P$\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of +primitives\X\mathrel{+}\S$\6 +\4\\{input}: \37\&{if} $\|m=0$ \1\&{then}\5 +$\\{print}(\.{"input"})$\ \&{else} $\\{print}(\.{"endinput"})$;\2\par +\fi + +\M711. \P$\X711:Initiate or terminate input from a file\X\S$\6 +\&{if} $\\{cur\_mod}>0$ \1\&{then}\5 +$\\{force\_eof}\K\\{true}$\6 +\4\&{else} \\{start\_input}\2\par +\U707.\fi + +\M712. We'll discuss the complicated parts of loop operations later. For now +it suffices to know that there's a global variable called \\{loop\_ptr} +that will be \\{null} if no loop is in progress. + +\Y\P$\4\X712:Repeat a loop\X\S$\6 +\&{begin} \37\&{while} $\\{token\_state}\W(\\{loc}=\\{null})$ \1\&{do}\5 +\\{end\_token\_list};\C{conserve stack space}\2\6 +\&{if} $\\{loop\_ptr}=\\{null}$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"Lost\ loop"})$;\5 +$\\{help2}(\.{"I\'m\ confused;\ after\ exiting\ from\ a\ loop,\ I\ still\ +seem"})$\6 +$(\.{"to\ want\ to\ repeat\ it.\ I\'ll\ try\ to\ forget\ the\ problem."})$;\6 +\\{error};\6 +\&{end}\6 +\4\&{else} \\{resume\_iteration};\C{this procedure is in Part 37 below}\2\6 +\&{end}\par +\U707.\fi + +\M713. \P$\X713:Exit a loop if the proper time has come\X\S$\6 +\&{begin} \37\\{get\_boolean};\6 +\&{if} $\\{internal}[\\{tracing\_commands}]>\\{unity}$ \1\&{then}\5 +$\\{show\_cmd\_mod}(\\{nullary},\39\\{cur\_exp})$;\2\6 +\&{if} $\\{cur\_exp}=\\{true\_code}$ \1\&{then}\6 +\&{if} $\\{loop\_ptr}=\\{null}$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"No\ loop\ is\ in\ progress"})$;\5 +$\\{help1}(\.{"Why\ say\ \`exitif\'\ when\ there\'s\ nothing\ to\ exit\ +from?"})$;\6 +\&{if} $\\{cur\_cmd}=\\{semicolon}$ \1\&{then}\5 +\\{error}\ \&{else} \\{back\_error};\2\6 +\&{end}\6 +\4\&{else} \X714:Exit prematurely from an iteration\X\2\6 +\4\&{else} \&{if} $\\{cur\_cmd}\I\\{semicolon}$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\.{";"})$;\6 +$\\{help2}(\.{"After\ \`exitif\ <boolean\ exp>\'\ I\ expect\ to\ see\ a\ +semicolon."})$\6 +$(\.{"I\ shall\ pretend\ that\ one\ was\ there."})$;\5 +\\{back\_error};\6 +\&{end};\2\2\6 +\&{end}\par +\U707.\fi + +\M714. Here we use the fact that \\{forever\_text} is the only \\{token\_type} +that +is less than \\{loop\_text}. + +\Y\P$\4\X714:Exit prematurely from an iteration\X\S$\6 +\&{begin} \37$\|p\K\\{null}$;\6 +\1\&{repeat} \37\&{if} $\\{file\_state}$ \1\&{then}\5 +\\{end\_file\_reading}\6 +\4\&{else} \&{begin} \37\&{if} $\\{token\_type}\L\\{loop\_text}$ \1\&{then}\5 +$\|p\K\\{start}$;\2\6 +\\{end\_token\_list};\6 +\&{end};\2\6 +\4\&{until}\5 +$\|p\I\\{null}$;\2\6 +\&{if} $\|p\I\\{info}(\\{loop\_ptr})$ \1\&{then}\5 +$\\{fatal\_error}(\.{"***\ (loop\ confusion)"})$;\2\6 +\\{stop\_iteration};\C{this procedure is in Part 37 below}\6 +\&{end}\par +\U713.\fi + +\M715. \P$\X715:Expand the token after the next token\X\S$\6 +\&{begin} \37\\{get\_next};\5 +$\|p\K\\{cur\_tok}$;\5 +\\{get\_next};\6 +\&{if} $\\{cur\_cmd}<\\{min\_command}$ \1\&{then}\5 +\\{expand}\6 +\4\&{else} \\{back\_input};\2\6 +$\\{back\_list}(\|p)$;\6 +\&{end}\par +\U707.\fi + +\M716. \P$\X716:Put a string into the input buffer\X\S$\6 +\&{begin} \37\\{get\_x\_next};\5 +\\{scan\_primary};\6 +\&{if} $\\{cur\_type}\I\\{string\_type}$ \1\&{then}\6 +\&{begin} \37$\\{disp\_err}(\\{null},\39\.{"Not\ a\ string"})$;\5 +$\\{help2}(\.{"I\'m\ going\ to\ flush\ this\ expression,\ since"})$\6 +$(\.{"scantokens\ should\ be\ followed\ by\ a\ known\ string."})$;\5 +$\\{put\_get\_flush\_error}(0)$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37\\{back\_input};\6 +\&{if} $\\{length}(\\{cur\_exp})>0$ \1\&{then}\5 +\X717:Pretend we're reading a new one-line file\X;\2\6 +\&{end};\2\6 +\&{end}\par +\U707.\fi + +\M717. \P$\X717:Pretend we're reading a new one-line file\X\S$\6 +\&{begin} \37\\{begin\_file\_reading};\5 +$\\{name}\K2$;\5 +$\|k\K\\{first}+\\{length}(\\{cur\_exp})$;\6 +\&{if} $\|k\G\\{max\_buf\_stack}$ \1\&{then}\6 +\&{begin} \37\&{if} $\|k\G\\{buf\_size}$ \1\&{then}\6 +\&{begin} \37$\\{max\_buf\_stack}\K\\{buf\_size}$;\5 +$\\{overflow}(\.{"buffer\ size"},\39\\{buf\_size})$;\6 +\&{end};\2\6 +$\\{max\_buf\_stack}\K\|k+1$;\6 +\&{end};\2\6 +$\|j\K\\{str\_start}[\\{cur\_exp}]$;\5 +$\\{limit}\K\|k$;\6 +\&{while} $\\{first}<\\{limit}$ \1\&{do}\6 +\&{begin} \37$\\{buffer}[\\{first}]\K\\{so}(\\{str\_pool}[\|j])$;\5 +$\\{incr}(\|j)$;\5 +$\\{incr}(\\{first})$;\6 +\&{end};\2\6 +$\\{buffer}[\\{limit}]\K\.{"\%"}$;\5 +$\\{first}\K\\{limit}+1$;\5 +$\\{loc}\K\\{start}$;\5 +$\\{flush\_cur\_exp}(0)$;\6 +\&{end}\par +\U716.\fi + +\M718. Here finally is \\{get\_x\_next}. + +The expression scanning routines to be considered later +communicate via the global quantities \\{cur\_type} and \\{cur\_exp}; +we must be very careful to save and restore these quantities while +macros are being expanded. + +\Y\P\4\&{procedure}\1\ \37\\{get\_x\_next};\6 +\4\&{var} \37\\{save\_exp}: \37\\{pointer};\C{a capsule to save \\{cur\_type} +and \\{cur\_exp}}\2\6 +\&{begin} \37\\{get\_next};\6 +\&{if} $\\{cur\_cmd}<\\{min\_command}$ \1\&{then}\6 +\&{begin} \37$\\{save\_exp}\K\\{stash\_cur\_exp}$;\6 +\1\&{repeat} \37\&{if} $\\{cur\_cmd}=\\{defined\_macro}$ \1\&{then}\5 +$\\{macro\_call}(\\{cur\_mod},\39\\{null},\39\\{cur\_sym})$\6 +\4\&{else} \\{expand};\2\6 +\\{get\_next};\6 +\4\&{until}\5 +$\\{cur\_cmd}\G\\{min\_command}$;\2\6 +$\\{unstash\_cur\_exp}(\\{save\_exp})$;\C{that restores \\{cur\_type} and % +\\{cur\_exp}}\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M719. Now let's consider the \\{macro\_call} procedure, which is used to start +up +all user-defined macros. Since the arguments to a macro might be expressions, +\\{macro\_call} is recursive. + +The first parameter to \\{macro\_call} points to the reference count of the +token list that defines the macro. The second parameter contains any +arguments that have already been parsed (see below). The third parameter +points to the symbolic token that names the macro. If the third parameter +is \\{null}, the macro was defined by \&{vardef}, so its name can be +reconstructed from the prefix and ``at'' arguments found within the +second parameter. + +What is this second parameter? It's simply a linked list of one-word items, +whose \\{info} fields point to the arguments. In other words, if $\\{arg% +\_list}=\\{null}$, +no arguments have been scanned yet; otherwise $\\{info}(\\{arg\_list})$ points +to +the first scanned argument, and $\\{link}(\\{arg\_list})$ points to the list of +further arguments (if any). + +Arguments of type \&{expr} are so-called capsules, which we will +discuss later when we concentrate on expressions; they can be +recognized easily because their \\{link} field is \\{void}. Arguments of type +\&{suffix} and \&{text} are token lists without reference counts. + +\fi + +\M720. After argument scanning is complete, the arguments are moved to the +\\{param\_stack}. (They can't be put on that stack any sooner, because +the stack is growing and shrinking in unpredictable ways as more arguments +are being acquired.) Then the macro body is fed to the scanner; i.e., +the replacement text of the macro is placed at the top of the \MF's +input stack, so that \\{get\_next} will proceed to read it next. + +\Y\P$\4\X720:Declare the procedure called \\{macro\_call}\X\S$\6 +\hbox{\4}\X722:Declare the procedure called \\{print\_macro\_name}\X\6 +\hbox{\4}\X723:Declare the procedure called \\{print\_arg}\X\6 +\hbox{\4}\X730:Declare the procedure called \\{scan\_text\_arg}\X\6 +\4\&{procedure}\1\ \37$\\{macro\_call}(\\{def\_ref},\39\\{arg\_list},\39% +\\{macro\_name}:\\{pointer})$;\C{invokes a user-defined control sequence}\6 +\4\&{label} \37\\{found};\6 +\4\&{var} \37\|r: \37\\{pointer};\C{current node in the macro's token list}\6 +$\|p,\39\|q$: \37\\{pointer};\C{for list manipulation}\6 +\|n: \37\\{integer};\C{the number of arguments}\6 +$\\{l\_delim},\39\\{r\_delim}$: \37\\{pointer};\C{a delimiter pair}\6 +\\{tail}: \37\\{pointer};\C{tail of the argument list}\2\6 +\&{begin} \37$\|r\K\\{link}(\\{def\_ref})$;\5 +$\\{add\_mac\_ref}(\\{def\_ref})$;\6 +\&{if} $\\{arg\_list}=\\{null}$ \1\&{then}\5 +$\|n\K0$\6 +\4\&{else} \X724:Determine the number \|n of arguments already supplied, and +set \\{tail} to the tail of \\{arg\_list}\X;\2\6 +\&{if} $\\{internal}[\\{tracing\_macros}]>0$ \1\&{then}\5 +\X721:Show the text of the macro being expanded, and the existing arguments\X;% +\2\6 +\X725:Scan the remaining arguments, if any; set \|r to the first token of the +replacement text\X;\6 +\X736:Feed the arguments and replacement text to the scanner\X;\6 +\&{end};\par +\U706.\fi + +\M721. \P$\X721:Show the text of the macro being expanded, and the existing +arguments\X\S$\6 +\&{begin} \37\\{begin\_diagnostic};\5 +\\{print\_ln};\5 +$\\{print\_macro\_name}(\\{arg\_list},\39\\{macro\_name})$;\6 +\&{if} $\|n=3$ \1\&{then}\5 +$\\{print}(\.{"@\#"})$;\C{indicate a suffixed macro}\2\6 +$\\{show\_macro}(\\{def\_ref},\39\\{null},\39100000)$;\6 +\&{if} $\\{arg\_list}\I\\{null}$ \1\&{then}\6 +\&{begin} \37$\|n\K0$;\5 +$\|p\K\\{arg\_list}$;\6 +\1\&{repeat} \37$\|q\K\\{info}(\|p)$;\5 +$\\{print\_arg}(\|q,\39\|n,\390)$;\5 +$\\{incr}(\|n)$;\5 +$\|p\K\\{link}(\|p)$;\6 +\4\&{until}\5 +$\|p=\\{null}$;\2\6 +\&{end};\2\6 +$\\{end\_diagnostic}(\\{false})$;\6 +\&{end}\par +\U720.\fi + +\M722. \P$\X722:Declare the procedure called \\{print\_macro\_name}\X\S$\6 +\4\&{procedure}\1\ \37$\\{print\_macro\_name}(\|a,\39\|n:\\{pointer})$;\6 +\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{they traverse the first part of % +\|a}\2\6 +\&{begin} \37\&{if} $\|n\I\\{null}$ \1\&{then}\5 +$\\{slow\_print}(\\{text}(\|n))$\6 +\4\&{else} \&{begin} \37$\|p\K\\{info}(\|a)$;\6 +\&{if} $\|p=\\{null}$ \1\&{then}\5 +$\\{slow\_print}(\\{text}(\\{info}(\\{info}(\\{link}(\|a)))))$\6 +\4\&{else} \&{begin} \37$\|q\K\|p$;\6 +\&{while} $\\{link}(\|q)\I\\{null}$ \1\&{do}\5 +$\|q\K\\{link}(\|q)$;\2\6 +$\\{link}(\|q)\K\\{info}(\\{link}(\|a))$;\5 +$\\{show\_token\_list}(\|p,\39\\{null},\391000,\390)$;\5 +$\\{link}(\|q)\K\\{null}$;\6 +\&{end};\2\6 +\&{end};\2\6 +\&{end};\par +\U720.\fi + +\M723. \P$\X723:Declare the procedure called \\{print\_arg}\X\S$\6 +\4\&{procedure}\1\ \37$\\{print\_arg}(\|q:\\{pointer};\,\35\|n:\\{integer};\,% +\35\|b:\\{pointer})$;\2\6 +\&{begin} \37\&{if} $\\{link}(\|q)=\\{void}$ \1\&{then}\5 +$\\{print\_nl}(\.{"(EXPR"})$\6 +\4\&{else} \&{if} $(\|b<\\{text\_base})\W(\|b\I\\{text\_macro})$ \1\&{then}\5 +$\\{print\_nl}(\.{"(SUFFIX"})$\6 +\4\&{else} $\\{print\_nl}(\.{"(TEXT"})$;\2\2\6 +$\\{print\_int}(\|n)$;\5 +$\\{print}(\.{")<-"})$;\6 +\&{if} $\\{link}(\|q)=\\{void}$ \1\&{then}\5 +$\\{print\_exp}(\|q,\391)$\6 +\4\&{else} $\\{show\_token\_list}(\|q,\39\\{null},\391000,\390)$;\2\6 +\&{end};\par +\U720.\fi + +\M724. \P$\X724:Determine the number \|n of arguments already supplied, and set +\\{tail} to the tail of \\{arg\_list}\X\S$\6 +\&{begin} \37$\|n\K1$;\5 +$\\{tail}\K\\{arg\_list}$;\6 +\&{while} $\\{link}(\\{tail})\I\\{null}$ \1\&{do}\6 +\&{begin} \37$\\{incr}(\|n)$;\5 +$\\{tail}\K\\{link}(\\{tail})$;\6 +\&{end};\2\6 +\&{end}\par +\U720.\fi + +\M725. \P$\X725:Scan the remaining arguments, if any; set \|r to the first +token of the replacement text\X\S$\6 +$\\{cur\_cmd}\K\\{comma}+1$;\C{anything $\I\\{comma}$ will do}\6 +\&{while} $\\{info}(\|r)\G\\{expr\_base}$ \1\&{do}\6 +\&{begin} \37\X726:Scan the delimited argument represented by $\\{info}(\|r)$% +\X;\6 +$\|r\K\\{link}(\|r)$;\6 +\&{end};\2\6 +\&{if} $\\{cur\_cmd}=\\{comma}$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"Too\ many\ arguments\ to\ "})$;\5 +$\\{print\_macro\_name}(\\{arg\_list},\39\\{macro\_name})$;\5 +$\\{print\_char}(\.{";"})$;\5 +$\\{print\_nl}(\.{"\ \ Missing\ \`"})$;\5 +$\\{slow\_print}(\\{text}(\\{r\_delim}))$;\5 +$\\{print}(\.{"\'\ has\ been\ inserted"})$;\5 +$\\{help3}(\.{"I\'m\ going\ to\ assume\ that\ the\ comma\ I\ just\ read\ was\ +a"})$\6 +$(\.{"right\ delimiter,\ and\ then\ I\'ll\ begin\ expanding\ the\ macro."})$\6 +$(\.{"You\ might\ want\ to\ delete\ some\ tokens\ before\ continuing."})$;\5 +\\{error};\6 +\&{end};\2\6 +\&{if} $\\{info}(\|r)\I\\{general\_macro}$ \1\&{then}\5 +\X733:Scan undelimited argument(s)\X;\2\6 +$\|r\K\\{link}(\|r)$\par +\U720.\fi + +\M726. At this point, the reader will find it advisable to review the +explanation +of token list format that was presented earlier, paying special attention to +the conventions that apply only at the beginning of a macro's token list. + +On the other hand, the reader will have to take the expression-parsing +aspects of the following program on faith; we will explain \\{cur\_type} +and \\{cur\_exp} later. (Several things in this program depend on each other, +and it's necessary to jump into the circle somewhere.) + +\Y\P$\4\X726:Scan the delimited argument represented by $\\{info}(\|r)$\X\S$\6 +\&{if} $\\{cur\_cmd}\I\\{comma}$ \1\&{then}\6 +\&{begin} \37\\{get\_x\_next};\6 +\&{if} $\\{cur\_cmd}\I\\{left\_delimiter}$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"Missing\ argument\ to\ "})$;\5 +$\\{print\_macro\_name}(\\{arg\_list},\39\\{macro\_name})$;\5 +$\\{help3}(\.{"That\ macro\ has\ more\ parameters\ than\ you\ thought."})$\6 +$(\.{"I\'ll\ continue\ by\ pretending\ that\ each\ missing\ argument"})$\6 +$(\.{"is\ either\ zero\ or\ null."})$;\6 +\&{if} $\\{info}(\|r)\G\\{suffix\_base}$ \1\&{then}\6 +\&{begin} \37$\\{cur\_exp}\K\\{null}$;\5 +$\\{cur\_type}\K\\{token\_list}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{cur\_exp}\K0$;\5 +$\\{cur\_type}\K\\{known}$;\6 +\&{end};\2\6 +\\{back\_error};\5 +$\\{cur\_cmd}\K\\{right\_delimiter}$;\5 +\&{goto} \37\\{found};\6 +\&{end};\2\6 +$\\{l\_delim}\K\\{cur\_sym}$;\5 +$\\{r\_delim}\K\\{cur\_mod}$;\6 +\&{end};\2\6 +\X729:Scan the argument represented by $\\{info}(\|r)$\X;\6 +\&{if} $\\{cur\_cmd}\I\\{comma}$ \1\&{then}\5 +\X727:Check that the proper right delimiter was present\X;\2\6 +\4\\{found}: \37\X728:Append the current expression to \\{arg\_list}\X\par +\U725.\fi + +\M727. \P$\X727:Check that the proper right delimiter was present\X\S$\6 +\&{if} $(\\{cur\_cmd}\I\\{right\_delimiter})\V(\\{cur\_mod}\I\\{l\_delim})$ \1% +\&{then}\6 +\&{if} $\\{info}(\\{link}(\|r))\G\\{expr\_base}$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\.{","})$;\5 +$\\{help3}(\.{"I\'ve\ finished\ reading\ a\ macro\ argument\ and\ am\ about\ +to"})$\6 +$(\.{"read\ another;\ the\ arguments\ weren\'t\ delimited\ correctly."})$\6 +$(\.{"You\ might\ want\ to\ delete\ some\ tokens\ before\ continuing."})$;\5 +\\{back\_error};\5 +$\\{cur\_cmd}\K\\{comma}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{missing\_err}(\\{text}(\\{r\_delim}))$;\5 +$\\{help2}(\.{"I\'ve\ gotten\ to\ the\ end\ of\ the\ macro\ parameter\ +list."})$\6 +$(\.{"You\ might\ want\ to\ delete\ some\ tokens\ before\ continuing."})$;\5 +\\{back\_error};\6 +\&{end}\2\2\par +\U726.\fi + +\M728. A \&{suffix} or \&{text} parameter will be have been scanned as +a token list pointed to by \\{cur\_exp}, in which case we will have +$\\{cur\_type}=\\{token\_list}$. + +\Y\P$\4\X728:Append the current expression to \\{arg\_list}\X\S$\6 +\&{begin} \37$\|p\K\\{get\_avail}$;\6 +\&{if} $\\{cur\_type}=\\{token\_list}$ \1\&{then}\5 +$\\{info}(\|p)\K\\{cur\_exp}$\6 +\4\&{else} $\\{info}(\|p)\K\\{stash\_cur\_exp}$;\2\6 +\&{if} $\\{internal}[\\{tracing\_macros}]>0$ \1\&{then}\6 +\&{begin} \37\\{begin\_diagnostic};\5 +$\\{print\_arg}(\\{info}(\|p),\39\|n,\39\\{info}(\|r))$;\5 +$\\{end\_diagnostic}(\\{false})$;\6 +\&{end};\2\6 +\&{if} $\\{arg\_list}=\\{null}$ \1\&{then}\5 +$\\{arg\_list}\K\|p$\6 +\4\&{else} $\\{link}(\\{tail})\K\|p$;\2\6 +$\\{tail}\K\|p$;\5 +$\\{incr}(\|n)$;\6 +\&{end}\par +\Us726\ET733.\fi + +\M729. \P$\X729:Scan the argument represented by $\\{info}(\|r)$\X\S$\6 +\&{if} $\\{info}(\|r)\G\\{text\_base}$ \1\&{then}\5 +$\\{scan\_text\_arg}(\\{l\_delim},\39\\{r\_delim})$\6 +\4\&{else} \&{begin} \37\\{get\_x\_next};\6 +\&{if} $\\{info}(\|r)\G\\{suffix\_base}$ \1\&{then}\5 +\\{scan\_suffix}\6 +\4\&{else} \\{scan\_expression};\2\6 +\&{end}\2\par +\U726.\fi + +\M730. The parameters to \\{scan\_text\_arg} are either a pair of delimiters +or zero; the latter case is for undelimited text arguments, which +end with the first semicolon or \&{endgroup} or \&{end} that is not +contained in a group. + +\Y\P$\4\X730:Declare the procedure called \\{scan\_text\_arg}\X\S$\6 +\4\&{procedure}\1\ \37$\\{scan\_text\_arg}(\\{l\_delim},\39\\{r\_delim}:% +\\{pointer})$;\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37\\{balance}: \37\\{integer};\C{excess of \\{l\_delim} over \\{r% +\_delim}}\6 +\|p: \37\\{pointer};\C{list tail}\2\6 +\&{begin} \37$\\{warning\_info}\K\\{l\_delim}$;\5 +$\\{scanner\_status}\K\\{absorbing}$;\5 +$\|p\K\\{hold\_head}$;\5 +$\\{balance}\K1$;\5 +$\\{link}(\\{hold\_head})\K\\{null}$;\6 +\~ \1\&{loop}\ \&{begin} \37\\{get\_next};\6 +\&{if} $\\{l\_delim}=0$ \1\&{then}\5 +\X732:Adjust the balance for an undelimited argument; \&{goto} \\{done} if done% +\X\6 +\4\&{else} \X731:Adjust the balance for a delimited argument; \&{goto} \\{done} +if done\X;\2\6 +$\\{link}(\|p)\K\\{cur\_tok}$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +\4\\{done}: \37$\\{cur\_exp}\K\\{link}(\\{hold\_head})$;\5 +$\\{cur\_type}\K\\{token\_list}$;\5 +$\\{scanner\_status}\K\\{normal}$;\6 +\&{end};\par +\U720.\fi + +\M731. \P$\X731:Adjust the balance for a delimited argument; \&{goto} \\{done} +if done\X\S$\6 +\&{begin} \37\&{if} $\\{cur\_cmd}=\\{right\_delimiter}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{cur\_mod}=\\{l\_delim}$ \1\&{then}\6 +\&{begin} \37$\\{decr}(\\{balance})$;\6 +\&{if} $\\{balance}=0$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +\&{end};\2\6 +\&{end}\6 +\4\&{else} \&{if} $\\{cur\_cmd}=\\{left\_delimiter}$ \1\&{then}\6 +\&{if} $\\{cur\_mod}=\\{r\_delim}$ \1\&{then}\5 +$\\{incr}(\\{balance})$;\2\2\2\6 +\&{end}\par +\U730.\fi + +\M732. \P$\X732:Adjust the balance for an undelimited argument; \&{goto} % +\\{done} if done\X\S$\6 +\&{begin} \37\&{if} $\\{end\_of\_statement}$ \1\&{then}\C{$\\{cur\_cmd}=% +\\{semicolon}$, \\{end\_group}, or \\{stop}}\6 +\&{begin} \37\&{if} $\\{balance}=1$ \1\&{then}\5 +\&{goto} \37\\{done}\6 +\4\&{else} \&{if} $\\{cur\_cmd}=\\{end\_group}$ \1\&{then}\5 +$\\{decr}(\\{balance})$;\2\2\6 +\&{end}\6 +\4\&{else} \&{if} $\\{cur\_cmd}=\\{begin\_group}$ \1\&{then}\5 +$\\{incr}(\\{balance})$;\2\2\6 +\&{end}\par +\U730.\fi + +\M733. \P$\X733:Scan undelimited argument(s)\X\S$\6 +\&{begin} \37\&{if} $\\{info}(\|r)<\\{text\_macro}$ \1\&{then}\6 +\&{begin} \37\\{get\_x\_next};\6 +\&{if} $\\{info}(\|r)\I\\{suffix\_macro}$ \1\&{then}\6 +\&{if} $(\\{cur\_cmd}=\\{equals})\V(\\{cur\_cmd}=\\{assignment})$ \1\&{then}\5 +\\{get\_x\_next};\2\2\6 +\&{end};\2\6 +\&{case} $\\{info}(\|r)$ \1\&{of}\6 +\4\\{primary\_macro}: \37\\{scan\_primary};\6 +\4\\{secondary\_macro}: \37\\{scan\_secondary};\6 +\4\\{tertiary\_macro}: \37\\{scan\_tertiary};\6 +\4\\{expr\_macro}: \37\\{scan\_expression};\6 +\4\\{of\_macro}: \37\X734:Scan an expression followed by `\&{of} $% +\langle$primary$\rangle$'\X;\6 +\4\\{suffix\_macro}: \37\X735:Scan a suffix with optional delimiters\X;\6 +\4\\{text\_macro}: \37$\\{scan\_text\_arg}(0,\390)$;\2\6 +\&{end};\C{there are no other cases}\6 +\\{back\_input};\5 +\X728:Append the current expression to \\{arg\_list}\X;\6 +\&{end}\par +\U725.\fi + +\M734. \P$\X734:Scan an expression followed by `\&{of} $\langle$primary$% +\rangle$'\X\S$\6 +\&{begin} \37\\{scan\_expression};\5 +$\|p\K\\{get\_avail}$;\5 +$\\{info}(\|p)\K\\{stash\_cur\_exp}$;\6 +\&{if} $\\{internal}[\\{tracing\_macros}]>0$ \1\&{then}\6 +\&{begin} \37\\{begin\_diagnostic};\5 +$\\{print\_arg}(\\{info}(\|p),\39\|n,\390)$;\5 +$\\{end\_diagnostic}(\\{false})$;\6 +\&{end};\2\6 +\&{if} $\\{arg\_list}=\\{null}$ \1\&{then}\5 +$\\{arg\_list}\K\|p$\ \&{else} $\\{link}(\\{tail})\K\|p$;\2\6 +$\\{tail}\K\|p$;\5 +$\\{incr}(\|n)$;\6 +\&{if} $\\{cur\_cmd}\I\\{of\_token}$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\.{"of"})$;\5 +$\\{print}(\.{"\ for\ "})$;\5 +$\\{print\_macro\_name}(\\{arg\_list},\39\\{macro\_name})$;\5 +$\\{help1}(\.{"I\'ve\ got\ the\ first\ argument;\ will\ look\ now\ for\ the\ +other."})$;\5 +\\{back\_error};\6 +\&{end};\2\6 +\\{get\_x\_next};\5 +\\{scan\_primary};\6 +\&{end}\par +\U733.\fi + +\M735. \P$\X735:Scan a suffix with optional delimiters\X\S$\6 +\&{begin} \37\&{if} $\\{cur\_cmd}\I\\{left\_delimiter}$ \1\&{then}\5 +$\\{l\_delim}\K\\{null}$\6 +\4\&{else} \&{begin} \37$\\{l\_delim}\K\\{cur\_sym}$;\5 +$\\{r\_delim}\K\\{cur\_mod}$;\5 +\\{get\_x\_next};\6 +\&{end};\2\6 +\\{scan\_suffix};\6 +\&{if} $\\{l\_delim}\I\\{null}$ \1\&{then}\6 +\&{begin} \37\&{if} $(\\{cur\_cmd}\I\\{right\_delimiter})\V(\\{cur\_mod}\I\\{l% +\_delim})$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\\{text}(\\{r\_delim}))$;\5 +$\\{help2}(\.{"I\'ve\ gotten\ to\ the\ end\ of\ the\ macro\ parameter\ +list."})$\6 +$(\.{"You\ might\ want\ to\ delete\ some\ tokens\ before\ continuing."})$;\5 +\\{back\_error};\6 +\&{end};\2\6 +\\{get\_x\_next};\6 +\&{end};\2\6 +\&{end}\par +\U733.\fi + +\M736. Before we put a new token list on the input stack, it is wise to clean +off +all token lists that have recently been depleted. Then a user macro that ends +with a call to itself will not require unbounded stack space. + +\Y\P$\4\X736:Feed the arguments and replacement text to the scanner\X\S$\6 +\&{while} $\\{token\_state}\W(\\{loc}=\\{null})$ \1\&{do}\5 +\\{end\_token\_list};\C{conserve stack space}\2\6 +\&{if} $\\{param\_ptr}+\|n>\\{max\_param\_stack}$ \1\&{then}\6 +\&{begin} \37$\\{max\_param\_stack}\K\\{param\_ptr}+\|n$;\6 +\&{if} $\\{max\_param\_stack}>\\{param\_size}$ \1\&{then}\5 +$\\{overflow}(\.{"parameter\ stack\ size"},\39\\{param\_size})$;\2\6 +\&{end};\2\6 +$\\{begin\_token\_list}(\\{def\_ref},\39\\{macro})$;\5 +$\\{name}\K\\{macro\_name}$;\5 +$\\{loc}\K\|r$;\6 +\&{if} $\|n>0$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{arg\_list}$;\6 +\1\&{repeat} \37$\\{param\_stack}[\\{param\_ptr}]\K\\{info}(\|p)$;\5 +$\\{incr}(\\{param\_ptr})$;\5 +$\|p\K\\{link}(\|p)$;\6 +\4\&{until}\5 +$\|p=\\{null}$;\2\6 +$\\{flush\_list}(\\{arg\_list})$;\6 +\&{end}\2\par +\U720.\fi + +\M737. It's sometimes necessary to put a single argument onto \\{param\_stack}. +The \\{stack\_argument} subroutine does this. + +\Y\P\4\&{procedure}\1\ \37$\\{stack\_argument}(\|p:\\{pointer})$;\2\6 +\&{begin} \37\&{if} $\\{param\_ptr}=\\{max\_param\_stack}$ \1\&{then}\6 +\&{begin} \37$\\{incr}(\\{max\_param\_stack})$;\6 +\&{if} $\\{max\_param\_stack}>\\{param\_size}$ \1\&{then}\5 +$\\{overflow}(\.{"parameter\ stack\ size"},\39\\{param\_size})$;\2\6 +\&{end};\2\6 +$\\{param\_stack}[\\{param\_ptr}]\K\|p$;\5 +$\\{incr}(\\{param\_ptr})$;\6 +\&{end};\par +\fi + +\N738. \[36] Conditional processing. +Let's consider now the way \&{if} commands are handled. + +Conditions can be inside conditions, and this nesting has a stack +that is independent of other stacks. +Four global variables represent the top of the condition stack: +\\{cond\_ptr} points to pushed-down entries, if~any; \\{cur\_if} tells whether +we are processing \&{if} or \&{elseif}; \\{if\_limit} specifies +the largest code of a \\{fi\_or\_else} command that is syntactically legal; +and \\{if\_line} is the line number at which the current conditional 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}, \\{name% +\_type}, and +\\{link} fields of the first word contain \\{if\_limit}, \\{cur\_if}, and +\\{cond\_ptr} at the next level, and the second word contains the +corresponding \\{if\_line}. + +\Y\P\D \37$\\{if\_node\_size}=2$\C{number of words in stack entry for +conditionals}\par +\P\D \37$\\{if\_line\_field}(\#)\S\\{mem}[\#+1].\\{int}$\par +\P\D \37$\\{if\_code}=1$\C{code for \&{if} being evaluated}\par +\P\D \37$\\{fi\_code}=2$\C{code for \&{fi}}\par +\P\D \37$\\{else\_code}=3$\C{code for \&{else}}\par +\P\D \37$\\{else\_if\_code}=4$\C{code for \&{elseif}}\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{cond\_ptr}: \37\\{pointer};\C{top of the condition stack}\6 +\4\\{if\_limit}: \37$\\{normal}\to\\{else\_if\_code}$;\C{upper bound on \\{fi% +\_or\_else} codes}\6 +\4\\{cur\_if}: \37\\{small\_number};\C{type of conditional being worked on}\6 +\4\\{if\_line}: \37\\{integer};\C{line where that conditional began}\par +\fi + +\M739. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{cond\_ptr}\K\\{null}$;\5 +$\\{if\_limit}\K\\{normal}$;\5 +$\\{cur\_if}\K0$;\5 +$\\{if\_line}\K0$;\par +\fi + +\M740. \P$\X192:Put each of \MF's primitives into the hash table\X\mathrel{+}% +\S$\6 +$\\{primitive}(\.{"if"},\39\\{if\_test},\39\\{if\_code})$;\6 +$\\{primitive}(\.{"fi"},\39\\{fi\_or\_else},\39\\{fi\_code})$;\5 +$\\{eqtb}[\\{frozen\_fi}]\K\\{eqtb}[\\{cur\_sym}]$;\6 +$\\{primitive}(\.{"else"},\39\\{fi\_or\_else},\39\\{else\_code})$;\6 +$\\{primitive}(\.{"elseif"},\39\\{fi\_or\_else},\39\\{else\_if\_code})$;\par +\fi + +\M741. \P$\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of +primitives\X\mathrel{+}\S$\6 +\4$\\{if\_test},\39\\{fi\_or\_else}$: \37\&{case} $\|m$ \1\&{of}\6 +\4\\{if\_code}: \37$\\{print}(\.{"if"})$;\6 +\4\\{fi\_code}: \37$\\{print}(\.{"fi"})$;\6 +\4\\{else\_code}: \37$\\{print}(\.{"else"})$;\6 +\4\&{othercases} \37$\\{print}(\.{"elseif"})$\2\6 +\&{endcases};\par +\fi + +\M742. Here is a procedure that ignores text until coming to an \&{elseif}, +\&{else}, or \&{fi} at level zero of $\&{if}\ldots\&{fi}$ +nesting. After it has acted, \\{cur\_mod} will indicate the token that +was found. + +\MF's smallest two command codes are \\{if\_test} and \\{fi\_or\_else}; this +makes the skipping process a bit simpler. + +\Y\P\4\&{procedure}\1\ \37\\{pass\_text};\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37\|l: \37\\{integer};\2\6 +\&{begin} \37$\\{scanner\_status}\K\\{skipping}$;\5 +$\|l\K0$;\5 +$\\{warning\_info}\K\\{line}$;\6 +\~ \1\&{loop}\ \&{begin} \37\\{get\_next};\6 +\&{if} $\\{cur\_cmd}\L\\{fi\_or\_else}$ \1\&{then}\6 +\&{if} $\\{cur\_cmd}<\\{fi\_or\_else}$ \1\&{then}\5 +$\\{incr}(\|l)$\6 +\4\&{else} \&{begin} \37\&{if} $\|l=0$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +\&{if} $\\{cur\_mod}=\\{fi\_code}$ \1\&{then}\5 +$\\{decr}(\|l)$;\2\6 +\&{end}\2\6 +\4\&{else} \X743:Decrease the string reference count, if the current token is a +string\X;\2\6 +\&{end};\2\6 +\4\\{done}: \37$\\{scanner\_status}\K\\{normal}$;\6 +\&{end};\par +\fi + +\M743. \P$\X743:Decrease the string reference count, if the current token is a +string\X\S$\6 +\&{if} $\\{cur\_cmd}=\\{string\_token}$ \1\&{then}\5 +$\\{delete\_str\_ref}(\\{cur\_mod})$\2\par +\Us83, 742, 991\ETs1016.\fi + +\M744. When we begin to process a new \&{if}, we set $\\{if\_limit}\K\\{if% +\_code}$; then +if \&{elseif} or \&{else} or \&{fi} occurs before the current \&{if} +condition has been evaluated, a colon will be inserted. +A construction like `\.{if fi}' would otherwise get \MF\ confused. + +\Y\P$\4\X744:Push the condition stack\X\S$\6 +\&{begin} \37$\|p\K\\{get\_node}(\\{if\_node\_size})$;\5 +$\\{link}(\|p)\K\\{cond\_ptr}$;\5 +$\\{type}(\|p)\K\\{if\_limit}$;\5 +$\\{name\_type}(\|p)\K\\{cur\_if}$;\5 +$\\{if\_line\_field}(\|p)\K\\{if\_line}$;\5 +$\\{cond\_ptr}\K\|p$;\5 +$\\{if\_limit}\K\\{if\_code}$;\5 +$\\{if\_line}\K\\{line}$;\5 +$\\{cur\_if}\K\\{if\_code}$;\6 +\&{end}\par +\U748.\fi + +\M745. \P$\X745:Pop the condition stack\X\S$\6 +\&{begin} \37$\|p\K\\{cond\_ptr}$;\5 +$\\{if\_line}\K\\{if\_line\_field}(\|p)$;\5 +$\\{cur\_if}\K\\{name\_type}(\|p)$;\5 +$\\{if\_limit}\K\\{type}(\|p)$;\5 +$\\{cond\_ptr}\K\\{link}(\|p)$;\5 +$\\{free\_node}(\|p,\39\\{if\_node\_size})$;\6 +\&{end}\par +\Us748, 749\ETs751.\fi + +\M746. Here's a procedure that changes the \\{if\_limit} code corresponding to +a given value of \\{cond\_ptr}. + +\Y\P\4\&{procedure}\1\ \37$\\{change\_if\_limit}(\|l:\\{small\_number};\,\35% +\|p:\\{pointer})$;\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37\|q: \37\\{pointer};\2\6 +\&{begin} \37\&{if} $\|p=\\{cond\_ptr}$ \1\&{then}\5 +$\\{if\_limit}\K\|l$\C{that's the easy case}\6 +\4\&{else} \&{begin} \37$\|q\K\\{cond\_ptr}$;\6 +\~ \1\&{loop}\ \&{begin} \37\&{if} $\|q=\\{null}$ \1\&{then}\5 +$\\{confusion}(\.{"if"})$;\2\6 +\&{if} $\\{link}(\|q)=\|p$ \1\&{then}\6 +\&{begin} \37$\\{type}(\|q)\K\|l$;\5 +\&{return};\6 +\&{end};\2\6 +$\|q\K\\{link}(\|q)$;\6 +\&{end};\2\6 +\&{end};\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M747. The user is supposed to put colons into the proper parts of conditional +statements. Therefore, \MF\ has to check for their presence. + +\Y\P\4\&{procedure}\1\ \37\\{check\_colon};\2\6 +\&{begin} \37\&{if} $\\{cur\_cmd}\I\\{colon}$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\.{":"})$;\6 +$\\{help2}(\.{"There\ should\'ve\ been\ a\ colon\ after\ the\ condition."})$\6 +$(\.{"I\ shall\ pretend\ that\ one\ was\ there."})$;\5 +\\{back\_error};\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M748. A condition is started when the \\{get\_x\_next} procedure encounters +an \\{if\_test} command; in that case \\{get\_x\_next} calls \\{conditional}, +which is a recursive procedure. + +\Y\P\4\&{procedure}\1\ \37\\{conditional};\6 +\4\&{label} \37$\\{exit},\39\\{done},\39\\{reswitch},\39\\{found}$;\6 +\4\&{var} \37\\{save\_cond\_ptr}: \37\\{pointer};\C{\\{cond\_ptr} corresponding +to this conditional}\6 +\\{new\_if\_limit}: \37$\\{fi\_code}\to\\{else\_if\_code}$;\C{future value of % +\\{if\_limit}}\6 +\|p: \37\\{pointer};\C{temporary register}\2\6 +\&{begin} \37\X744:Push the condition stack\X;\ $\\{save\_cond\_ptr}\K\\{cond% +\_ptr}$;\6 +\4\\{reswitch}: \37\\{get\_boolean};\5 +$\\{new\_if\_limit}\K\\{else\_if\_code}$;\6 +\&{if} $\\{internal}[\\{tracing\_commands}]>\\{unity}$ \1\&{then}\5 +\X750:Display the boolean value of \\{cur\_exp}\X;\2\6 +\4\\{found}: \37\\{check\_colon};\6 +\&{if} $\\{cur\_exp}=\\{true\_code}$ \1\&{then}\6 +\&{begin} \37$\\{change\_if\_limit}(\\{new\_if\_limit},\39\\{save\_cond% +\_ptr})$;\5 +\&{return};\C{wait for \&{elseif}, \&{else}, or \&{fi}}\6 +\&{end};\2\6 +\X749:Skip to \&{elseif} or \&{else} or \&{fi}, then \&{goto} \\{done}\X;\6 +\4\\{done}: \37$\\{cur\_if}\K\\{cur\_mod}$;\5 +$\\{if\_line}\K\\{line}$;\6 +\&{if} $\\{cur\_mod}=\\{fi\_code}$ \1\&{then}\5 +\X745:Pop the condition stack\X\6 +\4\&{else} \&{if} $\\{cur\_mod}=\\{else\_if\_code}$ \1\&{then}\5 +\&{goto} \37\\{reswitch}\6 +\4\&{else} \&{begin} \37$\\{cur\_exp}\K\\{true\_code}$;\5 +$\\{new\_if\_limit}\K\\{fi\_code}$;\5 +\\{get\_x\_next};\5 +\&{goto} \37\\{found};\6 +\&{end};\2\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M749. In a construction like `\&{if} \&{if} \&{true}: $0=1$: \\{foo} +\&{else}: \\{bar} \&{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. + +\Y\P$\4\X749:Skip to \&{elseif} or \&{else} or \&{fi}, then \&{goto} \\{done}\X% +\S$\6 +\~ \1\&{loop}\ \&{begin} \37\\{pass\_text};\6 +\&{if} $\\{cond\_ptr}=\\{save\_cond\_ptr}$ \1\&{then}\5 +\&{goto} \37\\{done}\6 +\4\&{else} \&{if} $\\{cur\_mod}=\\{fi\_code}$ \1\&{then}\5 +\X745:Pop the condition stack\X;\2\2\6 +\&{end}\2\par +\U748.\fi + +\M750. \P$\X750:Display the boolean value of \\{cur\_exp}\X\S$\6 +\&{begin} \37\\{begin\_diagnostic};\6 +\&{if} $\\{cur\_exp}=\\{true\_code}$ \1\&{then}\5 +$\\{print}(\.{"\{true\}"})$\ \&{else} $\\{print}(\.{"\{false\}"})$;\2\6 +$\\{end\_diagnostic}(\\{false})$;\6 +\&{end}\par +\U748.\fi + +\M751. The processing of conditionals is complete except for the following +code, which is actually part of \\{get\_x\_next}. It comes into play when +\&{elseif}, \&{else}, or \&{fi} is scanned. + +\Y\P$\4\X751:Terminate the current conditional and skip to \&{fi}\X\S$\6 +\&{if} $\\{cur\_mod}>\\{if\_limit}$ \1\&{then}\6 +\&{if} $\\{if\_limit}=\\{if\_code}$ \1\&{then}\C{condition not yet evaluated}\6 +\&{begin} \37$\\{missing\_err}(\.{":"})$;\5 +\\{back\_input};\5 +$\\{cur\_sym}\K\\{frozen\_colon}$;\5 +\\{ins\_error};\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Extra\ "})$;\5 +$\\{print\_cmd\_mod}(\\{fi\_or\_else},\39\\{cur\_mod})$;\5 +$\\{help1}(\.{"I\'m\ ignoring\ this;\ it\ doesn\'t\ match\ any\ if."})$;\5 +\\{error};\6 +\&{end}\2\6 +\4\&{else} \&{begin} \37\&{while} $\\{cur\_mod}\I\\{fi\_code}$ \1\&{do}\5 +\\{pass\_text};\C{skip to \&{fi}}\2\6 +\X745:Pop the condition stack\X;\6 +\&{end}\2\par +\U707.\fi + +\N752. \[37] Iterations. +To bring our treatment of \\{get\_x\_next} to a close, we need to consider what +\MF\ does when it sees \&{for}, \&{forsuffixes}, and \&{forever}. + +There's a global variable \\{loop\_ptr} that keeps track of the \&{for} loops +that are currently active. If $\\{loop\_ptr}=\\{null}$, no loops are in +progress; +otherwise $\\{info}(\\{loop\_ptr})$ points to the iterative text of the current +(innermost) loop, and $\\{link}(\\{loop\_ptr})$ points to the data for any +other +loops that enclose the current one. + +A loop-control node also has two other fields, called \\{loop\_type} and +\\{loop\_list}, whose contents depend on the type of loop: + +\yskip\indent$\\{loop\_type}(\\{loop\_ptr})=\\{null}$ means that $\\{loop% +\_list}(\\{loop\_ptr})$ +points to a list of one-word nodes whose \\{info} fields point to the +remaining argument values of a suffix list and expression list. + +\yskip\indent$\\{loop\_type}(\\{loop\_ptr})=\\{void}$ means that the current +loop is +`\&{forever}'. + +\yskip\indent$\\{loop\_type}(\\{loop\_ptr})=\|p>\\{void}$ means that $% +\\{value}(\|p)$, +$\\{step\_size}(\|p)$, and $\\{final\_value}(\|p)$ contain the data for an +arithmetic +progression. + +\yskip\noindent In the latter case, \|p points to a ``progression node'' +whose first word is not used. (No value could be stored there because the +link field of words in the dynamic memory area cannot be arbitrary.) + +\Y\P\D \37$\\{loop\_list\_loc}(\#)\S\#+1$\C{where the \\{loop\_list} field +resides}\par +\P\D \37$\\{loop\_type}(\#)\S\\{info}(\\{loop\_list\_loc}(\#))$\C{the type of % +\&{for} loop}\par +\P\D \37$\\{loop\_list}(\#)\S\\{link}(\\{loop\_list\_loc}(\#))$\C{the remaining +list elements}\par +\P\D \37$\\{loop\_node\_size}=2$\C{the number of words in a loop control node}% +\par +\P\D \37$\\{progression\_node\_size}=4$\C{the number of words in a progression +node}\par +\P\D \37$\\{step\_size}(\#)\S\\{mem}[\#+2].\\{sc}$\C{the step size in an +arithmetic progression}\par +\P\D \37$\\{final\_value}(\#)\S\\{mem}[\#+3].\\{sc}$\C{the final value in an +arithmetic progression}\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{loop\_ptr}: \37\\{pointer};\C{top of the loop-control-node stack}\par +\fi + +\M753. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{loop\_ptr}\K\\{null}$;\par +\fi + +\M754. If the expressions that define an arithmetic progression in +a \&{for} loop don't have known numeric values, the \\{bad\_for} +subroutine screams at the user. + +\Y\P\4\&{procedure}\1\ \37$\\{bad\_for}(\|s:\\{str\_number})$;\2\6 +\&{begin} \37$\\{disp\_err}(\\{null},\39\.{"Improper\ "})$;\C{show the bad +expression above the message}\6 +$\\{print}(\|s)$;\5 +$\\{print}(\.{"\ has\ been\ replaced\ by\ 0"})$;\5 +$\\{help4}(\.{"When\ you\ say\ \`for\ x=a\ step\ b\ until\ c\',"})$\6 +$(\.{"the\ initial\ value\ \`a\'\ and\ the\ step\ size\ \`b\'"})$\6 +$(\.{"and\ the\ final\ value\ \`c\'\ must\ have\ known\ numeric\ values."})$\6 +$(\.{"I\'m\ zeroing\ this\ one.\ Proceed,\ with\ fingers\ crossed."})$;\5 +$\\{put\_get\_flush\_error}(0)$;\6 +\&{end};\par +\fi + +\M755. Here's what \MF\ does when \&{for}, \&{forsuffixes}, or \&{forever} +has just been scanned. (This code requires slight familiarity with +expression-parsing routines that we have not yet discussed; but it seems +to belong in the present part of the program, even though the author +didn't write it until later. The reader may wish to come back to it.) + +\Y\P\4\&{procedure}\1\ \37\\{begin\_iteration};\6 +\4\&{label} \37$\\{continue},\39\\{done},\39\\{found}$;\6 +\4\&{var} \37\|m: \37\\{halfword};\C{\\{expr\_base} (\&{for}) or \\{suffix% +\_base} (\&{forsuffixes})}\6 +\|n: \37\\{halfword};\C{hash address of the current symbol}\6 +$\|p,\39\|q,\39\|s,\39\\{pp}$: \37\\{pointer};\C{link manipulation registers}\2% +\6 +\&{begin} \37$\|m\K\\{cur\_mod}$;\5 +$\|n\K\\{cur\_sym}$;\5 +$\|s\K\\{get\_node}(\\{loop\_node\_size})$;\6 +\&{if} $\|m=\\{start\_forever}$ \1\&{then}\6 +\&{begin} \37$\\{loop\_type}(\|s)\K\\{void}$;\5 +$\|p\K\\{null}$;\5 +\\{get\_x\_next};\5 +\&{goto} \37\\{found};\6 +\&{end};\2\6 +\\{get\_symbol};\5 +$\|p\K\\{get\_node}(\\{token\_node\_size})$;\5 +$\\{info}(\|p)\K\\{cur\_sym}$;\5 +$\\{value}(\|p)\K\|m$;\6 +\\{get\_x\_next};\6 +\&{if} $(\\{cur\_cmd}\I\\{equals})\W(\\{cur\_cmd}\I\\{assignment})$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\.{"="})$;\6 +$\\{help3}(\.{"The\ next\ thing\ in\ this\ loop\ should\ have\ been\ \`=\'\ or\ +\`:=\'."})$\6 +$(\.{"But\ don\'t\ worry;\ I\'ll\ pretend\ that\ an\ equals\ sign"})$\6 +$(\.{"was\ present,\ and\ I\'ll\ look\ for\ the\ values\ next."})$;\6 +\\{back\_error};\6 +\&{end};\2\6 +\X764:Scan the values to be used in the loop\X;\6 +\4\\{found}: \37\X756:Check for the presence of a colon\X;\6 +\X758:Scan the loop text and put it on the loop control stack\X;\6 +\\{resume\_iteration};\6 +\&{end};\par +\fi + +\M756. \P$\X756:Check for the presence of a colon\X\S$\6 +\&{if} $\\{cur\_cmd}\I\\{colon}$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\.{":"})$;\6 +$\\{help3}(\.{"The\ next\ thing\ in\ this\ loop\ should\ have\ been\ a\ \`:% +\'."})$\6 +$(\.{"So\ I\'ll\ pretend\ that\ a\ colon\ was\ present;"})$\6 +$(\.{"everything\ from\ here\ to\ \`endfor\'\ will\ be\ iterated."})$;\5 +\\{back\_error};\6 +\&{end}\2\par +\U755.\fi + +\M757. We append a special \\{frozen\_repeat\_loop} token in place of the +`\&{endfor}' at the end of the loop. This will come through \MF's scanner +at the proper time to cause the loop to be repeated. + +(If the user tries some shenanigan like `\&{for} $\ldots$ \&{let} \&{endfor}', +he will be foiled by the \\{get\_symbol} routine, which keeps frozen +tokens unchanged. Furthermore the \\{frozen\_repeat\_loop} is an \&{outer} +token, so it won't be lost accidentally.) + +\fi + +\M758. \P$\X758:Scan the loop text and put it on the loop control stack\X\S$\6 +$\|q\K\\{get\_avail}$;\5 +$\\{info}(\|q)\K\\{frozen\_repeat\_loop}$;\5 +$\\{scanner\_status}\K\\{loop\_defining}$;\5 +$\\{warning\_info}\K\|n$;\5 +$\\{info}(\|s)\K\\{scan\_toks}(\\{iteration},\39\|p,\39\|q,\390)$;\5 +$\\{scanner\_status}\K\\{normal}$;\6 +$\\{link}(\|s)\K\\{loop\_ptr}$;\5 +$\\{loop\_ptr}\K\|s$\par +\U755.\fi + +\M759. \P$\X176:Initialize table entries (done by \.{INIMF} only)\X\mathrel{+}% +\S$\6 +$\\{eq\_type}(\\{frozen\_repeat\_loop})\K\\{repeat\_loop}+\\{outer\_tag}$;\5 +$\\{text}(\\{frozen\_repeat\_loop})\K\.{"\ ENDFOR"}$;\par +\fi + +\M760. The loop text is inserted into \MF's scanning apparatus by the +\\{resume\_iteration} routine. + +\Y\P\4\&{procedure}\1\ \37\\{resume\_iteration};\6 +\4\&{label} \37$\\{not\_found},\39\\{exit}$;\6 +\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{link registers}\2\6 +\&{begin} \37$\|p\K\\{loop\_type}(\\{loop\_ptr})$;\6 +\&{if} $\|p>\\{void}$ \1\&{then}\C{\|p points to a progression node}\6 +\&{begin} \37$\\{cur\_exp}\K\\{value}(\|p)$;\6 +\&{if} $\X761:The arithmetic progression has ended\X$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +$\\{cur\_type}\K\\{known}$;\5 +$\|q\K\\{stash\_cur\_exp}$;\C{make \|q an \&{expr} argument}\6 +$\\{value}(\|p)\K\\{cur\_exp}+\\{step\_size}(\|p)$;\C{set $\\{value}(\|p)$ for +the next iteration}\6 +\&{end}\6 +\4\&{else} \&{if} $\|p<\\{void}$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{loop\_list}(\\{loop\_ptr})$;\6 +\&{if} $\|p=\\{null}$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +$\\{loop\_list}(\\{loop\_ptr})\K\\{link}(\|p)$;\5 +$\|q\K\\{info}(\|p)$;\5 +$\\{free\_avail}(\|p)$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{begin\_token\_list}(\\{info}(\\{loop\_ptr}),\39% +\\{forever\_text})$;\5 +\&{return};\6 +\&{end};\2\2\6 +$\\{begin\_token\_list}(\\{info}(\\{loop\_ptr}),\39\\{loop\_text})$;\5 +$\\{stack\_argument}(\|q)$;\6 +\&{if} $\\{internal}[\\{tracing\_commands}]>\\{unity}$ \1\&{then}\5 +\X762:Trace the start of a loop\X;\2\6 +\&{return};\6 +\4\\{not\_found}: \37\\{stop\_iteration};\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M761. \P$\X761:The arithmetic progression has ended\X\S$\6 +$((\\{step\_size}(\|p)>0)\W(\\{cur\_exp}>\\{final\_value}(\|p)))\V\30((\\{step% +\_size}(\|p)<0)\W(\\{cur\_exp}<\\{final\_value}(\|p)))$\par +\U760.\fi + +\M762. \P$\X762:Trace the start of a loop\X\S$\6 +\&{begin} \37\\{begin\_diagnostic};\5 +$\\{print\_nl}(\.{"\{loop\ value="})$;\6 +\&{if} $(\|q\I\\{null})\W(\\{link}(\|q)=\\{void})$ \1\&{then}\5 +$\\{print\_exp}(\|q,\391)$\6 +\4\&{else} $\\{show\_token\_list}(\|q,\39\\{null},\3950,\390)$;\2\6 +$\\{print\_char}(\.{"\}"})$;\5 +$\\{end\_diagnostic}(\\{false})$;\6 +\&{end}\par +\U760.\fi + +\M763. A level of loop control disappears when \\{resume\_iteration} has +decided +not to resume, or when an \&{exitif} construction has removed the loop text +from the input stack. + +\Y\P\4\&{procedure}\1\ \37\\{stop\_iteration};\6 +\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{the usual}\2\6 +\&{begin} \37$\|p\K\\{loop\_type}(\\{loop\_ptr})$;\6 +\&{if} $\|p>\\{void}$ \1\&{then}\5 +$\\{free\_node}(\|p,\39\\{progression\_node\_size})$\6 +\4\&{else} \&{if} $\|p<\\{void}$ \1\&{then}\6 +\&{begin} \37$\|q\K\\{loop\_list}(\\{loop\_ptr})$;\6 +\&{while} $\|q\I\\{null}$ \1\&{do}\6 +\&{begin} \37$\|p\K\\{info}(\|q)$;\6 +\&{if} $\|p\I\\{null}$ \1\&{then}\6 +\&{if} $\\{link}(\|p)=\\{void}$ \1\&{then}\C{it's an \&{expr} parameter}\6 +\&{begin} \37$\\{recycle\_value}(\|p)$;\5 +$\\{free\_node}(\|p,\39\\{value\_node\_size})$;\6 +\&{end}\6 +\4\&{else} $\\{flush\_token\_list}(\|p)$;\C{it's a \&{suffix} or \&{text} +parameter}\2\2\6 +$\|p\K\|q$;\5 +$\|q\K\\{link}(\|q)$;\5 +$\\{free\_avail}(\|p)$;\6 +\&{end};\2\6 +\&{end};\2\2\6 +$\|p\K\\{loop\_ptr}$;\5 +$\\{loop\_ptr}\K\\{link}(\|p)$;\5 +$\\{flush\_token\_list}(\\{info}(\|p))$;\5 +$\\{free\_node}(\|p,\39\\{loop\_node\_size})$;\6 +\&{end};\par +\fi + +\M764. Now that we know all about loop control, we can finish up +the missing portion of \\{begin\_iteration} and we'll be done. + +The following code is performed after the `\.=' has been scanned in +a \&{for} construction (if $\|m=\\{expr\_base}$) or a \&{forsuffixes} +construction +(if $\|m=\\{suffix\_base}$). + +\Y\P$\4\X764:Scan the values to be used in the loop\X\S$\6 +$\\{loop\_type}(\|s)\K\\{null}$;\5 +$\|q\K\\{loop\_list\_loc}(\|s)$;\5 +$\\{link}(\|q)\K\\{null}$;\C{$\\{link}(\|q)=\\{loop\_list}(\|s)$}\6 +\1\&{repeat} \37\\{get\_x\_next};\6 +\&{if} $\|m\I\\{expr\_base}$ \1\&{then}\5 +\\{scan\_suffix}\6 +\4\&{else} \&{begin} \37\&{if} $\\{cur\_cmd}\G\\{colon}$ \1\&{then}\6 +\&{if} $\\{cur\_cmd}\L\\{comma}$ \1\&{then}\5 +\&{goto} \37\\{continue};\2\2\6 +\\{scan\_expression};\6 +\&{if} $\\{cur\_cmd}=\\{step\_token}$ \1\&{then}\6 +\&{if} $\|q=\\{loop\_list\_loc}(\|s)$ \1\&{then}\5 +\X765:Prepare for step-until construction and \&{goto} \\{done}\X;\2\2\6 +$\\{cur\_exp}\K\\{stash\_cur\_exp}$;\6 +\&{end};\2\6 +$\\{link}(\|q)\K\\{get\_avail}$;\5 +$\|q\K\\{link}(\|q)$;\5 +$\\{info}(\|q)\K\\{cur\_exp}$;\5 +$\\{cur\_type}\K\\{vacuous}$;\6 +\4\\{continue}: \37\&{until}\5 +$\\{cur\_cmd}\I\\{comma}$;\2\6 +\4\\{done}: \37\par +\U755.\fi + +\M765. \P$\X765:Prepare for step-until construction and \&{goto} \\{done}\X\S$\6 +\&{begin} \37\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\5 +$\\{bad\_for}(\.{"initial\ value"})$;\2\6 +$\\{pp}\K\\{get\_node}(\\{progression\_node\_size})$;\5 +$\\{value}(\\{pp})\K\\{cur\_exp}$;\6 +\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\5 +$\\{bad\_for}(\.{"step\ size"})$;\2\6 +$\\{step\_size}(\\{pp})\K\\{cur\_exp}$;\6 +\&{if} $\\{cur\_cmd}\I\\{until\_token}$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\.{"until"})$;\6 +$\\{help2}(\.{"I\ assume\ you\ meant\ to\ say\ \`until\'\ after\ \`step\'."})$\6 +$(\.{"So\ I\'ll\ look\ for\ the\ final\ value\ and\ colon\ next."})$;\5 +\\{back\_error};\6 +\&{end};\2\6 +\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\5 +$\\{bad\_for}(\.{"final\ value"})$;\2\6 +$\\{final\_value}(\\{pp})\K\\{cur\_exp}$;\5 +$\\{loop\_type}(\|s)\K\\{pp}$;\5 +\&{goto} \37\\{done};\6 +\&{end}\par +\U764.\fi + +\N766. \[38] 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. + +\MF\ 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 is assumed to be +`\.{.mf}' unless otherwise specified; it is `\.{.log}' on the +transcript file that records each run of \MF; it is `\.{.tfm}' on the font +metric files that describe characters in the fonts \MF\ creates; it is +`\.{.gf}' on the output files that specify generic font information; and it +is `\.{.base}' on the base files written by \.{INIMF} to initialize \MF. +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, \MF\ will look for it on a special system +area; this special area is intended for commonly used input files. + +Simple uses of \MF\ refer only to file names that have no explicit +extension or area. For example, a person usually says `\.{input} \.{cmr10}' +instead of `\.{input} \.{cmr10.new}'. Simple file +names are best, because they make the \MF\ 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 \MF. 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. + +\fi + +\M767. \MF\ uses the same conventions that have proved to be satisfactory for +\TeX. In order to isolate the system-dependent aspects of file names, the +system-independent parts of \MF\ are expressed in terms +of three system-dependent +procedures called \\{begin\_name}, \\{more\_name}, and \\{end\_name}. In +essence, if the user-specified characters of the file name are $c_1\ldots c_n$, +the system-independent driver program does the operations +$$\\{begin\_name};\,\\{more\_name}(c_1);\,\ldots\,;\\{more\_name}(c_n); +\,\\{end\_name}.$$ +These three procedures communicate with each other via global variables. +Afterwards the file name will appear in the string pool as three strings +called \\{cur\_name}\penalty10000\hskip-.05em, +\\{cur\_area}, and \\{cur\_ext}; the latter two are null (i.e., +\.{""}), unless they were explicitly specified by the user. + +Actually the situation is slightly more complicated, because \MF\ 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 $c_n$ is the last character +on the current input line. In other words, +\\{more\_name} is supposed to return \\{true} unless it is sure that the +file name has been completely scanned; and \\{end\_name} is supposed to be able +to finish the assembly of \\{cur\_name}, \\{cur\_area}, and \\{cur\_ext} +regardless of +whether $\\{more\_name}(c_n)$ returned \\{true} or \\{false}. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{cur\_name}: \37\\{str\_number};\C{name of file just scanned}\6 +\4\\{cur\_area}: \37\\{str\_number};\C{file area just scanned, or \.{""}}\6 +\4\\{cur\_ext}: \37\\{str\_number};\C{file extension just scanned, or \.{""}}% +\par +\fi + +\M768. 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\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{area\_delimiter}: \37\\{pool\_pointer};\C{the most recent `\.>' or `\.:', +if any}\6 +\4\\{ext\_delimiter}: \37\\{pool\_pointer};\C{the relevant `\..', if any}\par +\fi + +\M769. Input files that can't be found in the user's area may appear in a +standard +system area called \\{MF\_area}. +This system area name will, of course, vary from place to place. + +\Y\P\D \37$\\{MF\_area}\S\.{"MFinputs:"}$\par +\fi + +\M770. Here now is the first of the system-dependent routines for file name +scanning. + +\Y\P\4\&{procedure}\1\ \37\\{begin\_name};\2\6 +\&{begin} \37$\\{area\_delimiter}\K0$;\5 +$\\{ext\_delimiter}\K0$;\6 +\&{end};\par +\fi + +\M771. And here's the second. + +\Y\P\4\&{function}\1\ \37$\\{more\_name}(\|c:\\{ASCII\_code})$: \37% +\\{boolean};\2\6 +\&{begin} \37\&{if} $\|c=\.{"\ "}$ \1\&{then}\5 +$\\{more\_name}\K\\{false}$\6 +\4\&{else} \&{begin} \37\&{if} $(\|c=\.{">"})\V(\|c=\.{":"})$ \1\&{then}\6 +\&{begin} \37$\\{area\_delimiter}\K\\{pool\_ptr}$;\5 +$\\{ext\_delimiter}\K0$;\6 +\&{end}\6 +\4\&{else} \&{if} $(\|c=\.{"."})\W(\\{ext\_delimiter}=0)$ \1\&{then}\5 +$\\{ext\_delimiter}\K\\{pool\_ptr}$;\2\2\6 +$\\{str\_room}(1)$;\5 +$\\{append\_char}(\|c)$;\C{contribute \|c to the current string}\6 +$\\{more\_name}\K\\{true}$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M772. The third. + +\Y\P\4\&{procedure}\1\ \37\\{end\_name};\2\6 +\&{begin} \37\&{if} $\\{str\_ptr}+3>\\{max\_str\_ptr}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{str\_ptr}+3>\\{max\_strings}$ \1\&{then}\5 +$\\{overflow}(\.{"number\ of\ strings"},\39\\{max\_strings}-\\{init\_str% +\_ptr})$;\2\6 +$\\{max\_str\_ptr}\K\\{str\_ptr}+3$;\6 +\&{end};\2\6 +\&{if} $\\{area\_delimiter}=0$ \1\&{then}\5 +$\\{cur\_area}\K\.{""}$\6 +\4\&{else} \&{begin} \37$\\{cur\_area}\K\\{str\_ptr}$;\5 +$\\{incr}(\\{str\_ptr})$;\5 +$\\{str\_start}[\\{str\_ptr}]\K\\{area\_delimiter}+1$;\6 +\&{end};\2\6 +\&{if} $\\{ext\_delimiter}=0$ \1\&{then}\6 +\&{begin} \37$\\{cur\_ext}\K\.{""}$;\5 +$\\{cur\_name}\K\\{make\_string}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{cur\_name}\K\\{str\_ptr}$;\5 +$\\{incr}(\\{str\_ptr})$;\5 +$\\{str\_start}[\\{str\_ptr}]\K\\{ext\_delimiter}$;\5 +$\\{cur\_ext}\K\\{make\_string}$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M773. Conversely, here is a routine that takes three strings and prints a file +name that might have produced them. (The routine is system dependent, because +some operating systems put the file area last instead of first.) + +\Y\P$\4\X57:Basic printing procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{print\_file\_name}(\|n,\39\|a,\39\|e:\\{integer})$;% +\2\6 +\&{begin} \37$\\{slow\_print}(\|a)$;\5 +$\\{slow\_print}(\|n)$;\5 +$\\{slow\_print}(\|e)$;\6 +\&{end};\par +\fi + +\M774. Another system-dependent routine is needed to convert three internal +\MF\ strings +to the \\{name\_of\_file} value that is used to open files. The present code +allows both lowercase and uppercase letters in the file name. + +\Y\P\D \37$\\{append\_to\_name}(\#)\S$\1\6 +\&{begin} \37$\|c\K\#$;\5 +$\\{incr}(\|k)$;\6 +\&{if} $\|k\L\\{file\_name\_size}$ \1\&{then}\5 +$\\{name\_of\_file}[\|k]\K\\{xchr}[\|c]$;\2\6 +\&{end}\2\par +\Y\P\4\&{procedure}\1\ \37$\\{pack\_file\_name}(\|n,\39\|a,\39\|e:\\{str% +\_number})$;\6 +\4\&{var} \37\|k: \37\\{integer};\C{number of positions filled in \\{name\_of% +\_file}}\6 +\|c: \37\\{ASCII\_code};\C{character being packed}\6 +\|j: \37\\{pool\_pointer};\C{index into \\{str\_pool}}\2\6 +\&{begin} \37$\|k\K0$;\6 +\&{for} $\|j\K\\{str\_start}[\|a]\mathrel{\&{to}}\\{str\_start}[\|a+1]-1$ \1% +\&{do}\5 +$\\{append\_to\_name}(\\{so}(\\{str\_pool}[\|j]))$;\2\6 +\&{for} $\|j\K\\{str\_start}[\|n]\mathrel{\&{to}}\\{str\_start}[\|n+1]-1$ \1% +\&{do}\5 +$\\{append\_to\_name}(\\{so}(\\{str\_pool}[\|j]))$;\2\6 +\&{for} $\|j\K\\{str\_start}[\|e]\mathrel{\&{to}}\\{str\_start}[\|e+1]-1$ \1% +\&{do}\5 +$\\{append\_to\_name}(\\{so}(\\{str\_pool}[\|j]))$;\2\6 +\&{if} $\|k\L\\{file\_name\_size}$ \1\&{then}\5 +$\\{name\_length}\K\|k$\ \&{else} $\\{name\_length}\K\\{file\_name\_size}$;\2\6 +\&{for} $\|k\K\\{name\_length}+1\mathrel{\&{to}}\\{file\_name\_size}$ \1\&{do}\5 +$\\{name\_of\_file}[\|k]\K\.{\'\ \'}$;\2\6 +\&{end};\par +\fi + +\M775. A messier routine is also needed, since base file names must be scanned +before \MF's string mechanism has been initialized. We shall use the +global variable \\{MF\_base\_default} to supply the text for default system +areas +and extensions related to base files. + +\Y\P\D \37$\\{base\_default\_length}=18$\C{length of the \\{MF\_base\_default} +string}\par +\P\D \37$\\{base\_area\_length}=8$\C{length of its area part}\par +\P\D \37$\\{base\_ext\_length}=5$\C{length of its `\.{.base}' part}\par +\P\D \37$\\{base\_extension}=\.{".base"}$\C{the extension, as a \.{WEB} +constant}\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{MF\_base\_default}: \37\&{packed} \37\&{array} $[1\to\\{base\_default% +\_length}]$ \1\&{of}\5 +\\{char};\2\par +\fi + +\M776. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{MF\_base\_default}\K\.{\'MFbases:plain.base\'}$;\par +\fi + +\M777. \P$\X14:Check the ``constant'' values for consistency\X\mathrel{+}\S$\6 +\&{if} $\\{base\_default\_length}>\\{file\_name\_size}$ \1\&{then}\5 +$\\{bad}\K41$;\2\par +\fi + +\M778. Here is the messy routine that was just mentioned. It sets \\{name\_of% +\_file} +from the first \|n characters of \\{MF\_base\_default}, followed by +$\\{buffer}[\|a\to\|b]$, followed by the last \\{base\_ext\_length} characters +of +\\{MF\_base\_default}. + +We dare not give error messages here, since \MF\ calls this routine before +the \\{error} routine is ready to roll. Instead, we simply drop excess +characters, +since the error will be detected in another way when a strange file name +isn't found. + +\Y\P\4\&{procedure}\1\ \37$\\{pack\_buffered\_name}(\|n:\\{small\_number};\,% +\35\|a,\39\|b:\\{integer})$;\6 +\4\&{var} \37\|k: \37\\{integer};\C{number of positions filled in \\{name\_of% +\_file}}\6 +\|c: \37\\{ASCII\_code};\C{character being packed}\6 +\|j: \37\\{integer};\C{index into \\{buffer} or \\{MF\_base\_default}}\2\6 +\&{begin} \37\&{if} $\|n+\|b-\|a+1+\\{base\_ext\_length}>\\{file\_name\_size}$ % +\1\&{then}\5 +$\|b\K\|a+\\{file\_name\_size}-\|n-1-\\{base\_ext\_length}$;\2\6 +$\|k\K0$;\6 +\&{for} $\|j\K1\mathrel{\&{to}}\|n$ \1\&{do}\5 +$\\{append\_to\_name}(\\{xord}[\\{MF\_base\_default}[\|j]])$;\2\6 +\&{for} $\|j\K\|a\mathrel{\&{to}}\|b$ \1\&{do}\5 +$\\{append\_to\_name}(\\{buffer}[\|j])$;\2\6 +\&{for} $\|j\K\\{base\_default\_length}-\\{base\_ext\_length}+1\mathrel{\&{to}}% +\\{base\_default\_length}$ \1\&{do}\5 +$\\{append\_to\_name}(\\{xord}[\\{MF\_base\_default}[\|j]])$;\2\6 +\&{if} $\|k\L\\{file\_name\_size}$ \1\&{then}\5 +$\\{name\_length}\K\|k$\ \&{else} $\\{name\_length}\K\\{file\_name\_size}$;\2\6 +\&{for} $\|k\K\\{name\_length}+1\mathrel{\&{to}}\\{file\_name\_size}$ \1\&{do}\5 +$\\{name\_of\_file}[\|k]\K\.{\'\ \'}$;\2\6 +\&{end};\par +\fi + +\M779. Here is the only place we use \\{pack\_buffered\_name}. This part of the +program +becomes active when a ``virgin'' \MF\ is trying to get going, just after +the preliminary initialization, or when the user is substituting another +base file by typing `\.\&' after the initial `\.{**}' prompt. The buffer +contains the first line of input in $\\{buffer}[\\{loc}\to(\\{last}-1)]$, where +$\\{loc}<\\{last}$ and $\\{buffer}[\\{loc}]\I\.{"\ "}$. + +\Y\P$\4\X779:Declare the function called \\{open\_base\_file}\X\S$\6 +\4\&{function}\1\ \37\\{open\_base\_file}: \37\\{boolean};\6 +\4\&{label} \37$\\{found},\39\\{exit}$;\6 +\4\&{var} \37\|j: \37$0\to\\{buf\_size}$;\C{the first space after the file +name}\2\6 +\&{begin} \37$\|j\K\\{loc}$;\6 +\&{if} $\\{buffer}[\\{loc}]=\.{"\&"}$ \1\&{then}\6 +\&{begin} \37$\\{incr}(\\{loc})$;\5 +$\|j\K\\{loc}$;\5 +$\\{buffer}[\\{last}]\K\.{"\ "}$;\6 +\&{while} $\\{buffer}[\|j]\I\.{"\ "}$ \1\&{do}\5 +$\\{incr}(\|j)$;\2\6 +$\\{pack\_buffered\_name}(0,\39\\{loc},\39\|j-1)$;\C{try first without the +system file area}\6 +\&{if} $\\{w\_open\_in}(\\{base\_file})$ \1\&{then}\5 +\&{goto} \37\\{found};\2\6 +$\\{pack\_buffered\_name}(\\{base\_area\_length},\39\\{loc},\39\|j-1)$;\C{now +try the system base file area}\6 +\&{if} $\\{w\_open\_in}(\\{base\_file})$ \1\&{then}\5 +\&{goto} \37\\{found};\2\6 +\\{wake\_up\_terminal};\5 +$\\{wterm\_ln}(\.{\'Sorry,\ I\ can\'}\.{\'t\ find\ that\ base;\'},\39\.{\'\ +will\ try\ PLAIN.\'})$;\5 +\\{update\_terminal};\6 +\&{end};\C{now pull out all the stops: try for the system \.{plain} file}\2\6 +$\\{pack\_buffered\_name}(\\{base\_default\_length}-\\{base\_ext\_length},\391,% +\390)$;\6 +\&{if} $\R\\{w\_open\_in}(\\{base\_file})$ \1\&{then}\6 +\&{begin} \37\\{wake\_up\_terminal};\5 +$\\{wterm\_ln}(\.{\'I\ can\'}\.{\'t\ find\ the\ PLAIN\ base\ file!\'})$;\5 +$\\{open\_base\_file}\K\\{false}$;\5 +\&{return};\6 +\&{end};\2\6 +\4\\{found}: \37$\\{loc}\K\|j$;\5 +$\\{open\_base\_file}\K\\{true}$;\6 +\4\\{exit}: \37\&{end};\par +\U1187.\fi + +\M780. 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 \MF\ string from the value of \\{name\_of\_file}, should +ideally be changed to deduce the full name of file~\|f, which is the file +most recently opened, if it is possible to do this in a \PASCAL\ program. + +This routine might be called after string memory has overflowed, hence +we dare not use `\\{str\_room}'. + +\Y\P\4\&{function}\1\ \37\\{make\_name\_string}: \37\\{str\_number};\6 +\4\&{var} \37\|k: \37$1\to\\{file\_name\_size}$;\C{index into \\{name\_of% +\_file}}\2\6 +\&{begin} \37\&{if} $(\\{pool\_ptr}+\\{name\_length}>\\{pool\_size})\V(\\{str% +\_ptr}=\\{max\_strings})$ \1\&{then}\5 +$\\{make\_name\_string}\K\.{"?"}$\6 +\4\&{else} \&{begin} \37\&{for} $\|k\K1\mathrel{\&{to}}\\{name\_length}$ \1% +\&{do}\5 +$\\{append\_char}(\\{xord}[\\{name\_of\_file}[\|k]])$;\2\6 +$\\{make\_name\_string}\K\\{make\_string}$;\6 +\&{end};\2\6 +\&{end};\6 +\4\&{function}\1\ \37$\\{a\_make\_name\_string}(\mathop{\&{var}}\|f:\\{alpha% +\_file})$: \37\\{str\_number};\2\6 +\&{begin} \37$\\{a\_make\_name\_string}\K\\{make\_name\_string}$;\6 +\&{end};\6 +\4\&{function}\1\ \37$\\{b\_make\_name\_string}(\mathop{\&{var}}\|f:\\{byte% +\_file})$: \37\\{str\_number};\2\6 +\&{begin} \37$\\{b\_make\_name\_string}\K\\{make\_name\_string}$;\6 +\&{end};\6 +\4\&{function}\1\ \37$\\{w\_make\_name\_string}(\mathop{\&{var}}\|f:\\{word% +\_file})$: \37\\{str\_number};\2\6 +\&{begin} \37$\\{w\_make\_name\_string}\K\\{make\_name\_string}$;\6 +\&{end};\par +\fi + +\M781. Now let's consider the ``driver'' +routines by which \MF\ deals with file names +in a system-independent manner. First comes a procedure that looks for a +file name in the input by taking the information from the input buffer. +(We can't use \\{get\_next}, because the conversion to tokens would +destroy necessary information.) + +This procedure doesn't allow semicolons or percent signs to be part of +file names, because of other conventions of \MF. The manual doesn't +use semicolons or percents immediately after file names, but some users +no doubt will find it natural to do so; therefore system-dependent +changes to allow such characters in file names should probably +be made with reluctance, and only when an entire file name that +includes special characters is ``quoted'' somehow. + +\Y\P\4\&{procedure}\1\ \37\\{scan\_file\_name};\6 +\4\&{label} \37\\{done};\2\6 +\&{begin} \37\\{begin\_name};\6 +\&{while} $\\{buffer}[\\{loc}]=\.{"\ "}$ \1\&{do}\5 +$\\{incr}(\\{loc})$;\2\6 +\~ \1\&{loop}\ \&{begin} \37\&{if} $(\\{buffer}[\\{loc}]=\.{";"})\V(\\{buffer}[% +\\{loc}]=\.{"\%"})$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +\&{if} $\R\\{more\_name}(\\{buffer}[\\{loc}])$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\\{incr}(\\{loc})$;\6 +\&{end};\2\6 +\4\\{done}: \37\\{end\_name};\6 +\&{end};\par +\fi + +\M782. The global variable \\{job\_name} contains the file name that was first +\&{input} by the user. This name is extended by `\.{.log}' and `\.{.gf}' and +`\.{.base}' and `\.{.tfm}' in the names of \MF's output files. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{job\_name}: \37\\{str\_number};\C{principal file name}\6 +\4\\{log\_opened}: \37\\{boolean};\C{has the transcript file been opened?}\6 +\4\\{log\_name}: \37\\{str\_number};\C{full name of the log file}\par +\fi + +\M783. Initially $\\{job\_name}=0$; it becomes nonzero as soon as the true name +is known. +We have $\\{job\_name}=0$ if and only if the `\.{log}' file has not been +opened, +except of course for a short time just after \\{job\_name} has become nonzero. + +\Y\P$\4\X55:Initialize the output routines\X\mathrel{+}\S$\6 +$\\{job\_name}\K0$;\5 +$\\{log\_opened}\K\\{false}$;\par +\fi + +\M784. Here is a routine that manufactures the output file names, assuming that +$\\{job\_name}\I0$. It ignores and changes the current settings of \\{cur% +\_area} +and \\{cur\_ext}. + +\Y\P\D \37$\\{pack\_cur\_name}\S\\{pack\_file\_name}(\\{cur\_name},\39\\{cur% +\_area},\39\\{cur\_ext})$\par +\Y\P\4\&{procedure}\1\ \37$\\{pack\_job\_name}(\|s:\\{str\_number})$;\C{$\|s=% +\.{".log"}$, \.{".gf"}, \.{".tfm"}, or \\{base\_extension}}\2\6 +\&{begin} \37$\\{cur\_area}\K\.{""}$;\5 +$\\{cur\_ext}\K\|s$;\5 +$\\{cur\_name}\K\\{job\_name}$;\5 +\\{pack\_cur\_name};\6 +\&{end};\par +\fi + +\M785. Actually the main output file extension is usually something like +\.{".300gf"} instead of just \.{".gf"}; the additional number indicates the +resolution in pixels per inch, based on the setting of \\{hppp} when +the file is opened. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{gf\_ext}: \37\\{str\_number};\C{default extension for the output file}\par +\fi + +\M786. If some trouble arises when \MF\ tries to open a file, the following +routine calls upon the user to supply another file name. Parameter~\|s +is used in the error message to identify the type of file; parameter~\|e +is the default extension if none is given. Upon exit from the routine, +variables \\{cur\_name}, \\{cur\_area}, \\{cur\_ext}, and \\{name\_of\_file} +are +ready for another attempt at file opening. + +\Y\P\4\&{procedure}\1\ \37$\\{prompt\_file\_name}(\|s,\39\|e:\\{str% +\_number})$;\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37\|k: \37$0\to\\{buf\_size}$;\C{index into \\{buffer}}\2\6 +\&{begin} \37\&{if} $\\{interaction}=\\{scroll\_mode}$ \1\&{then}\5 +\\{wake\_up\_terminal};\2\6 +\&{if} $\|s=\.{"input\ file\ name"}$ \1\&{then}\5 +$\\{print\_err}(\.{"I\ can\'t\ find\ file\ \`"})$\6 +\4\&{else} $\\{print\_err}(\.{"I\ can\'t\ write\ on\ file\ \`"})$;\2\6 +$\\{print\_file\_name}(\\{cur\_name},\39\\{cur\_area},\39\\{cur\_ext})$;\5 +$\\{print}(\.{"\'."})$;\6 +\&{if} $\|e=\.{".mf"}$ \1\&{then}\5 +\\{show\_context};\2\6 +$\\{print\_nl}(\.{"Please\ type\ another\ "})$;\5 +$\\{print}(\|s)$;\6 +\&{if} $\\{interaction}<\\{scroll\_mode}$ \1\&{then}\5 +$\\{fatal\_error}(\.{"***\ (job\ aborted,\ file\ error\ in\ nonstop\ mode)"})$;% +\2\6 +\\{clear\_terminal};\5 +$\\{prompt\_input}(\.{":\ "})$;\5 +\X787:Scan file name in the buffer\X;\6 +\&{if} $\\{cur\_ext}=\.{""}$ \1\&{then}\5 +$\\{cur\_ext}\K\|e$;\2\6 +\\{pack\_cur\_name};\6 +\&{end};\par +\fi + +\M787. \P$\X787:Scan file name in the buffer\X\S$\6 +\&{begin} \37\\{begin\_name};\5 +$\|k\K\\{first}$;\6 +\&{while} $(\\{buffer}[\|k]=\.{"\ "})\W(\|k<\\{last})$ \1\&{do}\5 +$\\{incr}(\|k)$;\2\6 +\~ \1\&{loop}\ \&{begin} \37\&{if} $\|k=\\{last}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +\&{if} $\R\\{more\_name}(\\{buffer}[\|k])$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\\{incr}(\|k)$;\6 +\&{end};\2\6 +\4\\{done}: \37\\{end\_name};\6 +\&{end}\par +\U786.\fi + +\M788. The \\{open\_log\_file} routine is used to open the transcript file and +to help +it catch up to what has previously been printed on the terminal. + +\Y\P\4\&{procedure}\1\ \37\\{open\_log\_file};\6 +\4\&{var} \37\\{old\_setting}: \37$0\to\\{max\_selector}$;\C{previous % +\\{selector} setting}\6 +\|k: \37$0\to\\{buf\_size}$;\C{index into \\{months} and \\{buffer}}\6 +\|l: \37$0\to\\{buf\_size}$;\C{end of first input line}\6 +\|m: \37\\{integer};\C{the current month}\6 +\\{months}: \37\&{packed} \37\&{array} $[1\to36]$ \1\&{of}\5 +\\{char};\C{abbreviations of month names}\2\2\6 +\&{begin} \37$\\{old\_setting}\K\\{selector}$;\6 +\&{if} $\\{job\_name}=0$ \1\&{then}\5 +$\\{job\_name}\K\.{"mfput"}$;\2\6 +$\\{pack\_job\_name}(\.{".log"})$;\6 +\&{while} $\R\\{a\_open\_out}(\\{log\_file})$ \1\&{do}\5 +\X789:Try to get a different log file name\X;\2\6 +$\\{log\_name}\K\\{a\_make\_name\_string}(\\{log\_file})$;\5 +$\\{selector}\K\\{log\_only}$;\5 +$\\{log\_opened}\K\\{true}$;\5 +\X790: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}[0].\\{limit\_field}-1$;\C{last position of first line}\6 +\&{for} $\|k\K1\mathrel{\&{to}}\|l$ \1\&{do}\5 +$\\{print}(\\{buffer}[\|k])$;\2\6 +\\{print\_ln};\C{now the transcript file contains the first line of input}\6 +$\\{selector}\K\\{old\_setting}+2$;\C{\\{log\_only} or \\{term\_and\_log}}\6 +\&{end};\par +\fi + +\M789. Sometimes \\{open\_log\_file} is called at awkward moments when \MF\ is +unable to print error messages or even to \\{show\_context}. +The \\{prompt\_file\_name} routine can result in a \\{fatal\_error}, but the % +\\{error} +routine will not be invoked because \\{log\_opened} will be false. + +The normal idea of \\{batch\_mode} is that nothing at all should be written +on the terminal. However, in the unusual case that +no log file could be opened, we make an exception and allow +an explanatory message to be seen. + +Incidentally, the program always refers to the log file as a `\.{transcript +file}', because some systems cannot use the extension `\.{.log}' for +this file. + +\Y\P$\4\X789:Try to get a different log file name\X\S$\6 +\&{begin} \37$\\{selector}\K\\{term\_only}$;\5 +$\\{prompt\_file\_name}(\.{"transcript\ file\ name"},\39\.{".log"})$;\6 +\&{end}\par +\U788.\fi + +\M790. \P$\X790:Print the banner line, including the date and time\X\S$\6 +\&{begin} \37$\\{wlog}(\\{banner})$;\5 +$\\{slow\_print}(\\{base\_ident})$;\5 +$\\{print}(\.{"\ \ "})$;\5 +$\\{print\_int}(\\{round\_unscaled}(\\{internal}[\\{day}]))$;\5 +$\\{print\_char}(\.{"\ "})$;\5 +$\\{months}\K\.{\'JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC\'}$;\5 +$\|m\K\\{round\_unscaled}(\\{internal}[\\{month}])$;\6 +\&{for} $\|k\K3\ast\|m-2\mathrel{\&{to}}3\ast\|m$ \1\&{do}\5 +$\\{wlog}(\\{months}[\|k])$;\2\6 +$\\{print\_char}(\.{"\ "})$;\5 +$\\{print\_int}(\\{round\_unscaled}(\\{internal}[\\{year}]))$;\5 +$\\{print\_char}(\.{"\ "})$;\5 +$\|m\K\\{round\_unscaled}(\\{internal}[\\{time}])$;\5 +$\\{print\_dd}(\|m\mathbin{\&{div}}60)$;\5 +$\\{print\_char}(\.{":"})$;\5 +$\\{print\_dd}(\|m\mathbin{\&{mod}}60)$;\6 +\&{end}\par +\U788.\fi + +\M791. Here's an example of how these file-name-parsing routines work in +practice. +We shall use the macro \\{set\_output\_file\_name} when it is time to +crank up the output file. + +\Y\P\D \37$\\{set\_output\_file\_name}\S$\1\6 +\&{begin} \37\&{if} $\\{job\_name}=0$ \1\&{then}\5 +\\{open\_log\_file};\2\6 +$\\{pack\_job\_name}(\\{gf\_ext})$;\6 +\&{while} $\R\\{b\_open\_out}(\\{gf\_file})$ \1\&{do}\5 +$\\{prompt\_file\_name}(\.{"file\ name\ for\ output"},\39\\{gf\_ext})$;\2\6 +$\\{output\_file\_name}\K\\{b\_make\_name\_string}(\\{gf\_file})$;\6 +\&{end}\2\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{gf\_file}: \37\\{byte\_file};\C{the generic font output goes here}\6 +\4\\{output\_file\_name}: \37\\{str\_number};\C{full name of the output file}% +\par +\fi + +\M792. \P$\X55:Initialize the output routines\X\mathrel{+}\S$\6 +$\\{output\_file\_name}\K0$;\par +\fi + +\M793. Let's turn now to the procedure that is used to initiate file reading +when an `\.{input}' command is being processed. + +\Y\P\4\&{procedure}\1\ \37\\{start\_input};\C{\MF\ will \.{input} something}\6 +\4\&{label} \37\\{done};\2\6 +\&{begin} \37\X795:Put the desired file name in $(\\{cur\_name},\\{cur\_ext},% +\\{cur\_area})$\X;\6 +\&{if} $\\{cur\_ext}=\.{""}$ \1\&{then}\5 +$\\{cur\_ext}\K\.{".mf"}$;\2\6 +\\{pack\_cur\_name};\6 +\~ \1\&{loop}\ \&{begin} \37\\{begin\_file\_reading};\C{set up \\{cur\_file} +and new level of input}\6 +\&{if} $\\{a\_open\_in}(\\{cur\_file})$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +\&{if} $\\{cur\_area}=\.{""}$ \1\&{then}\6 +\&{begin} \37$\\{pack\_file\_name}(\\{cur\_name},\39\\{MF\_area},\39\\{cur% +\_ext})$;\6 +\&{if} $\\{a\_open\_in}(\\{cur\_file})$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +\&{end};\2\6 +\\{end\_file\_reading};\C{remove the level that didn't work}\6 +$\\{prompt\_file\_name}(\.{"input\ file\ name"},\39\.{".mf"})$;\6 +\&{end};\2\6 +\4\\{done}: \37$\\{name}\K\\{a\_make\_name\_string}(\\{cur\_file})$;\5 +$\\{str\_ref}[\\{cur\_name}]\K\\{max\_str\_ref}$;\6 +\&{if} $\\{job\_name}=0$ \1\&{then}\6 +\&{begin} \37$\\{job\_name}\K\\{cur\_name}$;\5 +\\{open\_log\_file};\6 +\&{end};\C{\\{open\_log\_file} doesn't \\{show\_context}, so \\{limit} and % +\\{loc} needn't be set to meaningful values yet}\2\6 +\&{if} $\\{term\_offset}+\\{length}(\\{name})>\\{max\_print\_line}-2$ \1% +\&{then}\5 +\\{print\_ln}\6 +\4\&{else} \&{if} $(\\{term\_offset}>0)\V(\\{file\_offset}>0)$ \1\&{then}\5 +$\\{print\_char}(\.{"\ "})$;\2\2\6 +$\\{print\_char}(\.{"("})$;\5 +$\\{incr}(\\{open\_parens})$;\5 +$\\{slow\_print}(\\{name})$;\5 +\\{update\_terminal};\6 +\&{if} $\\{name}=\\{str\_ptr}-1$ \1\&{then}\C{we can conserve string pool space +now}\6 +\&{begin} \37$\\{flush\_string}(\\{name})$;\5 +$\\{name}\K\\{cur\_name}$;\6 +\&{end};\2\6 +\X794:Read the first line of the new file\X;\6 +\&{end};\par +\fi + +\M794. Here we have to remember to tell the \\{input\_ln} routine not to +start with a \\{get}. If the file is empty, it is considered to +contain a single blank line. + +\Y\P$\4\X794:Read the first line of the new file\X\S$\6 +\&{begin} \37$\\{line}\K1$;\6 +\&{if} $\\{input\_ln}(\\{cur\_file},\39\\{false})$ \1\&{then}\5 +\\{do\_nothing};\2\6 +\\{firm\_up\_the\_line};\5 +$\\{buffer}[\\{limit}]\K\.{"\%"}$;\5 +$\\{first}\K\\{limit}+1$;\5 +$\\{loc}\K\\{start}$;\6 +\&{end}\par +\U793.\fi + +\M795. \P$\X795:Put the desired file name in $(\\{cur\_name},\\{cur\_ext},% +\\{cur\_area})$\X\S$\6 +\&{while} $\\{token\_state}\W(\\{loc}=\\{null})$ \1\&{do}\5 +\\{end\_token\_list};\2\6 +\&{if} $\\{token\_state}$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"File\ names\ can\'t\ appear\ within\ +macros"})$;\5 +$\\{help3}(\.{"Sorry...I\'ve\ converted\ what\ follows\ to\ tokens,"})$\6 +$(\.{"possibly\ garbaging\ the\ name\ you\ gave."})$\6 +$(\.{"Please\ delete\ the\ tokens\ and\ insert\ the\ name\ again."})$;\6 +\\{error};\6 +\&{end};\2\6 +\&{if} $\\{file\_state}$ \1\&{then}\5 +\\{scan\_file\_name}\6 +\4\&{else} \&{begin} \37$\\{cur\_name}\K\.{""}$;\5 +$\\{cur\_ext}\K\.{""}$;\5 +$\\{cur\_area}\K\.{""}$;\6 +\&{end}\2\par +\U793.\fi + +\N796. \[39] Introduction to the parsing routines. +We come now to the central nervous system that sparks many of \MF's activities. +By evaluating expressions, from their primary constituents to ever larger +subexpressions, \MF\ builds the structures that ultimately define fonts of +type. + +Four mutually recursive subroutines are involved in this process: We call them +$$\hbox{\\{scan\_primary}, \\{scan\_secondary}, \\{scan\_tertiary}, +and \\{scan\_expression}.}$$ +Each of them is parameterless and begins with the first token to be scanned +already represented in \\{cur\_cmd}, \\{cur\_mod}, and \\{cur\_sym}. After +execution, +the value of the primary or secondary or tertiary or expression that was +found will appear in the global variables \\{cur\_type} and \\{cur\_exp}. The +token following the expression will be represented in \\{cur\_cmd}, \\{cur% +\_mod}, +and \\{cur\_sym}. + +Technically speaking, the parsing algorithms are ``LL(1),'' more or less; +backup mechanisms have been added in order to provide reasonable error +recovery. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{cur\_type}: \37\\{small\_number};\C{the type of the expression just found}% +\6 +\4\\{cur\_exp}: \37\\{integer};\C{the value of the expression just found}\par +\fi + +\M797. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{cur\_exp}\K0$;\par +\fi + +\M798. Many different kinds of expressions are possible, so it is wise to have +precise descriptions of what \\{cur\_type} and \\{cur\_exp} mean in all cases: + +\smallskip\hang +$\\{cur\_type}=\\{vacuous}$ means that this expression didn't turn out to have +a +value at all, because it arose from a \&{begingroup}$\,\ldots\,$\&{endgroup} +construction in which there was no expression before the \&{endgroup}. +In this case \\{cur\_exp} has some irrelevant value. + +\smallskip\hang +$\\{cur\_type}=\\{boolean\_type}$ means that \\{cur\_exp} is either \\{true% +\_code} +or \\{false\_code}. + +\smallskip\hang +$\\{cur\_type}=\\{unknown\_boolean}$ means that \\{cur\_exp} points to a +capsule +node that is in the ring of variables equivalent +to at least one undefined boolean variable. + +\smallskip\hang +$\\{cur\_type}=\\{string\_type}$ means that \\{cur\_exp} is a string number +(i.e., an +integer in the range $0\L\\{cur\_exp}<\\{str\_ptr}$). That string's reference +count +includes this particular reference. + +\smallskip\hang +$\\{cur\_type}=\\{unknown\_string}$ means that \\{cur\_exp} points to a capsule +node that is in the ring of variables equivalent +to at least one undefined string variable. + +\smallskip\hang +$\\{cur\_type}=\\{pen\_type}$ means that \\{cur\_exp} points to a pen header +node. This +node contains a reference count, which takes account of this particular +reference. + +\smallskip\hang +$\\{cur\_type}=\\{unknown\_pen}$ means that \\{cur\_exp} points to a capsule +node that is in the ring of variables equivalent +to at least one undefined pen variable. + +\smallskip\hang +$\\{cur\_type}=\\{future\_pen}$ means that \\{cur\_exp} points to a knot list +that +should eventually be made into a pen. Nobody else points to this particular +knot list. The \\{future\_pen} option occurs only as an output of \\{scan% +\_primary} +and \\{scan\_secondary}, not as an output of \\{scan\_tertiary} or \\{scan% +\_expression}. + +\smallskip\hang +$\\{cur\_type}=\\{path\_type}$ means that \\{cur\_exp} points to a the first +node of +a path; nobody else points to this particular path. The control points of +the path will have been chosen. + +\smallskip\hang +$\\{cur\_type}=\\{unknown\_path}$ means that \\{cur\_exp} points to a capsule +node that is in the ring of variables equivalent +to at least one undefined path variable. + +\smallskip\hang +$\\{cur\_type}=\\{picture\_type}$ means that \\{cur\_exp} points to an edges +header node. +Nobody else points to this particular set of edges. + +\smallskip\hang +$\\{cur\_type}=\\{unknown\_picture}$ means that \\{cur\_exp} points to a +capsule +node that is in the ring of variables equivalent +to at least one undefined picture variable. + +\smallskip\hang +$\\{cur\_type}=\\{transform\_type}$ means that \\{cur\_exp} points to a % +\\{transform\_type} +capsule node. The \\{value} part of this capsule +points to a transform node that contains six numeric values, +each of which is \\{independent}, \\{dependent}, \\{proto\_dependent}, or % +\\{known}. + +\smallskip\hang +$\\{cur\_type}=\\{pair\_type}$ means that \\{cur\_exp} points to a capsule +node whose type is \\{pair\_type}. The \\{value} part of this capsule +points to a pair node that contains two numeric values, +each of which is \\{independent}, \\{dependent}, \\{proto\_dependent}, or % +\\{known}. + +\smallskip\hang +$\\{cur\_type}=\\{known}$ means that \\{cur\_exp} is a \\{scaled} value. + +\smallskip\hang +$\\{cur\_type}=\\{dependent}$ means that \\{cur\_exp} points to a capsule node +whose type +is \\{dependent}. The \\{dep\_list} field in this capsule points to the +associated +dependency list. + +\smallskip\hang +$\\{cur\_type}=\\{proto\_dependent}$ means that \\{cur\_exp} points to a % +\\{proto\_dependent} +capsule node . The \\{dep\_list} field in this capsule +points to the associated dependency list. + +\smallskip\hang +$\\{cur\_type}=\\{independent}$ means that \\{cur\_exp} points to a capsule +node +whose type is \\{independent}. This somewhat unusual case can arise, for +example, in the expression +`$x+\&{begingroup}\penalty0\,\&{string}\,x; 0\,\&{endgroup}$'. + +\smallskip\hang +$\\{cur\_type}=\\{token\_list}$ means that \\{cur\_exp} points to a linked list +of +tokens. This case arises only on the left-hand side of an assignment +(`\.{:=}') operation, under very special circumstances. + +\smallskip\noindent +The possible settings of \\{cur\_type} have been listed here in increasing +numerical order. Notice that \\{cur\_type} will never be \\{numeric\_type} or +\\{suffixed\_macro} or \\{unsuffixed\_macro}, although variables of those types +are allowed. Conversely, \MF\ has no variables of type \\{vacuous} or +\\{token\_list}. + +\fi + +\M799. Capsules are two-word nodes that have a similar meaning +to \\{cur\_type} and \\{cur\_exp}. Such nodes have $\\{name\_type}=\\{capsule}$ +and $\\{link}\L\\{void}$; and their \\{type} field is one of the possibilities +for +\\{cur\_type} listed above. + +The \\{value} field of a capsule is, in most cases, the value that +corresponds to its \\{type}, as \\{cur\_exp} corresponds to \\{cur\_type}. +However, when \\{cur\_exp} would point to a capsule, +no extra layer of indirection is present; the \\{value} +field is what would have been called $\\{value}(\\{cur\_exp})$ if it had not +been +encapsulated. Furthermore, if the type is \\{dependent} or +\\{proto\_dependent}, the \\{value} field of a capsule is replaced by +\\{dep\_list} and \\{prev\_dep} fields, since dependency lists in capsules are +always part of the general \\{dep\_list} structure. + +The \\{get\_x\_next} routine is careful not to change the values of \\{cur% +\_type} +and \\{cur\_exp} when it gets an expanded token. However, \\{get\_x\_next} +might +call a macro, which might parse an expression, which might execute lots of +commands in a group; hence it's possible that \\{cur\_type} might change +from, say, \\{unknown\_boolean} to \\{boolean\_type}, or from \\{dependent} to +\\{known} or \\{independent}, during the time \\{get\_x\_next} is called. The +programs below are careful to stash sensitive intermediate results in +capsules, so that \MF's generality doesn't cause trouble. + +Here's a procedure that illustrates these conventions. It takes +the contents of $(\\{cur\_type}\kern-.3pt,\\{cur\_exp}\kern-.3pt)$ +and stashes them away in a +capsule. It is not used when $\\{cur\_type}=\\{token\_list}$. +After the operation, $\\{cur\_type}=\\{vacuous}$; hence there is no need to +copy path lists or to update reference counts, etc. + +The special link \\{void} is put on the capsule returned by +\\{stash\_cur\_exp}, because this procedure is used to store macro parameters +that must be easily distinguishable from token lists. + +\Y\P$\4\X799:Declare the stashing/unstashing routines\X\S$\6 +\4\&{function}\1\ \37\\{stash\_cur\_exp}: \37\\{pointer};\6 +\4\&{var} \37\|p: \37\\{pointer};\C{the capsule that will be returned}\2\6 +\&{begin} \37\&{case} $\\{cur\_type}$ \1\&{of}\6 +\4$\\{unknown\_types},\39\\{transform\_type},\39\\{pair\_type},\39% +\\{dependent},\39\\{proto\_dependent},\39\\{independent}$: \37$\|p\K\\{cur% +\_exp}$;\6 +\4\&{othercases} \37\&{begin} \37$\|p\K\\{get\_node}(\\{value\_node\_size})$;\5 +$\\{name\_type}(\|p)\K\\{capsule}$;\5 +$\\{type}(\|p)\K\\{cur\_type}$;\5 +$\\{value}(\|p)\K\\{cur\_exp}$;\6 +\&{end}\2\6 +\&{endcases};\6 +$\\{cur\_type}\K\\{vacuous}$;\5 +$\\{link}(\|p)\K\\{void}$;\5 +$\\{stash\_cur\_exp}\K\|p$;\6 +\&{end};\par +\A800. +\U801.\fi + +\M800. The inverse of \\{stash\_cur\_exp} is the following procedure, which +deletes an unnecessary capsule and puts its contents into \\{cur\_type} +and \\{cur\_exp}. + +The program steps of \MF\ can be divided into two categories: those in +which \\{cur\_type} and \\{cur\_exp} are ``alive'' and those in which they are +``dead,'' in the sense that \\{cur\_type} and \\{cur\_exp} contain relevant +information or not. It's important not to ignore them when they're alive, +and it's important not to pay attention to them when they're dead. + +There's also an intermediate category: If $\\{cur\_type}=\\{vacuous}$, then +\\{cur\_exp} is irrelevant, hence we can proceed without caring if \\{cur% +\_type} +and \\{cur\_exp} are alive or dead. In such cases we say that \\{cur\_type} +and \\{cur\_exp} are {\sl dormant}. It is permissible to call \\{get\_x\_next} +only when they are alive or dormant. + +The \\{stash} procedure above assumes that \\{cur\_type} and \\{cur\_exp} +are alive or dormant. The \\{unstash} procedure assumes that they are +dead or dormant; it resuscitates them. + +\Y\P$\4\X799:Declare the stashing/unstashing routines\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{unstash\_cur\_exp}(\|p:\\{pointer})$;\2\6 +\&{begin} \37$\\{cur\_type}\K\\{type}(\|p)$;\6 +\&{case} $\\{cur\_type}$ \1\&{of}\6 +\4$\\{unknown\_types},\39\\{transform\_type},\39\\{pair\_type},\39% +\\{dependent},\39\\{proto\_dependent},\39\\{independent}$: \37$\\{cur\_exp}\K% +\|p$;\6 +\4\&{othercases} \37\&{begin} \37$\\{cur\_exp}\K\\{value}(\|p)$;\5 +$\\{free\_node}(\|p,\39\\{value\_node\_size})$;\6 +\&{end}\2\6 +\&{endcases};\6 +\&{end};\par +\fi + +\M801. The following procedure prints the values of expressions in an +abbreviated format. If its first parameter \|p is null, the value of +$(\\{cur\_type},\\{cur\_exp})$ is displayed; otherwise \|p should be a capsule +containing the desired value. The second parameter controls the amount of +output. If it is~0, dependency lists will be abbreviated to +`\.{linearform}' unless they consist of a single term. If it is greater +than~1, complicated structures (pens, pictures, and paths) will be displayed +in full. + +\Y\P$\4\X257:Declare subroutines for printing expressions\X\mathrel{+}\S$\6 +\hbox{\4}\X805:Declare the procedure called \\{print\_dp}\X\6 +\hbox{\4}\X799:Declare the stashing/unstashing routines\X\6 +\4\&{procedure}\1\ \37$\\{print\_exp}(\|p:\\{pointer};\,\35\\{verbosity}:% +\\{small\_number})$;\6 +\4\&{var} \37\\{restore\_cur\_exp}: \37\\{boolean};\C{should \\{cur\_exp} be +restored?}\6 +\|t: \37\\{small\_number};\C{the type of the expression}\6 +\|v: \37\\{integer};\C{the value of the expression}\6 +\|q: \37\\{pointer};\C{a big node being displayed}\2\6 +\&{begin} \37\&{if} $\|p\I\\{null}$ \1\&{then}\5 +$\\{restore\_cur\_exp}\K\\{false}$\6 +\4\&{else} \&{begin} \37$\|p\K\\{stash\_cur\_exp}$;\5 +$\\{restore\_cur\_exp}\K\\{true}$;\6 +\&{end};\2\6 +$\|t\K\\{type}(\|p)$;\6 +\&{if} $\|t<\\{dependent}$ \1\&{then}\5 +$\|v\K\\{value}(\|p)$\ \&{else} \&{if} $\|t<\\{independent}$ \1\&{then}\5 +$\|v\K\\{dep\_list}(\|p)$;\2\2\6 +\X802:Print an abbreviated value of \|v with format depending on \|t\X;\6 +\&{if} $\\{restore\_cur\_exp}$ \1\&{then}\5 +$\\{unstash\_cur\_exp}(\|p)$;\2\6 +\&{end};\par +\fi + +\M802. \P$\X802:Print an abbreviated value of \|v with format depending on \|t% +\X\S$\6 +\&{case} $\|t$ \1\&{of}\6 +\4\\{vacuous}: \37$\\{print}(\.{"vacuous"})$;\6 +\4\\{boolean\_type}: \37\&{if} $\|v=\\{true\_code}$ \1\&{then}\5 +$\\{print}(\.{"true"})$\ \&{else} $\\{print}(\.{"false"})$;\2\6 +\4$\\{unknown\_types},\39\\{numeric\_type}$: \37\X806:Display a variable that's +been declared but not defined\X;\6 +\4\\{string\_type}: \37\&{begin} \37$\\{print\_char}(\.{""}\.{""})$;\5 +$\\{slow\_print}(\|v)$;\5 +$\\{print\_char}(\.{""}\.{""})$;\6 +\&{end};\6 +\4$\\{pen\_type},\39\\{future\_pen},\39\\{path\_type},\39\\{picture\_type}$: % +\37\X804:Display a complex type\X;\6 +\4$\\{transform\_type},\39\\{pair\_type}$: \37\&{if} $\|v=\\{null}$ \1\&{then}\5 +$\\{print\_type}(\|t)$\6 +\4\&{else} \X803:Display a big node\X;\2\6 +\4\\{known}: \37$\\{print\_scaled}(\|v)$;\6 +\4$\\{dependent},\39\\{proto\_dependent}$: \37$\\{print\_dp}(\|t,\39\|v,\39% +\\{verbosity})$;\6 +\4\\{independent}: \37$\\{print\_variable\_name}(\|p)$;\6 +\4\&{othercases} \37$\\{confusion}(\.{"exp"})$\2\6 +\&{endcases}\par +\U801.\fi + +\M803. \P$\X803:Display a big node\X\S$\6 +\&{begin} \37$\\{print\_char}(\.{"("})$;\5 +$\|q\K\|v+\\{big\_node\_size}[\|t]$;\6 +\1\&{repeat} \37\&{if} $\\{type}(\|v)=\\{known}$ \1\&{then}\5 +$\\{print\_scaled}(\\{value}(\|v))$\6 +\4\&{else} \&{if} $\\{type}(\|v)=\\{independent}$ \1\&{then}\5 +$\\{print\_variable\_name}(\|v)$\6 +\4\&{else} $\\{print\_dp}(\\{type}(\|v),\39\\{dep\_list}(\|v),\39% +\\{verbosity})$;\2\2\6 +$\|v\K\|v+2$;\6 +\&{if} $\|v\I\|q$ \1\&{then}\5 +$\\{print\_char}(\.{","})$;\2\6 +\4\&{until}\5 +$\|v=\|q$;\2\6 +$\\{print\_char}(\.{")"})$;\6 +\&{end}\par +\U802.\fi + +\M804. Values of type \&{picture}, \&{path}, and \&{pen} are displayed +verbosely +in the log file only, unless the user has given a positive value to +\\{tracingonline}. + +\Y\P$\4\X804:Display a complex type\X\S$\6 +\&{if} $\\{verbosity}\L1$ \1\&{then}\5 +$\\{print\_type}(\|t)$\6 +\4\&{else} \&{begin} \37\&{if} $\\{selector}=\\{term\_and\_log}$ \1\&{then}\6 +\&{if} $\\{internal}[\\{tracing\_online}]\L0$ \1\&{then}\6 +\&{begin} \37$\\{selector}\K\\{term\_only}$;\5 +$\\{print\_type}(\|t)$;\5 +$\\{print}(\.{"\ (see\ the\ transcript\ file)"})$;\5 +$\\{selector}\K\\{term\_and\_log}$;\6 +\&{end};\2\2\6 +\&{case} $\|t$ \1\&{of}\6 +\4\\{pen\_type}: \37$\\{print\_pen}(\|v,\39\.{""},\39\\{false})$;\6 +\4\\{future\_pen}: \37$\\{print\_path}(\|v,\39\.{"\ (future\ pen)"},\39% +\\{false})$;\6 +\4\\{path\_type}: \37$\\{print\_path}(\|v,\39\.{""},\39\\{false})$;\6 +\4\\{picture\_type}: \37\&{begin} \37$\\{cur\_edges}\K\|v$;\5 +$\\{print\_edges}(\.{""},\39\\{false},\390,\390)$;\6 +\&{end};\2\6 +\&{end};\C{there are no other cases}\6 +\&{end}\2\par +\U802.\fi + +\M805. \P$\X805:Declare the procedure called \\{print\_dp}\X\S$\6 +\4\&{procedure}\1\ \37$\\{print\_dp}(\|t:\\{small\_number};\,\35\|p:% +\\{pointer};\,\35\\{verbosity}:\\{small\_number})$;\6 +\4\&{var} \37\|q: \37\\{pointer};\C{the node following \|p}\2\6 +\&{begin} \37$\|q\K\\{link}(\|p)$;\6 +\&{if} $(\\{info}(\|q)=\\{null})\V(\\{verbosity}>0)$ \1\&{then}\5 +$\\{print\_dependency}(\|p,\39\|t)$\6 +\4\&{else} $\\{print}(\.{"linearform"})$;\2\6 +\&{end};\par +\U801.\fi + +\M806. The displayed name of a variable in a ring will not be a capsule unless +the ring consists entirely of capsules. + +\Y\P$\4\X806:Display a variable that's been declared but not defined\X\S$\6 +\&{begin} \37$\\{print\_type}(\|t)$;\6 +\&{if} $\|v\I\\{null}$ \1\&{then}\6 +\&{begin} \37$\\{print\_char}(\.{"\ "})$;\6 +\&{while} $(\\{name\_type}(\|v)=\\{capsule})\W(\|v\I\|p)$ \1\&{do}\5 +$\|v\K\\{value}(\|v)$;\2\6 +$\\{print\_variable\_name}(\|v)$;\6 +\&{end};\2\6 +\&{end}\par +\U802.\fi + +\M807. When errors are detected during parsing, it is often helpful to +display an expression just above the error message, using \\{exp\_err} +or \\{disp\_err} instead of \\{print\_err}. + +\Y\P\D \37$\\{exp\_err}(\#)\S\\{disp\_err}(\\{null},\39\#)$\C{displays the +current expression}\par +\Y\P$\4\X257:Declare subroutines for printing expressions\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{disp\_err}(\|p:\\{pointer};\,\35\|s:\\{str% +\_number})$;\2\6 +\&{begin} \37\&{if} $\\{interaction}=\\{error\_stop\_mode}$ \1\&{then}\5 +\\{wake\_up\_terminal};\2\6 +$\\{print\_nl}(\.{">>\ "})$;\5 +$\\{print\_exp}(\|p,\391)$;\C{``medium verbose'' printing of the expression}\6 +\&{if} $\|s\I\.{""}$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"!\ "})$;\5 +$\\{print}(\|s)$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M808. If \\{cur\_type} and \\{cur\_exp} contain relevant information that +should +be recycled, we will use the following procedure, which changes \\{cur\_type} +to \\{known} and stores a given value in \\{cur\_exp}. We can think of \\{cur% +\_type} +and \\{cur\_exp} as either alive or dormant after this has been done, +because \\{cur\_exp} will not contain a pointer value. + +\Y\P$\4\X808:Declare the procedure called \\{flush\_cur\_exp}\X\S$\6 +\4\&{procedure}\1\ \37$\\{flush\_cur\_exp}(\|v:\\{scaled})$;\2\6 +\&{begin} \37\&{case} $\\{cur\_type}$ \1\&{of}\6 +\4$\\{unknown\_types},\39\\{transform\_type},\39\\{pair\_type},\39\30% +\\{dependent},\39\\{proto\_dependent},\39\\{independent}$: \37\&{begin} \37$% +\\{recycle\_value}(\\{cur\_exp})$;\5 +$\\{free\_node}(\\{cur\_exp},\39\\{value\_node\_size})$;\6 +\&{end};\6 +\4\\{pen\_type}: \37$\\{delete\_pen\_ref}(\\{cur\_exp})$;\6 +\4\\{string\_type}: \37$\\{delete\_str\_ref}(\\{cur\_exp})$;\6 +\4$\\{future\_pen},\39\\{path\_type}$: \37$\\{toss\_knot\_list}(\\{cur\_exp})$;% +\6 +\4\\{picture\_type}: \37$\\{toss\_edges}(\\{cur\_exp})$;\6 +\4\&{othercases} \37\\{do\_nothing}\2\6 +\&{endcases};\6 +$\\{cur\_type}\K\\{known}$;\5 +$\\{cur\_exp}\K\|v$;\6 +\&{end};\par +\A820. +\U246.\fi + +\M809. There's a much more general procedure that is capable of releasing +the storage associated with any two-word value packet. + +\Y\P$\4\X268:Declare the recycling subroutines\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{recycle\_value}(\|p:\\{pointer})$;\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37\|t: \37\\{small\_number};\C{a type code}\6 +\|v: \37\\{integer};\C{a value}\6 +\\{vv}: \37\\{integer};\C{another value}\6 +$\|q,\39\|r,\39\|s,\39\\{pp}$: \37\\{pointer};\C{link manipulation registers}\2% +\6 +\&{begin} \37$\|t\K\\{type}(\|p)$;\6 +\&{if} $\|t<\\{dependent}$ \1\&{then}\5 +$\|v\K\\{value}(\|p)$;\2\6 +\&{case} $\|t$ \1\&{of}\6 +\4$\\{undefined},\39\\{vacuous},\39\\{boolean\_type},\39\\{known},\39\\{numeric% +\_type}$: \37\\{do\_nothing};\6 +\4\\{unknown\_types}: \37$\\{ring\_delete}(\|p)$;\6 +\4\\{string\_type}: \37$\\{delete\_str\_ref}(\|v)$;\6 +\4\\{pen\_type}: \37$\\{delete\_pen\_ref}(\|v)$;\6 +\4$\\{path\_type},\39\\{future\_pen}$: \37$\\{toss\_knot\_list}(\|v)$;\6 +\4\\{picture\_type}: \37$\\{toss\_edges}(\|v)$;\6 +\4$\\{pair\_type},\39\\{transform\_type}$: \37\X810:Recycle a big node\X;\6 +\4$\\{dependent},\39\\{proto\_dependent}$: \37\X811:Recycle a dependency list% +\X;\6 +\4\\{independent}: \37\X812:Recycle an independent variable\X;\6 +\4$\\{token\_list},\39\\{structured}$: \37$\\{confusion}(\.{"recycle"})$;\6 +\4$\\{unsuffixed\_macro},\39\\{suffixed\_macro}$: \37$\\{delete\_mac\_ref}(% +\\{value}(\|p))$;\2\6 +\&{end};\C{there are no other cases}\6 +$\\{type}(\|p)\K\\{undefined}$;\6 +\&{end};\par +\fi + +\M810. \P$\X810:Recycle a big node\X\S$\6 +\&{if} $\|v\I\\{null}$ \1\&{then}\6 +\&{begin} \37$\|q\K\|v+\\{big\_node\_size}[\|t]$;\6 +\1\&{repeat} \37$\|q\K\|q-2$;\5 +$\\{recycle\_value}(\|q)$;\6 +\4\&{until}\5 +$\|q=\|v$;\2\6 +$\\{free\_node}(\|v,\39\\{big\_node\_size}[\|t])$;\6 +\&{end}\2\par +\U809.\fi + +\M811. \P$\X811:Recycle a dependency list\X\S$\6 +\&{begin} \37$\|q\K\\{dep\_list}(\|p)$;\6 +\&{while} $\\{info}(\|q)\I\\{null}$ \1\&{do}\5 +$\|q\K\\{link}(\|q)$;\2\6 +$\\{link}(\\{prev\_dep}(\|p))\K\\{link}(\|q)$;\5 +$\\{prev\_dep}(\\{link}(\|q))\K\\{prev\_dep}(\|p)$;\5 +$\\{link}(\|q)\K\\{null}$;\5 +$\\{flush\_node\_list}(\\{dep\_list}(\|p))$;\6 +\&{end}\par +\U809.\fi + +\M812. When an independent variable disappears, it simply fades away, unless +something depends on it. In the latter case, a dependent variable whose +coefficient of dependence is maximal will take its place. +The relevant algorithm is due to Ignacio~A. Zabala, who implemented it +as part of his Ph.D. thesis (Stanford University, December 1982). + +For example, suppose that variable $x$ is being recycled, and that the +only variables depending on~$x$ are $y=2x+a$ and $z=x+b$. In this case +we want to make $y$ independent and $z=.5y-.5a+b$; no other variables +will depend on~$y$. If $\\{tracingequations}>0$ in this situation, +we will print `\.{\#\#\# -2x=-y+a}'. + +There's a slight complication, however: An independent variable $x$ +can occur both in dependency lists and in proto-dependency lists. +This makes it necessary to be careful when deciding which coefficient +is maximal. + +Furthermore, this complication is not so slight when +a proto-dependent variable is chosen to become independent. For example, +suppose that $y=2x+100a$ is proto-dependent while $z=x+b$ is dependent; +then we must change $z=.5y-50a+b$ to a proto-dependency, because of the +large coefficient `50'. + +In order to deal with these complications without wasting too much time, +we shall link together the occurrences of~$x$ among all the linear +dependencies, maintaining separate lists for the dependent and +proto-dependent cases. + +\Y\P$\4\X812:Recycle an independent variable\X\S$\6 +\&{begin} \37$\\{max\_c}[\\{dependent}]\K0$;\5 +$\\{max\_c}[\\{proto\_dependent}]\K0$;\6 +$\\{max\_link}[\\{dependent}]\K\\{null}$;\5 +$\\{max\_link}[\\{proto\_dependent}]\K\\{null}$;\6 +$\|q\K\\{link}(\\{dep\_head})$;\6 +\&{while} $\|q\I\\{dep\_head}$ \1\&{do}\6 +\&{begin} \37$\|s\K\\{value\_loc}(\|q)$;\C{now $\\{link}(\|s)=\\{dep\_list}(% +\|q)$}\6 +\~ \1\&{loop}\ \&{begin} \37$\|r\K\\{link}(\|s)$;\6 +\&{if} $\\{info}(\|r)=\\{null}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +\&{if} $\\{info}(\|r)\I\|p$ \1\&{then}\5 +$\|s\K\|r$\6 +\4\&{else} \&{begin} \37$\|t\K\\{type}(\|q)$;\5 +$\\{link}(\|s)\K\\{link}(\|r)$;\5 +$\\{info}(\|r)\K\|q$;\6 +\&{if} $\\{abs}(\\{value}(\|r))>\\{max\_c}[\|t]$ \1\&{then}\5 +\X814:Record a new maximum coefficient of type \|t\X\6 +\4\&{else} \&{begin} \37$\\{link}(\|r)\K\\{max\_link}[\|t]$;\5 +$\\{max\_link}[\|t]\K\|r$;\6 +\&{end};\2\6 +\&{end};\2\6 +\&{end};\2\6 +\4\\{done}: \37$\|q\K\\{link}(\|r)$;\6 +\&{end};\2\6 +\&{if} $(\\{max\_c}[\\{dependent}]>0)\V(\\{max\_c}[\\{proto\_dependent}]>0)$ \1% +\&{then}\5 +\X815:Choose a dependent variable to take the place of the disappearing +independent variable, and change all remaining dependencies accordingly\X;\2\6 +\&{end}\par +\U809.\fi + +\M813. The code for independency removal makes use of three two-word arrays. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{max\_c}: \37\&{array} $[\\{dependent}\to\\{proto\_dependent}]$ \1\&{of}\5 +\\{integer};\C{max coefficient magnitude}\2\6 +\4\\{max\_ptr}: \37\&{array} $[\\{dependent}\to\\{proto\_dependent}]$ \1\&{of}\5 +\\{pointer};\C{where \|p occurs with \\{max\_c}}\2\6 +\4\\{max\_link}: \37\&{array} $[\\{dependent}\to\\{proto\_dependent}]$ \1\&{of}% +\5 +\\{pointer};\C{other occurrences of \|p}\2\par +\fi + +\M814. \P$\X814:Record a new maximum coefficient of type \|t\X\S$\6 +\&{begin} \37\&{if} $\\{max\_c}[\|t]>0$ \1\&{then}\6 +\&{begin} \37$\\{link}(\\{max\_ptr}[\|t])\K\\{max\_link}[\|t]$;\5 +$\\{max\_link}[\|t]\K\\{max\_ptr}[\|t]$;\6 +\&{end};\2\6 +$\\{max\_c}[\|t]\K\\{abs}(\\{value}(\|r))$;\5 +$\\{max\_ptr}[\|t]\K\|r$;\6 +\&{end}\par +\U812.\fi + +\M815. \P$\X815:Choose a dependent variable to take the place of the +disappearing independent variable, and change all remaining dependencies +accordingly\X\S$\6 +\&{begin} \37\&{if} $(\\{max\_c}[\\{dependent}]\mathbin{\&{div}}\O{10000}\G% +\\{max\_c}[\\{proto\_dependent}])$ \1\&{then}\5 +$\|t\K\\{dependent}$\6 +\4\&{else} $\|t\K\\{proto\_dependent}$;\2\6 +\X816:Determine the dependency list \|s to substitute for the independent +variable~\|p\X;\6 +$\|t\K\\{dependent}+\\{proto\_dependent}-\|t$;\C{complement \|t}\6 +\&{if} $\\{max\_c}[\|t]>0$ \1\&{then}\C{we need to pick up an unchosen +dependency}\6 +\&{begin} \37$\\{link}(\\{max\_ptr}[\|t])\K\\{max\_link}[\|t]$;\5 +$\\{max\_link}[\|t]\K\\{max\_ptr}[\|t]$;\6 +\&{end};\2\6 +\&{if} $\|t\I\\{dependent}$ \1\&{then}\5 +\X818:Substitute new dependencies in place of \|p\X\6 +\4\&{else} \X819:Substitute new proto-dependencies in place of \|p\X;\2\6 +$\\{flush\_node\_list}(\|s)$;\6 +\&{if} $\\{fix\_needed}$ \1\&{then}\5 +\\{fix\_dependencies};\2\6 +\\{check\_arith};\6 +\&{end}\par +\U812.\fi + +\M816. Let $\|s=\\{max\_ptr}[\|t]$. At this point we have $\\{value}(s)=\pm% +\\{max\_c}[t]$, +and $\\{info}(\|s)$ points to the dependent variable~\\{pp} of type~\|t from +whose dependency list we have removed node~\|s. We must reinsert +node~\|s into the dependency list, with coefficient $-1.0$, and with +\\{pp} as the new independent variable. Since \\{pp} will have a larger serial +number than any other variable, we can put node \|s at the head of the +list. + +\Y\P$\4\X816:Determine the dependency list \|s to substitute for the +independent variable~\|p\X\S$\6 +$\|s\K\\{max\_ptr}[\|t]$;\5 +$\\{pp}\K\\{info}(\|s)$;\5 +$\|v\K\\{value}(\|s)$;\6 +\&{if} $\|t=\\{dependent}$ \1\&{then}\5 +$\\{value}(\|s)\K-\\{fraction\_one}$\ \&{else} $\\{value}(\|s)\K-\\{unity}$;\2\6 +$\|r\K\\{dep\_list}(\\{pp})$;\5 +$\\{link}(\|s)\K\|r$;\6 +\&{while} $\\{info}(\|r)\I\\{null}$ \1\&{do}\5 +$\|r\K\\{link}(\|r)$;\2\6 +$\|q\K\\{link}(\|r)$;\5 +$\\{link}(\|r)\K\\{null}$;\5 +$\\{prev\_dep}(\|q)\K\\{prev\_dep}(\\{pp})$;\5 +$\\{link}(\\{prev\_dep}(\\{pp}))\K\|q$;\5 +$\\{new\_indep}(\\{pp})$;\6 +\&{if} $\\{cur\_exp}=\\{pp}$ \1\&{then}\6 +\&{if} $\\{cur\_type}=\|t$ \1\&{then}\5 +$\\{cur\_type}\K\\{independent}$;\2\2\6 +\&{if} $\\{internal}[\\{tracing\_equations}]>0$ \1\&{then}\5 +\X817:Show the transformed dependency\X\2\par +\U815.\fi + +\M817. Now $(-v)$ times the formerly independent variable~\|p is being replaced +by the dependency list~\|s. + +\Y\P$\4\X817:Show the transformed dependency\X\S$\6 +\&{if} $\\{interesting}(\|p)$ \1\&{then}\6 +\&{begin} \37\\{begin\_diagnostic};\5 +$\\{print\_nl}(\.{"\#\#\#\ "})$;\6 +\&{if} $\|v>0$ \1\&{then}\5 +$\\{print\_char}(\.{"-"})$;\2\6 +\&{if} $\|t=\\{dependent}$ \1\&{then}\5 +$\\{vv}\K\\{round\_fraction}(\\{max\_c}[\\{dependent}])$\6 +\4\&{else} $\\{vv}\K\\{max\_c}[\\{proto\_dependent}]$;\2\6 +\&{if} $\\{vv}\I\\{unity}$ \1\&{then}\5 +$\\{print\_scaled}(\\{vv})$;\2\6 +$\\{print\_variable\_name}(\|p)$;\6 +\&{while} $\\{value}(\|p)\mathbin{\&{mod}}\\{s\_scale}>0$ \1\&{do}\6 +\&{begin} \37$\\{print}(\.{"*4"})$;\5 +$\\{value}(\|p)\K\\{value}(\|p)-2$;\6 +\&{end};\2\6 +\&{if} $\|t=\\{dependent}$ \1\&{then}\5 +$\\{print\_char}(\.{"="})$\ \&{else} $\\{print}(\.{"\ =\ "})$;\2\6 +$\\{print\_dependency}(\|s,\39\|t)$;\5 +$\\{end\_diagnostic}(\\{false})$;\6 +\&{end}\2\par +\U816.\fi + +\M818. Finally, there are dependent and proto-dependent variables whose +dependency lists must be brought up to date. + +\Y\P$\4\X818:Substitute new dependencies in place of \|p\X\S$\6 +\&{for} $\|t\K\\{dependent}\mathrel{\&{to}}\\{proto\_dependent}$ \1\&{do}\6 +\&{begin} \37$\|r\K\\{max\_link}[\|t]$;\6 +\&{while} $\|r\I\\{null}$ \1\&{do}\6 +\&{begin} \37$\|q\K\\{info}(\|r)$;\5 +$\\{dep\_list}(\|q)\K\\{p\_plus\_fq}(\\{dep\_list}(\|q),\39\30\\{make% +\_fraction}(\\{value}(\|r),\39-\|v),\39\|s,\39\|t,\39\\{dependent})$;\6 +\&{if} $\\{dep\_list}(\|q)=\\{dep\_final}$ \1\&{then}\5 +$\\{make\_known}(\|q,\39\\{dep\_final})$;\2\6 +$\|q\K\|r$;\5 +$\|r\K\\{link}(\|r)$;\5 +$\\{free\_node}(\|q,\39\\{dep\_node\_size})$;\6 +\&{end};\2\6 +\&{end}\2\par +\U815.\fi + +\M819. \P$\X819:Substitute new proto-dependencies in place of \|p\X\S$\6 +\&{for} $\|t\K\\{dependent}\mathrel{\&{to}}\\{proto\_dependent}$ \1\&{do}\6 +\&{begin} \37$\|r\K\\{max\_link}[\|t]$;\6 +\&{while} $\|r\I\\{null}$ \1\&{do}\6 +\&{begin} \37$\|q\K\\{info}(\|r)$;\6 +\&{if} $\|t=\\{dependent}$ \1\&{then}\C{for safety's sake, we change \|q to % +\\{proto\_dependent}}\6 +\&{begin} \37\&{if} $\\{cur\_exp}=\|q$ \1\&{then}\6 +\&{if} $\\{cur\_type}=\\{dependent}$ \1\&{then}\5 +$\\{cur\_type}\K\\{proto\_dependent}$;\2\2\6 +$\\{dep\_list}(\|q)\K\\{p\_over\_v}(\\{dep\_list}(\|q),\39\\{unity},\39% +\\{dependent},\39\\{proto\_dependent})$;\5 +$\\{type}(\|q)\K\\{proto\_dependent}$;\5 +$\\{value}(\|r)\K\\{round\_fraction}(\\{value}(\|r))$;\6 +\&{end};\2\6 +$\\{dep\_list}(\|q)\K\\{p\_plus\_fq}(\\{dep\_list}(\|q),\39\30\\{make\_scaled}(% +\\{value}(\|r),\39-\|v),\39\|s,\39\\{proto\_dependent},\39\\{proto% +\_dependent})$;\6 +\&{if} $\\{dep\_list}(\|q)=\\{dep\_final}$ \1\&{then}\5 +$\\{make\_known}(\|q,\39\\{dep\_final})$;\2\6 +$\|q\K\|r$;\5 +$\|r\K\\{link}(\|r)$;\5 +$\\{free\_node}(\|q,\39\\{dep\_node\_size})$;\6 +\&{end};\2\6 +\&{end}\2\par +\U815.\fi + +\M820. Here are some routines that provide handy combinations of actions +that are often needed during error recovery. For example, +`\\{flush\_error}' flushes the current expression, replaces it by +a given value, and calls \\{error}. + +Errors often are detected after an extra token has already been scanned. +The `\\{put\_get}' routines put that token back before calling \\{error}; +then they get it back again. (Or perhaps they get another token, if +the user has changed things.) + +\Y\P$\4\X808:Declare the procedure called \\{flush\_cur\_exp}\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{flush\_error}(\|v:\\{scaled})$;\ \2\6 +\&{begin} \37\\{error};\5 +$\\{flush\_cur\_exp}(\|v)$;\ \&{end};\7 +\4\&{procedure}\1\ \37\\{back\_error};\5 +\\{forward};\5 +\hbox{\2}\6 +\4\&{procedure}\1\ \37\\{get\_x\_next};\5 +\\{forward};\5 +\hbox{\2}\7 +\4\&{procedure}\1\ \37\\{put\_get\_error};\ \2\6 +\&{begin} \37\\{back\_error};\5 +\\{get\_x\_next};\ \&{end};\7 +\4\&{procedure}\1\ \37$\\{put\_get\_flush\_error}(\|v:\\{scaled})$;\ \2\6 +\&{begin} \37\\{put\_get\_error};\5 +$\\{flush\_cur\_exp}(\|v)$;\ \&{end};\par +\fi + +\M821. A global variable called \\{var\_flag} is set to a special command code +just before \MF\ calls \\{scan\_expression}, if the expression should be +treated as a variable when this command code immediately follows. For +example, \\{var\_flag} is set to \\{assignment} at the beginning of a +statement, because we want to know the {\sl location\/} of a variable at +the left of `\.{:=}', not the {\sl value\/} of that variable. + +The \\{scan\_expression} subroutine calls \\{scan\_tertiary}, +which calls \\{scan\_secondary}, which calls \\{scan\_primary}, which sets +$\\{var\_flag}\K0$. In this way each of the scanning routines ``knows'' +when it has been called with a special \\{var\_flag}, but \\{var\_flag} is +usually zero. + +A variable preceding a command that equals \\{var\_flag} is converted to a +token list rather than a value. Furthermore, an `\.{=}' sign following an +expression with $\\{var\_flag}=\\{assignment}$ is not considered to be a +relation +that produces boolean expressions. + + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{var\_flag}: \37$0\to\\{max\_command\_code}$;\C{command that wants a +variable}\par +\fi + +\M822. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{var\_flag}\K0$;\par +\fi + +\N823. \[40] Parsing primary expressions. +The first parsing routine, \\{scan\_primary}, is also the most complicated one, +since it involves so many different cases. But each case---with one +exception---is fairly simple by itself. + +When \\{scan\_primary} begins, the first token of the primary to be scanned +should already appear in \\{cur\_cmd}, \\{cur\_mod}, and \\{cur\_sym}. The +values +of \\{cur\_type} and \\{cur\_exp} should be either dead or dormant, as +explained +earlier. If \\{cur\_cmd} is not between \\{min\_primary\_command} and +\\{max\_primary\_command}, inclusive, a syntax error will be signalled. + +\Y\P$\4\X823:Declare the basic parsing subroutines\X\S$\6 +\4\&{procedure}\1\ \37\\{scan\_primary};\6 +\4\&{label} \37$\\{restart},\39\\{done},\39\\{done1},\39\\{done2}$;\6 +\4\&{var} \37$\|p,\39\|q,\39\|r$: \37\\{pointer};\C{for list manipulation}\6 +\|c: \37\\{quarterword};\C{a primitive operation code}\6 +\\{my\_var\_flag}: \37$0\to\\{max\_command\_code}$;\C{initial value of \\{my% +\_var\_flag}}\6 +$\\{l\_delim},\39\\{r\_delim}$: \37\\{pointer};\C{hash addresses of a delimiter +pair}\6 +\X831:Other local variables for \\{scan\_primary}\X\2\6 +\&{begin} \37$\\{my\_var\_flag}\K\\{var\_flag}$;\5 +$\\{var\_flag}\K0$;\6 +\4\\{restart}: \37\\{check\_arith};\5 +\X825:Supply diagnostic information, if requested\X;\6 +\&{case} $\\{cur\_cmd}$ \1\&{of}\6 +\4\\{left\_delimiter}: \37\X826:Scan a delimited primary\X;\6 +\4\\{begin\_group}: \37\X832:Scan a grouped primary\X;\6 +\4\\{string\_token}: \37\X833:Scan a string constant\X;\6 +\4\\{numeric\_token}: \37\X837:Scan a primary that starts with a numeric token% +\X;\6 +\4\\{nullary}: \37\X834:Scan a nullary operation\X;\6 +\4$\\{unary},\39\\{type\_name},\39\\{cycle},\39\\{plus\_or\_minus}$: \37% +\X835:Scan a unary operation\X;\6 +\4\\{primary\_binary}: \37\X839:Scan a binary operation with `\&{of}' between +its operands\X;\6 +\4\\{str\_op}: \37\X840:Convert a suffix to a string\X;\6 +\4\\{internal\_quantity}: \37\X841:Scan an internal numeric quantity\X;\6 +\4\\{capsule\_token}: \37$\\{make\_exp\_copy}(\\{cur\_mod})$;\6 +\4\\{tag\_token}: \37\X844:Scan a variable primary; \&{goto} \\{restart} if it +turns out to be a macro\X;\6 +\4\&{othercases} \37\&{begin} \37$\\{bad\_exp}(\.{"A\ primary"})$;\5 +\&{goto} \37\\{restart};\6 +\&{end}\2\6 +\&{endcases};\6 +\\{get\_x\_next};\C{the routines \&{goto} \\{done} if they don't want this}\6 +\4\\{done}: \37\&{if} $\\{cur\_cmd}=\\{left\_bracket}$ \1\&{then}\6 +\&{if} $\\{cur\_type}\G\\{known}$ \1\&{then}\5 +\X859:Scan a mediation construction\X;\2\2\6 +\&{end};\par +\As860, 862, 864, 868\ETs892. +\U1202.\fi + +\M824. Errors at the beginning of expressions are flagged by \\{bad\_exp}. + +\Y\P\4\&{procedure}\1\ \37$\\{bad\_exp}(\|s:\\{str\_number})$;\6 +\4\&{var} \37\\{save\_flag}: \37$0\to\\{max\_command\_code}$;\2\6 +\&{begin} \37$\\{print\_err}(\|s)$;\5 +$\\{print}(\.{"\ expression\ can\'t\ begin\ with\ \`"})$;\5 +$\\{print\_cmd\_mod}(\\{cur\_cmd},\39\\{cur\_mod})$;\5 +$\\{print\_char}(\.{"\'"})$;\5 +$\\{help4}(\.{"I\'m\ afraid\ I\ need\ some\ sort\ of\ value\ in\ order\ to\ +continue,"})$\6 +$(\.{"so\ I\'ve\ tentatively\ inserted\ \`0\'.\ You\ may\ want\ to"})$\6 +$(\.{"delete\ this\ zero\ and\ insert\ something\ else;"})$\6 +$(\.{"see\ Chapter\ 27\ of\ The\ METAFONTbook\ for\ an\ example."})$;\5 +\\{back\_input};\5 +$\\{cur\_sym}\K0$;\5 +$\\{cur\_cmd}\K\\{numeric\_token}$;\5 +$\\{cur\_mod}\K0$;\5 +\\{ins\_error};\6 +$\\{save\_flag}\K\\{var\_flag}$;\5 +$\\{var\_flag}\K0$;\5 +\\{get\_x\_next};\5 +$\\{var\_flag}\K\\{save\_flag}$;\6 +\&{end};\par +\fi + +\M825. \P$\X825:Supply diagnostic information, if requested\X\S$\6 +\&{debug} \37\&{if} $\\{panicking}$ \1\&{then}\5 +$\\{check\_mem}(\\{false})$;\ \2\6 +\&{gubed}\6 +\&{if} $\\{interrupt}\I0$ \1\&{then}\6 +\&{if} $\\{OK\_to\_interrupt}$ \1\&{then}\6 +\&{begin} \37\\{back\_input};\5 +\\{check\_interrupt};\5 +\\{get\_x\_next};\6 +\&{end}\2\2\par +\U823.\fi + +\M826. \P$\X826:Scan a delimited primary\X\S$\6 +\&{begin} \37$\\{l\_delim}\K\\{cur\_sym}$;\5 +$\\{r\_delim}\K\\{cur\_mod}$;\5 +\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $(\\{cur\_cmd}=\\{comma})\W(\\{cur\_type}\G\\{known})$ \1\&{then}\5 +\X830:Scan the second of a pair of numerics\X\6 +\4\&{else} $\\{check\_delimiter}(\\{l\_delim},\39\\{r\_delim})$;\2\6 +\&{end}\par +\U823.\fi + +\M827. The \\{stash\_in} subroutine puts the current (numeric) expression into +a field +within a ``big node.'' + +\Y\P\4\&{procedure}\1\ \37$\\{stash\_in}(\|p:\\{pointer})$;\6 +\4\&{var} \37\|q: \37\\{pointer};\C{temporary register}\2\6 +\&{begin} \37$\\{type}(\|p)\K\\{cur\_type}$;\6 +\&{if} $\\{cur\_type}=\\{known}$ \1\&{then}\5 +$\\{value}(\|p)\K\\{cur\_exp}$\6 +\4\&{else} \&{begin} \37\&{if} $\\{cur\_type}=\\{independent}$ \1\&{then}\5 +\X829:Stash an independent \\{cur\_exp} into a big node\X\6 +\4\&{else} \&{begin} \37$\\{mem}[\\{value\_loc}(\|p)]\K\\{mem}[\\{value\_loc}(% +\\{cur\_exp})]$;\C{$\\{dep\_list}(\|p)\K\\{dep\_list}(\\{cur\_exp})$ and $% +\\{prev\_dep}(\|p)\K\\{prev\_dep}(\\{cur\_exp})$}\6 +$\\{link}(\\{prev\_dep}(\|p))\K\|p$;\6 +\&{end};\2\6 +$\\{free\_node}(\\{cur\_exp},\39\\{value\_node\_size})$;\6 +\&{end};\2\6 +$\\{cur\_type}\K\\{vacuous}$;\6 +\&{end};\par +\fi + +\M828. In rare cases the current expression can become \\{independent}. There +may be many dependency lists pointing to such an independent capsule, +so we can't simply move it into place within a big node. Instead, +we copy it, then recycle it. + +\fi + +\M829. \P$\X829:Stash an independent \\{cur\_exp} into a big node\X\S$\6 +\&{begin} \37$\|q\K\\{single\_dependency}(\\{cur\_exp})$;\6 +\&{if} $\|q=\\{dep\_final}$ \1\&{then}\6 +\&{begin} \37$\\{type}(\|p)\K\\{known}$;\5 +$\\{value}(\|p)\K0$;\5 +$\\{free\_node}(\|q,\39\\{dep\_node\_size})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{type}(\|p)\K\\{dependent}$;\5 +$\\{new\_dep}(\|p,\39\|q)$;\6 +\&{end};\2\6 +$\\{recycle\_value}(\\{cur\_exp})$;\6 +\&{end}\par +\U827.\fi + +\M830. \P$\X830:Scan the second of a pair of numerics\X\S$\6 +\&{begin} \37$\|p\K\\{get\_node}(\\{value\_node\_size})$;\5 +$\\{type}(\|p)\K\\{pair\_type}$;\5 +$\\{name\_type}(\|p)\K\\{capsule}$;\5 +$\\{init\_big\_node}(\|p)$;\5 +$\|q\K\\{value}(\|p)$;\5 +$\\{stash\_in}(\\{x\_part\_loc}(\|q))$;\6 +\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_type}<\\{known}$ \1\&{then}\6 +\&{begin} \37$\\{exp\_err}(\.{"Nonnumeric\ ypart\ has\ been\ replaced\ by\ +0"})$;\5 +$\\{help4}(\.{"I\ thought\ you\ were\ giving\ me\ a\ pair\ \`(x,y)\';\ but"})$\6 +$(\.{"after\ finding\ a\ nice\ xpart\ \`x\'\ I\ found\ a\ ypart\ \`y\'"})$\6 +$(\.{"that\ isn\'t\ of\ numeric\ type.\ So\ I\'ve\ changed\ y\ to\ zero."})$\6 +$(\.{"(The\ y\ that\ I\ didn\'t\ like\ appears\ above\ the\ error\ +message.)"})$;\5 +$\\{put\_get\_flush\_error}(0)$;\6 +\&{end};\2\6 +$\\{stash\_in}(\\{y\_part\_loc}(\|q))$;\5 +$\\{check\_delimiter}(\\{l\_delim},\39\\{r\_delim})$;\5 +$\\{cur\_type}\K\\{pair\_type}$;\5 +$\\{cur\_exp}\K\|p$;\6 +\&{end}\par +\U826.\fi + +\M831. The local variable \\{group\_line} keeps track of the line +where a \&{begingroup} command occurred; this will be useful +in an error message if the group doesn't actually end. + +\Y\P$\4\X831:Other local variables for \\{scan\_primary}\X\S$\6 +\4\\{group\_line}: \37\\{integer};\C{where a group began}\par +\As836\ET843. +\U823.\fi + +\M832. \P$\X832:Scan a grouped primary\X\S$\6 +\&{begin} \37$\\{group\_line}\K\\{line}$;\6 +\&{if} $\\{internal}[\\{tracing\_commands}]>0$ \1\&{then}\5 +\\{show\_cur\_cmd\_mod};\2\6 +$\\{save\_boundary\_item}(\|p)$;\6 +\1\&{repeat} \37\\{do\_statement};\C{ends with $\\{cur\_cmd}\G\\{semicolon}$}\6 +\4\&{until}\5 +$\\{cur\_cmd}\I\\{semicolon}$;\2\6 +\&{if} $\\{cur\_cmd}\I\\{end\_group}$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"A\ group\ begun\ on\ line\ "})$;\5 +$\\{print\_int}(\\{group\_line})$;\5 +$\\{print}(\.{"\ never\ ended"})$;\5 +$\\{help2}(\.{"I\ saw\ a\ \`begingroup\'\ back\ there\ that\ hasn\'t\ been\ +matched"})$\6 +$(\.{"by\ \`endgroup\'.\ So\ I\'ve\ inserted\ \`endgroup\'\ now."})$;\5 +\\{back\_error};\5 +$\\{cur\_cmd}\K\\{end\_group}$;\6 +\&{end};\2\6 +\\{unsave};\C{this might change \\{cur\_type}, if independent variables are +recycled}\6 +\&{if} $\\{internal}[\\{tracing\_commands}]>0$ \1\&{then}\5 +\\{show\_cur\_cmd\_mod};\2\6 +\&{end}\par +\U823.\fi + +\M833. \P$\X833:Scan a string constant\X\S$\6 +\&{begin} \37$\\{cur\_type}\K\\{string\_type}$;\5 +$\\{cur\_exp}\K\\{cur\_mod}$;\6 +\&{end}\par +\U823.\fi + +\M834. Later we'll come to procedures that perform actual operations like +addition, square root, and so on; our purpose now is to do the parsing. +But we might as well mention those future procedures now, so that the +suspense won't be too bad: + +\smallskip +$\\{do\_nullary}(\|c)$ does primitive operations that have no operands (e.g., +`\&{true}' or `\&{pencircle}'); + +\smallskip +$\\{do\_unary}(\|c)$ applies a primitive operation to the current expression; + +\smallskip +$\\{do\_binary}(\|p,\|c)$ applies a primitive operation to the capsule~\|p +and the current expression. + +\Y\P$\4\X834:Scan a nullary operation\X\S$\6 +$\\{do\_nullary}(\\{cur\_mod})$\par +\U823.\fi + +\M835. \P$\X835:Scan a unary operation\X\S$\6 +\&{begin} \37$\|c\K\\{cur\_mod}$;\5 +\\{get\_x\_next};\5 +\\{scan\_primary};\5 +$\\{do\_unary}(\|c)$;\5 +\&{goto} \37\\{done};\6 +\&{end}\par +\U823.\fi + +\M836. A numeric token might be a primary by itself, or it might be the +numerator of a fraction composed solely of numeric tokens, or it might +multiply the primary that follows (provided that the primary doesn't begin +with a plus sign or a minus sign). The code here uses the facts that +$\\{max\_primary\_command}=\\{plus\_or\_minus}$ and +$\\{max\_primary\_command}-1=\\{numeric\_token}$. If a fraction is found that +is less +than unity, we try to retain higher precision when we use it in scalar +multiplication. + +\Y\P$\4\X831:Other local variables for \\{scan\_primary}\X\mathrel{+}\S$\6 +\4$\\{num},\39\\{denom}$: \37\\{scaled};\C{for primaries that are fractions, +like `1/2'}\par +\fi + +\M837. \P$\X837:Scan a primary that starts with a numeric token\X\S$\6 +\&{begin} \37$\\{cur\_exp}\K\\{cur\_mod}$;\5 +$\\{cur\_type}\K\\{known}$;\5 +\\{get\_x\_next};\6 +\&{if} $\\{cur\_cmd}\I\\{slash}$ \1\&{then}\6 +\&{begin} \37$\\{num}\K0$;\5 +$\\{denom}\K0$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37\\{get\_x\_next};\6 +\&{if} $\\{cur\_cmd}\I\\{numeric\_token}$ \1\&{then}\6 +\&{begin} \37\\{back\_input};\5 +$\\{cur\_cmd}\K\\{slash}$;\5 +$\\{cur\_mod}\K\\{over}$;\5 +$\\{cur\_sym}\K\\{frozen\_slash}$;\5 +\&{goto} \37\\{done};\6 +\&{end};\2\6 +$\\{num}\K\\{cur\_exp}$;\5 +$\\{denom}\K\\{cur\_mod}$;\6 +\&{if} $\\{denom}=0$ \1\&{then}\5 +\X838:Protest division by zero\X\6 +\4\&{else} $\\{cur\_exp}\K\\{make\_scaled}(\\{num},\39\\{denom})$;\2\6 +\\{check\_arith};\5 +\\{get\_x\_next};\6 +\&{end};\2\6 +\&{if} $\\{cur\_cmd}\G\\{min\_primary\_command}$ \1\&{then}\6 +\&{if} $\\{cur\_cmd}<\\{numeric\_token}$ \1\&{then}\C{in particular, $\\{cur% +\_cmd}\I\\{plus\_or\_minus}$}\6 +\&{begin} \37$\|p\K\\{stash\_cur\_exp}$;\5 +\\{scan\_primary};\6 +\&{if} $(\\{abs}(\\{num})\G\\{abs}(\\{denom}))\V(\\{cur\_type}<\\{pair\_type})$ +\1\&{then}\5 +$\\{do\_binary}(\|p,\39\\{times})$\6 +\4\&{else} \&{begin} \37$\\{frac\_mult}(\\{num},\39\\{denom})$;\5 +$\\{free\_node}(\|p,\39\\{value\_node\_size})$;\6 +\&{end};\2\6 +\&{end};\2\2\6 +\&{goto} \37\\{done};\6 +\&{end}\par +\U823.\fi + +\M838. \P$\X838:Protest division by zero\X\S$\6 +\&{begin} \37$\\{print\_err}(\.{"Division\ by\ zero"})$;\5 +$\\{help1}(\.{"I\'ll\ pretend\ that\ you\ meant\ to\ divide\ by\ 1."})$;\5 +\\{error};\6 +\&{end}\par +\U837.\fi + +\M839. \P$\X839:Scan a binary operation with `\&{of}' between its operands\X\S$% +\6 +\&{begin} \37$\|c\K\\{cur\_mod}$;\5 +\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_cmd}\I\\{of\_token}$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\.{"of"})$;\5 +$\\{print}(\.{"\ for\ "})$;\5 +$\\{print\_cmd\_mod}(\\{primary\_binary},\39\|c)$;\5 +$\\{help1}(\.{"I\'ve\ got\ the\ first\ argument;\ will\ look\ now\ for\ the\ +other."})$;\5 +\\{back\_error};\6 +\&{end};\2\6 +$\|p\K\\{stash\_cur\_exp}$;\5 +\\{get\_x\_next};\5 +\\{scan\_primary};\5 +$\\{do\_binary}(\|p,\39\|c)$;\5 +\&{goto} \37\\{done};\6 +\&{end}\par +\U823.\fi + +\M840. \P$\X840:Convert a suffix to a string\X\S$\6 +\&{begin} \37\\{get\_x\_next};\5 +\\{scan\_suffix};\5 +$\\{old\_setting}\K\\{selector}$;\5 +$\\{selector}\K\\{new\_string}$;\5 +$\\{show\_token\_list}(\\{cur\_exp},\39\\{null},\39100000,\390)$;\5 +$\\{flush\_token\_list}(\\{cur\_exp})$;\5 +$\\{cur\_exp}\K\\{make\_string}$;\5 +$\\{selector}\K\\{old\_setting}$;\5 +$\\{cur\_type}\K\\{string\_type}$;\5 +\&{goto} \37\\{done};\6 +\&{end}\par +\U823.\fi + +\M841. If an internal quantity appears all by itself on the left of an +assignment, we return a token list of length one, containing the address +of the internal quantity plus \\{hash\_end}. (This accords with the conventions +of the save stack, as described earlier.) + +\Y\P$\4\X841:Scan an internal numeric quantity\X\S$\6 +\&{begin} \37$\|q\K\\{cur\_mod}$;\6 +\&{if} $\\{my\_var\_flag}=\\{assignment}$ \1\&{then}\6 +\&{begin} \37\\{get\_x\_next};\6 +\&{if} $\\{cur\_cmd}=\\{assignment}$ \1\&{then}\6 +\&{begin} \37$\\{cur\_exp}\K\\{get\_avail}$;\5 +$\\{info}(\\{cur\_exp})\K\|q+\\{hash\_end}$;\5 +$\\{cur\_type}\K\\{token\_list}$;\5 +\&{goto} \37\\{done};\6 +\&{end};\2\6 +\\{back\_input};\6 +\&{end};\2\6 +$\\{cur\_type}\K\\{known}$;\5 +$\\{cur\_exp}\K\\{internal}[\|q]$;\6 +\&{end}\par +\U823.\fi + +\M842. The most difficult part of \\{scan\_primary} has been saved for last, +since +it was necessary to build up some confidence first. We can now face the task +of scanning a variable. + +As we scan a variable, we build a token list containing the relevant +names and subscript values, simultaneously following along in the +``collective'' structure to see if we are actually dealing with a macro +instead of a value. + +The local variables \\{pre\_head} and \\{post\_head} will point to the +beginning +of the prefix and suffix lists; \\{tail} will point to the end of the list +that is currently growing. + +Another local variable, \\{tt}, contains partial information about the +declared type of the variable-so-far. If $\\{tt}\G\\{unsuffixed\_macro}$, the +relation $\\{tt}=\\{type}(\|q)$ will always hold. If $\\{tt}=\\{undefined}$, +the routine +doesn't bother to update its information about type. And if +$\\{undefined}<\\{tt}<\\{unsuffixed\_macro}$, the precise value of \\{tt} isn't +critical. + +\fi + +\M843. \P$\X831:Other local variables for \\{scan\_primary}\X\mathrel{+}\S$\6 +\4$\\{pre\_head},\39\\{post\_head},\39\\{tail}$: \37\\{pointer};\C{prefix and +suffix list variables}\6 +\4\\{tt}: \37\\{small\_number};\C{approximation to the type of the +variable-so-far}\6 +\4\|t: \37\\{pointer};\C{a token}\6 +\4\\{macro\_ref}: \37\\{pointer};\C{reference count for a suffixed macro}\par +\fi + +\M844. \P$\X844:Scan a variable primary; \&{goto} \\{restart} if it turns out +to be a macro\X\S$\6 +\&{begin} \37$\\{fast\_get\_avail}(\\{pre\_head})$;\5 +$\\{tail}\K\\{pre\_head}$;\5 +$\\{post\_head}\K\\{null}$;\5 +$\\{tt}\K\\{vacuous}$;\6 +\~ \1\&{loop}\ \&{begin} \37$\|t\K\\{cur\_tok}$;\5 +$\\{link}(\\{tail})\K\|t$;\6 +\&{if} $\\{tt}\I\\{undefined}$ \1\&{then}\6 +\&{begin} \37\X850:Find the approximate type \\{tt} and corresponding~\|q\X;\6 +\&{if} $\\{tt}\G\\{unsuffixed\_macro}$ \1\&{then}\5 +\X845:Either begin an unsuffixed macro call or prepare for a suffixed one\X;\2\6 +\&{end};\2\6 +\\{get\_x\_next};\5 +$\\{tail}\K\|t$;\6 +\&{if} $\\{cur\_cmd}=\\{left\_bracket}$ \1\&{then}\5 +\X846:Scan for a subscript; replace \\{cur\_cmd} by \\{numeric\_token} if found% +\X;\2\6 +\&{if} $\\{cur\_cmd}>\\{max\_suffix\_token}$ \1\&{then}\5 +\&{goto} \37\\{done1};\2\6 +\&{if} $\\{cur\_cmd}<\\{min\_suffix\_token}$ \1\&{then}\5 +\&{goto} \37\\{done1};\2\6 +\&{end};\C{now \\{cur\_cmd} is \\{internal\_quantity}, \\{tag\_token}, or % +\\{numeric\_token}}\2\6 +\4\\{done1}: \37\X852:Handle unusual cases that masquerade as variables, and % +\&{goto} \\{restart} or \&{goto} \\{done} if appropriate; otherwise make a copy +of the variable and \&{goto} \\{done}\X;\6 +\&{end}\par +\U823.\fi + +\M845. \P$\X845:Either begin an unsuffixed macro call or prepare for a suffixed +one\X\S$\6 +\&{begin} \37$\\{link}(\\{tail})\K\\{null}$;\6 +\&{if} $\\{tt}>\\{unsuffixed\_macro}$ \1\&{then}\C{$\\{tt}=\\{suffixed% +\_macro}$}\6 +\&{begin} \37$\\{post\_head}\K\\{get\_avail}$;\5 +$\\{tail}\K\\{post\_head}$;\5 +$\\{link}(\\{tail})\K\|t$;\6 +$\\{tt}\K\\{undefined}$;\5 +$\\{macro\_ref}\K\\{value}(\|q)$;\5 +$\\{add\_mac\_ref}(\\{macro\_ref})$;\6 +\&{end}\6 +\4\&{else} \X853:Set up unsuffixed macro call and \&{goto} \\{restart}\X;\2\6 +\&{end}\par +\U844.\fi + +\M846. \P$\X846:Scan for a subscript; replace \\{cur\_cmd} by \\{numeric% +\_token} if found\X\S$\6 +\&{begin} \37\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_cmd}\I\\{right\_bracket}$ \1\&{then}\5 +\X847:Put the left bracket and the expression back to be rescanned\X\6 +\4\&{else} \&{begin} \37\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\5 +\\{bad\_subscript};\2\6 +$\\{cur\_cmd}\K\\{numeric\_token}$;\5 +$\\{cur\_mod}\K\\{cur\_exp}$;\5 +$\\{cur\_sym}\K0$;\6 +\&{end};\2\6 +\&{end}\par +\U844.\fi + +\M847. The left bracket that we thought was introducing a subscript might have +actually been the left bracket in a mediation construction like `\.{x[a,b]}'. +So we don't issue an error message at this point; but we do want to back up +so as to avoid any embarrassment about our incorrect assumption. + +\Y\P$\4\X847:Put the left bracket and the expression back to be rescanned\X\S$\6 +\&{begin} \37\\{back\_input};\C{that was the token following the current +expression}\6 +\\{back\_expr};\5 +$\\{cur\_cmd}\K\\{left\_bracket}$;\5 +$\\{cur\_mod}\K0$;\5 +$\\{cur\_sym}\K\\{frozen\_left\_bracket}$;\6 +\&{end}\par +\Us846\ET859.\fi + +\M848. Here's a routine that puts the current expression back to be read again. + +\Y\P\4\&{procedure}\1\ \37\\{back\_expr};\6 +\4\&{var} \37\|p: \37\\{pointer};\C{capsule token}\2\6 +\&{begin} \37$\|p\K\\{stash\_cur\_exp}$;\5 +$\\{link}(\|p)\K\\{null}$;\5 +$\\{back\_list}(\|p)$;\6 +\&{end};\par +\fi + +\M849. Unknown subscripts lead to the following error message. + +\Y\P\4\&{procedure}\1\ \37\\{bad\_subscript};\2\6 +\&{begin} \37$\\{exp\_err}(\.{"Improper\ subscript\ has\ been\ replaced\ by\ +zero"})$;\5 +$\\{help3}(\.{"A\ bracketed\ subscript\ must\ have\ a\ known\ numeric\ +value;"})$\6 +$(\.{"unfortunately,\ what\ I\ found\ was\ the\ value\ that\ appears\ just"})$\6 +$(\.{"above\ this\ error\ message.\ So\ I\'ll\ try\ a\ zero\ subscript."})$;\5 +$\\{flush\_error}(0)$;\6 +\&{end};\par +\fi + +\M850. Every time we call \\{get\_x\_next}, there's a chance that the variable +we've +been looking at will disappear. Thus, we cannot safely keep \|q pointing +into the variable structure; we need to start searching from the root each +time. + +\Y\P$\4\X850:Find the approximate type \\{tt} and corresponding~\|q\X\S$\6 +\&{begin} \37$\|p\K\\{link}(\\{pre\_head})$;\5 +$\|q\K\\{info}(\|p)$;\5 +$\\{tt}\K\\{undefined}$;\6 +\&{if} $\\{eq\_type}(\|q)\mathbin{\&{mod}}\\{outer\_tag}=\\{tag\_token}$ \1% +\&{then}\6 +\&{begin} \37$\|q\K\\{equiv}(\|q)$;\6 +\&{if} $\|q=\\{null}$ \1\&{then}\5 +\&{goto} \37\\{done2};\2\6 +\~ \1\&{loop}\ \&{begin} \37$\|p\K\\{link}(\|p)$;\6 +\&{if} $\|p=\\{null}$ \1\&{then}\6 +\&{begin} \37$\\{tt}\K\\{type}(\|q)$;\5 +\&{goto} \37\\{done2};\6 +\&{end};\2\6 +\&{if} $\\{type}(\|q)\I\\{structured}$ \1\&{then}\5 +\&{goto} \37\\{done2};\2\6 +$\|q\K\\{link}(\\{attr\_head}(\|q))$;\C{the \\{collective\_subscript} +attribute}\6 +\&{if} $\|p\G\\{hi\_mem\_min}$ \1\&{then}\C{it's not a subscript}\6 +\&{begin} \37\1\&{repeat} \37$\|q\K\\{link}(\|q)$;\6 +\4\&{until}\5 +$\\{attr\_loc}(\|q)\G\\{info}(\|p)$;\2\6 +\&{if} $\\{attr\_loc}(\|q)>\\{info}(\|p)$ \1\&{then}\5 +\&{goto} \37\\{done2};\2\6 +\&{end};\2\6 +\&{end};\2\6 +\&{end};\2\6 +\4\\{done2}: \37\&{end}\par +\U844.\fi + +\M851. How do things stand now? Well, we have scanned an entire variable name, +including possible subscripts and/or attributes; \\{cur\_cmd}, \\{cur\_mod}, +and +\\{cur\_sym} represent the token that follows. If $\\{post\_head}=\\{null}$, a +token list for this variable name starts at $\\{link}(\\{pre\_head})$, with all +subscripts evaluated. But if $\\{post\_head}\I\\{null}$, the variable turned +out +to be a suffixed macro; \\{pre\_head} is the head of the prefix list, while +\\{post\_head} is the head of a token list containing both `\.{\AT!}' and +the suffix. + +Our immediate problem is to see if this variable still exists. (Variable +structures can change drastically whenever we call \\{get\_x\_next}; users +aren't supposed to do this, but the fact that it is possible means that +we must be cautious.) + +The following procedure prints an error message when a variable +unexpectedly disappears. Its help message isn't quite right for +our present purposes, but we'll be able to fix that up. + +\Y\P\4\&{procedure}\1\ \37$\\{obliterated}(\|q:\\{pointer})$;\2\6 +\&{begin} \37$\\{print\_err}(\.{"Variable\ "})$;\5 +$\\{show\_token\_list}(\|q,\39\\{null},\391000,\390)$;\5 +$\\{print}(\.{"\ has\ been\ obliterated"})$;\5 +$\\{help5}(\.{"It\ seems\ you\ did\ a\ nasty\ thing---probably\ by\ +accident,"})$\6 +$(\.{"but\ nevertheless\ you\ nearly\ hornswoggled\ me..."})$\6 +$(\.{"While\ I\ was\ evaluating\ the\ right-hand\ side\ of\ this"})$\6 +$(\.{"command,\ something\ happened,\ and\ the\ left-hand\ side"})$\6 +$(\.{"is\ no\ longer\ a\ variable!\ So\ I\ won\'t\ change\ anything."})$;\6 +\&{end};\par +\fi + +\M852. If the variable does exist, we also need to check +for a few other special cases before deciding that a plain old ordinary +variable has, indeed, been scanned. + +\Y\P$\4\X852:Handle unusual cases that masquerade as variables, and \&{goto} % +\\{restart} or \&{goto} \\{done} if appropriate; otherwise make a copy of the +variable and \&{goto} \\{done}\X\S$\6 +\&{if} $\\{post\_head}\I\\{null}$ \1\&{then}\5 +\X854:Set up suffixed macro call and \&{goto} \\{restart}\X;\2\6 +$\|q\K\\{link}(\\{pre\_head})$;\5 +$\\{free\_avail}(\\{pre\_head})$;\6 +\&{if} $\\{cur\_cmd}=\\{my\_var\_flag}$ \1\&{then}\6 +\&{begin} \37$\\{cur\_type}\K\\{token\_list}$;\5 +$\\{cur\_exp}\K\|q$;\5 +\&{goto} \37\\{done};\6 +\&{end};\2\6 +$\|p\K\\{find\_variable}(\|q)$;\6 +\&{if} $\|p\I\\{null}$ \1\&{then}\5 +$\\{make\_exp\_copy}(\|p)$\6 +\4\&{else} \&{begin} \37$\\{obliterated}(\|q)$;\6 +$\\{help\_line}[2]\K\.{"While\ I\ was\ evaluating\ the\ suffix\ of\ this\ +variable,"}$;\5 +$\\{help\_line}[1]\K\.{"something\ was\ redefined,\ and\ it\'s\ no\ longer\ a\ +variable!"}$;\5 +$\\{help\_line}[0]\K\.{"In\ order\ to\ get\ back\ on\ my\ feet,\ I\'ve\ +inserted\ \`0\'\ instead."}$;\5 +$\\{put\_get\_flush\_error}(0)$;\6 +\&{end};\2\6 +$\\{flush\_node\_list}(\|q)$;\5 +\&{goto} \37\\{done}\par +\U844.\fi + +\M853. The only complication associated with macro calling is that the prefix +and ``at'' parameters must be packaged in an appropriate list of lists. + +\Y\P$\4\X853:Set up unsuffixed macro call and \&{goto} \\{restart}\X\S$\6 +\&{begin} \37$\|p\K\\{get\_avail}$;\5 +$\\{info}(\\{pre\_head})\K\\{link}(\\{pre\_head})$;\5 +$\\{link}(\\{pre\_head})\K\|p$;\5 +$\\{info}(\|p)\K\|t$;\5 +$\\{macro\_call}(\\{value}(\|q),\39\\{pre\_head},\39\\{null})$;\5 +\\{get\_x\_next};\5 +\&{goto} \37\\{restart};\6 +\&{end}\par +\U845.\fi + +\M854. If the ``variable'' that turned out to be a suffixed macro no longer +exists, +we don't care, because we have reserved a pointer (\\{macro\_ref}) to its +token list. + +\Y\P$\4\X854:Set up suffixed macro call and \&{goto} \\{restart}\X\S$\6 +\&{begin} \37\\{back\_input};\5 +$\|p\K\\{get\_avail}$;\5 +$\|q\K\\{link}(\\{post\_head})$;\5 +$\\{info}(\\{pre\_head})\K\\{link}(\\{pre\_head})$;\5 +$\\{link}(\\{pre\_head})\K\\{post\_head}$;\5 +$\\{info}(\\{post\_head})\K\|q$;\5 +$\\{link}(\\{post\_head})\K\|p$;\5 +$\\{info}(\|p)\K\\{link}(\|q)$;\5 +$\\{link}(\|q)\K\\{null}$;\5 +$\\{macro\_call}(\\{macro\_ref},\39\\{pre\_head},\39\\{null})$;\5 +$\\{decr}(\\{ref\_count}(\\{macro\_ref}))$;\5 +\\{get\_x\_next};\5 +\&{goto} \37\\{restart};\6 +\&{end}\par +\U852.\fi + +\M855. Our remaining job is simply to make a copy of the value that has been +found. Some cases are harder than others, but complexity arises solely +because of the multiplicity of possible cases. + +\Y\P$\4\X855:Declare the procedure called \\{make\_exp\_copy}\X\S$\6 +\hbox{\4}\X856:Declare subroutines needed by \\{make\_exp\_copy}\X\6 +\4\&{procedure}\1\ \37$\\{make\_exp\_copy}(\|p:\\{pointer})$;\6 +\4\&{label} \37\\{restart};\6 +\4\&{var} \37$\|q,\39\|r,\39\|t$: \37\\{pointer};\C{registers for list +manipulation}\2\6 +\&{begin} \37\\{restart}: \37$\\{cur\_type}\K\\{type}(\|p)$;\6 +\&{case} $\\{cur\_type}$ \1\&{of}\6 +\4$\\{vacuous},\39\\{boolean\_type},\39\\{known}$: \37$\\{cur\_exp}\K\\{value}(% +\|p)$;\6 +\4\\{unknown\_types}: \37$\\{cur\_exp}\K\\{new\_ring\_entry}(\|p)$;\6 +\4\\{string\_type}: \37\&{begin} \37$\\{cur\_exp}\K\\{value}(\|p)$;\5 +$\\{add\_str\_ref}(\\{cur\_exp})$;\6 +\&{end};\6 +\4\\{pen\_type}: \37\&{begin} \37$\\{cur\_exp}\K\\{value}(\|p)$;\5 +$\\{add\_pen\_ref}(\\{cur\_exp})$;\6 +\&{end};\6 +\4\\{picture\_type}: \37$\\{cur\_exp}\K\\{copy\_edges}(\\{value}(\|p))$;\6 +\4$\\{path\_type},\39\\{future\_pen}$: \37$\\{cur\_exp}\K\\{copy\_path}(% +\\{value}(\|p))$;\6 +\4$\\{transform\_type},\39\\{pair\_type}$: \37\X857:Copy the big node \|p\X;\6 +\4$\\{dependent},\39\\{proto\_dependent}$: \37$\\{encapsulate}(\\{copy\_dep% +\_list}(\\{dep\_list}(\|p)))$;\6 +\4\\{numeric\_type}: \37\&{begin} \37$\\{new\_indep}(\|p)$;\5 +\&{goto} \37\\{restart};\6 +\&{end};\6 +\4\\{independent}: \37\&{begin} \37$\|q\K\\{single\_dependency}(\|p)$;\6 +\&{if} $\|q=\\{dep\_final}$ \1\&{then}\6 +\&{begin} \37$\\{cur\_type}\K\\{known}$;\5 +$\\{cur\_exp}\K0$;\5 +$\\{free\_node}(\|q,\39\\{value\_node\_size})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{cur\_type}\K\\{dependent}$;\5 +$\\{encapsulate}(\|q)$;\6 +\&{end};\2\6 +\&{end};\6 +\4\&{othercases} \37$\\{confusion}(\.{"copy"})$\2\6 +\&{endcases};\6 +\&{end};\par +\U651.\fi + +\M856. The \\{encapsulate} subroutine assumes that \\{dep\_final} is the +tail of dependency list~\|p. + +\Y\P$\4\X856:Declare subroutines needed by \\{make\_exp\_copy}\X\S$\6 +\4\&{procedure}\1\ \37$\\{encapsulate}(\|p:\\{pointer})$;\2\6 +\&{begin} \37$\\{cur\_exp}\K\\{get\_node}(\\{value\_node\_size})$;\5 +$\\{type}(\\{cur\_exp})\K\\{cur\_type}$;\5 +$\\{name\_type}(\\{cur\_exp})\K\\{capsule}$;\5 +$\\{new\_dep}(\\{cur\_exp},\39\|p)$;\6 +\&{end};\par +\A858. +\U855.\fi + +\M857. The most tedious case arises when the user refers to a +\&{pair} or \&{transform} variable; we must copy several fields, +each of which can be \\{independent}, \\{dependent}, \\{proto\_dependent}, +or \\{known}. + +\Y\P$\4\X857:Copy the big node \|p\X\S$\6 +\&{begin} \37\&{if} $\\{value}(\|p)=\\{null}$ \1\&{then}\5 +$\\{init\_big\_node}(\|p)$;\2\6 +$\|t\K\\{get\_node}(\\{value\_node\_size})$;\5 +$\\{name\_type}(\|t)\K\\{capsule}$;\5 +$\\{type}(\|t)\K\\{cur\_type}$;\5 +$\\{init\_big\_node}(\|t)$;\6 +$\|q\K\\{value}(\|p)+\\{big\_node\_size}[\\{cur\_type}]$;\5 +$\|r\K\\{value}(\|t)+\\{big\_node\_size}[\\{cur\_type}]$;\6 +\1\&{repeat} \37$\|q\K\|q-2$;\5 +$\|r\K\|r-2$;\5 +$\\{install}(\|r,\39\|q)$;\6 +\4\&{until}\5 +$\|q=\\{value}(\|p)$;\2\6 +$\\{cur\_exp}\K\|t$;\6 +\&{end}\par +\U855.\fi + +\M858. The \\{install} procedure copies a numeric field~\|q into field~\|r of +a big node that will be part of a capsule. + +\Y\P$\4\X856:Declare subroutines needed by \\{make\_exp\_copy}\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{install}(\|r,\39\|q:\\{pointer})$;\6 +\4\&{var} \37\|p: \37\\{pointer};\C{temporary register}\2\6 +\&{begin} \37\&{if} $\\{type}(\|q)=\\{known}$ \1\&{then}\6 +\&{begin} \37$\\{value}(\|r)\K\\{value}(\|q)$;\5 +$\\{type}(\|r)\K\\{known}$;\6 +\&{end}\6 +\4\&{else} \&{if} $\\{type}(\|q)=\\{independent}$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{single\_dependency}(\|q)$;\6 +\&{if} $\|p=\\{dep\_final}$ \1\&{then}\6 +\&{begin} \37$\\{type}(\|r)\K\\{known}$;\5 +$\\{value}(\|r)\K0$;\5 +$\\{free\_node}(\|p,\39\\{value\_node\_size})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{type}(\|r)\K\\{dependent}$;\5 +$\\{new\_dep}(\|r,\39\|p)$;\6 +\&{end};\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{type}(\|r)\K\\{type}(\|q)$;\5 +$\\{new\_dep}(\|r,\39\\{copy\_dep\_list}(\\{dep\_list}(\|q)))$;\6 +\&{end};\2\2\6 +\&{end};\par +\fi + +\M859. Expressions of the form `\.{a[b,c]}' are converted into +`\.{b+a*(c-b)}', without checking the types of \.b~or~\.c, +provided that \.a is numeric. + +\Y\P$\4\X859:Scan a mediation construction\X\S$\6 +\&{begin} \37$\|p\K\\{stash\_cur\_exp}$;\5 +\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_cmd}\I\\{comma}$ \1\&{then}\6 +\&{begin} \37\X847:Put the left bracket and the expression back to be rescanned% +\X;\6 +$\\{unstash\_cur\_exp}(\|p)$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|q\K\\{stash\_cur\_exp}$;\5 +\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_cmd}\I\\{right\_bracket}$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\.{"]"})$;\6 +$\\{help3}(\.{"I\'ve\ scanned\ an\ expression\ of\ the\ form\ \`a[b,c\',"})$\6 +$(\.{"so\ a\ right\ bracket\ should\ have\ come\ next."})$\6 +$(\.{"I\ shall\ pretend\ that\ one\ was\ there."})$;\6 +\\{back\_error};\6 +\&{end};\2\6 +$\|r\K\\{stash\_cur\_exp}$;\5 +$\\{make\_exp\_copy}(\|q)$;\6 +$\\{do\_binary}(\|r,\39\\{minus})$;\5 +$\\{do\_binary}(\|p,\39\\{times})$;\5 +$\\{do\_binary}(\|q,\39\\{plus})$;\5 +\\{get\_x\_next};\6 +\&{end};\2\6 +\&{end}\par +\U823.\fi + +\M860. Here is a comparatively simple routine that is used to scan the +\&{suffix} parameters of a macro. + +\Y\P$\4\X823:Declare the basic parsing subroutines\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{scan\_suffix};\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37$\|h,\39\|t$: \37\\{pointer};\C{head and tail of the list being +built}\6 +\|p: \37\\{pointer};\C{temporary register}\2\6 +\&{begin} \37$\|h\K\\{get\_avail}$;\5 +$\|t\K\|h$;\6 +\~ \1\&{loop}\ \&{begin} \37\&{if} $\\{cur\_cmd}=\\{left\_bracket}$ \1\&{then}\5 +\X861:Scan a bracketed subscript and set $\\{cur\_cmd}\K\\{numeric\_token}$\X;% +\2\6 +\&{if} $\\{cur\_cmd}=\\{numeric\_token}$ \1\&{then}\5 +$\|p\K\\{new\_num\_tok}(\\{cur\_mod})$\6 +\4\&{else} \&{if} $(\\{cur\_cmd}=\\{tag\_token})\V(\\{cur\_cmd}=\\{internal% +\_quantity})$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{get\_avail}$;\5 +$\\{info}(\|p)\K\\{cur\_sym}$;\6 +\&{end}\6 +\4\&{else} \&{goto} \37\\{done};\2\2\6 +$\\{link}(\|t)\K\|p$;\5 +$\|t\K\|p$;\5 +\\{get\_x\_next};\6 +\&{end};\2\6 +\4\\{done}: \37$\\{cur\_exp}\K\\{link}(\|h)$;\5 +$\\{free\_avail}(\|h)$;\5 +$\\{cur\_type}\K\\{token\_list}$;\6 +\&{end};\par +\fi + +\M861. \P$\X861:Scan a bracketed subscript and set $\\{cur\_cmd}\K\\{numeric% +\_token}$\X\S$\6 +\&{begin} \37\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\5 +\\{bad\_subscript};\2\6 +\&{if} $\\{cur\_cmd}\I\\{right\_bracket}$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\.{"]"})$;\6 +$\\{help3}(\.{"I\'ve\ seen\ a\ \`[\'\ and\ a\ subscript\ value,\ in\ a\ +suffix,"})$\6 +$(\.{"so\ a\ right\ bracket\ should\ have\ come\ next."})$\6 +$(\.{"I\ shall\ pretend\ that\ one\ was\ there."})$;\6 +\\{back\_error};\6 +\&{end};\2\6 +$\\{cur\_cmd}\K\\{numeric\_token}$;\5 +$\\{cur\_mod}\K\\{cur\_exp}$;\6 +\&{end}\par +\U860.\fi + +\N862. \[41] Parsing secondary and higher expressions. +After the intricacies of \\{scan\_primary}\kern-1pt, +the \\{scan\_secondary} routine is +refreshingly simple. It's not trivial, but the operations are relatively +straightforward; the main difficulty is, again, that expressions and data +structures might change drastically every time we call \\{get\_x\_next}, so a +cautious approach is mandatory. For example, a macro defined by +\&{primarydef} might have disappeared by the time its second argument has +been scanned; we solve this by increasing the reference count of its token +list, so that the macro can be called even after it has been clobbered. + +\Y\P$\4\X823:Declare the basic parsing subroutines\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{scan\_secondary};\6 +\4\&{label} \37$\\{restart},\39\\{continue}$;\6 +\4\&{var} \37\|p: \37\\{pointer};\C{for list manipulation}\6 +$\|c,\39\|d$: \37\\{halfword};\C{operation codes or modifiers}\6 +\\{mac\_name}: \37\\{pointer};\C{token defined with \&{primarydef}}\2\6 +\&{begin} \37\\{restart}: \37\&{if} $(\\{cur\_cmd}<\\{min\_primary\_command})\V% +\30(\\{cur\_cmd}>\\{max\_primary\_command})$ \1\&{then}\5 +$\\{bad\_exp}(\.{"A\ secondary"})$;\2\6 +\\{scan\_primary};\6 +\4\\{continue}: \37\&{if} $\\{cur\_cmd}\L\\{max\_secondary\_command}$ \1% +\&{then}\6 +\&{if} $\\{cur\_cmd}\G\\{min\_secondary\_command}$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{stash\_cur\_exp}$;\5 +$\|c\K\\{cur\_mod}$;\5 +$\|d\K\\{cur\_cmd}$;\6 +\&{if} $\|d=\\{secondary\_primary\_macro}$ \1\&{then}\6 +\&{begin} \37$\\{mac\_name}\K\\{cur\_sym}$;\5 +$\\{add\_mac\_ref}(\|c)$;\6 +\&{end};\2\6 +\\{get\_x\_next};\5 +\\{scan\_primary};\6 +\&{if} $\|d\I\\{secondary\_primary\_macro}$ \1\&{then}\5 +$\\{do\_binary}(\|p,\39\|c)$\6 +\4\&{else} \&{begin} \37\\{back\_input};\5 +$\\{binary\_mac}(\|p,\39\|c,\39\\{mac\_name})$;\5 +$\\{decr}(\\{ref\_count}(\|c))$;\5 +\\{get\_x\_next};\5 +\&{goto} \37\\{restart};\6 +\&{end};\2\6 +\&{goto} \37\\{continue};\6 +\&{end};\2\2\6 +\&{end};\par +\fi + +\M863. The following procedure calls a macro that has two parameters, +\|p and \\{cur\_exp}. + +\Y\P\4\&{procedure}\1\ \37$\\{binary\_mac}(\|p,\39\|c,\39\|n:\\{pointer})$;\6 +\4\&{var} \37$\|q,\39\|r$: \37\\{pointer};\C{nodes in the parameter list}\2\6 +\&{begin} \37$\|q\K\\{get\_avail}$;\5 +$\|r\K\\{get\_avail}$;\5 +$\\{link}(\|q)\K\|r$;\6 +$\\{info}(\|q)\K\|p$;\5 +$\\{info}(\|r)\K\\{stash\_cur\_exp}$;\6 +$\\{macro\_call}(\|c,\39\|q,\39\|n)$;\6 +\&{end};\par +\fi + +\M864. The next procedure, \\{scan\_tertiary}, is pretty much the same deal. + +\Y\P$\4\X823:Declare the basic parsing subroutines\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{scan\_tertiary};\6 +\4\&{label} \37$\\{restart},\39\\{continue}$;\6 +\4\&{var} \37\|p: \37\\{pointer};\C{for list manipulation}\6 +$\|c,\39\|d$: \37\\{halfword};\C{operation codes or modifiers}\6 +\\{mac\_name}: \37\\{pointer};\C{token defined with \&{secondarydef}}\2\6 +\&{begin} \37\\{restart}: \37\&{if} $(\\{cur\_cmd}<\\{min\_primary\_command})\V% +\30(\\{cur\_cmd}>\\{max\_primary\_command})$ \1\&{then}\5 +$\\{bad\_exp}(\.{"A\ tertiary"})$;\2\6 +\\{scan\_secondary};\6 +\&{if} $\\{cur\_type}=\\{future\_pen}$ \1\&{then}\5 +\\{materialize\_pen};\2\6 +\4\\{continue}: \37\&{if} $\\{cur\_cmd}\L\\{max\_tertiary\_command}$ \1\&{then}% +\6 +\&{if} $\\{cur\_cmd}\G\\{min\_tertiary\_command}$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{stash\_cur\_exp}$;\5 +$\|c\K\\{cur\_mod}$;\5 +$\|d\K\\{cur\_cmd}$;\6 +\&{if} $\|d=\\{tertiary\_secondary\_macro}$ \1\&{then}\6 +\&{begin} \37$\\{mac\_name}\K\\{cur\_sym}$;\5 +$\\{add\_mac\_ref}(\|c)$;\6 +\&{end};\2\6 +\\{get\_x\_next};\5 +\\{scan\_secondary};\6 +\&{if} $\|d\I\\{tertiary\_secondary\_macro}$ \1\&{then}\5 +$\\{do\_binary}(\|p,\39\|c)$\6 +\4\&{else} \&{begin} \37\\{back\_input};\5 +$\\{binary\_mac}(\|p,\39\|c,\39\\{mac\_name})$;\5 +$\\{decr}(\\{ref\_count}(\|c))$;\5 +\\{get\_x\_next};\5 +\&{goto} \37\\{restart};\6 +\&{end};\2\6 +\&{goto} \37\\{continue};\6 +\&{end};\2\2\6 +\&{end};\par +\fi + +\M865. A \\{future\_pen} becomes a full-fledged pen here. + +\Y\P\4\&{procedure}\1\ \37\\{materialize\_pen};\6 +\4\&{label} \37\\{common\_ending};\6 +\4\&{var} \37$\\{a\_minus\_b},\39\\{a\_plus\_b},\39\\{major\_axis},\39\\{minor% +\_axis}$: \37\\{scaled};\C{ellipse variables}\6 +\\{theta}: \37\\{angle};\C{amount by which the ellipse has been rotated}\6 +\|p: \37\\{pointer};\C{path traverser}\6 +\|q: \37\\{pointer};\C{the knot list to be made into a pen}\2\6 +\&{begin} \37$\|q\K\\{cur\_exp}$;\6 +\&{if} $\\{left\_type}(\|q)=\\{endpoint}$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"Pen\ path\ must\ be\ a\ cycle"})$;\5 +$\\{help2}(\.{"I\ can\'t\ make\ a\ pen\ from\ the\ given\ path."})$\6 +$(\.{"So\ I\'ve\ replaced\ it\ by\ the\ trivial\ path\ \`(0,0)..cycle\'."})$;\5 +\\{put\_get\_error};\5 +$\\{cur\_exp}\K\\{null\_pen}$;\5 +\&{goto} \37\\{common\_ending};\6 +\&{end}\6 +\4\&{else} \&{if} $\\{left\_type}(\|q)=\\{open}$ \1\&{then}\5 +\X866:Change node \|q to a path for an elliptical pen\X;\2\2\6 +$\\{cur\_exp}\K\\{make\_pen}(\|q)$;\6 +\4\\{common\_ending}: \37$\\{toss\_knot\_list}(\|q)$;\5 +$\\{cur\_type}\K\\{pen\_type}$;\6 +\&{end};\par +\fi + +\M866. We placed the three points $(0,0)$, $(1,0)$, $(0,1)$ into a % +\&{pencircle}, +and they have now been transformed to $(u,v)$, $(A+u,B+v)$, $(C+u,D+v)$; +this gives us enough information to deduce the transformation +$(x,y)\mapsto(Ax+Cy+u,Bx+Dy+v)$. + +Given ($A,B,C,D)$ we can always find $(a,b,\theta,\phi)$ such that +$$\eqalign{A&=a\cos\phi\cos\theta-b\sin\phi\sin\theta;\cr +B&=a\cos\phi\sin\theta+b\sin\phi\cos\theta;\cr +C&=-a\sin\phi\cos\theta-b\cos\phi\sin\theta;\cr +D&=-a\sin\phi\sin\theta+b\cos\phi\cos\theta.\cr}$$ +In this notation, the unit circle $(\cos t,\sin t)$ is transformed into +$$\bigl(a\cos(\phi+t)\cos\theta-b\sin(\phi+t)\sin\theta,\; +a\cos(\phi+t)\sin\theta+b\sin(\phi+t)\cos\theta\bigr)\;+\;(u,v),$$ +which is an ellipse with semi-axes~$(a,b)$, rotated by~$\theta$ and +shifted by~$(u,v)$. To solve the stated equations, we note that it is +necessary and sufficient to solve +$$\eqalign{A-D&=(a-b)\cos(\theta-\phi),\cr +B+C&=(a-b)\sin(\theta-\phi),\cr} +\qquad +\eqalign{A+D&=(a+b)\cos(\theta+\phi),\cr +B-C&=(a+b)\sin(\theta+\phi);\cr}$$ +and it is easy to find $a-b$, $a+b$, $\theta-\phi$, and $\theta+\phi$ +from these formulas. + +The code below uses $(\\{txx},\\{tyx},\\{txy},\\{tyy},\\{tx},\\{ty})$ to stand +for +$(A,B,C,D,u,v)$. + +\Y\P$\4\X866:Change node \|q to a path for an elliptical pen\X\S$\6 +\&{begin} \37$\\{tx}\K\\{x\_coord}(\|q)$;\5 +$\\{ty}\K\\{y\_coord}(\|q)$;\5 +$\\{txx}\K\\{left\_x}(\|q)-\\{tx}$;\5 +$\\{tyx}\K\\{left\_y}(\|q)-\\{ty}$;\5 +$\\{txy}\K\\{right\_x}(\|q)-\\{tx}$;\5 +$\\{tyy}\K\\{right\_y}(\|q)-\\{ty}$;\5 +$\\{a\_minus\_b}\K\\{pyth\_add}(\\{txx}-\\{tyy},\39\\{tyx}+\\{txy})$;\5 +$\\{a\_plus\_b}\K\\{pyth\_add}(\\{txx}+\\{tyy},\39\\{tyx}-\\{txy})$;\5 +$\\{major\_axis}\K\\{half}(\\{a\_minus\_b}+\\{a\_plus\_b})$;\5 +$\\{minor\_axis}\K\\{half}(\\{abs}(\\{a\_plus\_b}-\\{a\_minus\_b}))$;\6 +\&{if} $\\{major\_axis}=\\{minor\_axis}$ \1\&{then}\5 +$\\{theta}\K0$\C{circle}\6 +\4\&{else} $\\{theta}\K\\{half}(\\{n\_arg}(\\{txx}-\\{tyy},\39\\{tyx}+\\{txy})+% +\\{n\_arg}(\\{txx}+\\{tyy},\39\\{tyx}-\\{txy}))$;\2\6 +$\\{free\_node}(\|q,\39\\{knot\_node\_size})$;\5 +$\|q\K\\{make\_ellipse}(\\{major\_axis},\39\\{minor\_axis},\39\\{theta})$;\6 +\&{if} $(\\{tx}\I0)\V(\\{ty}\I0)$ \1\&{then}\5 +\X867:Shift the coordinates of path \|q\X;\2\6 +\&{end}\par +\U865.\fi + +\M867. \P$\X867:Shift the coordinates of path \|q\X\S$\6 +\&{begin} \37$\|p\K\|q$;\6 +\1\&{repeat} \37$\\{x\_coord}(\|p)\K\\{x\_coord}(\|p)+\\{tx}$;\5 +$\\{y\_coord}(\|p)\K\\{y\_coord}(\|p)+\\{ty}$;\5 +$\|p\K\\{link}(\|p)$;\6 +\4\&{until}\5 +$\|p=\|q$;\2\6 +\&{end}\par +\U866.\fi + +\M868. Finally we reach the deepest level in our quartet of parsing routines. +This one is much like the others; but it has an extra complication from +paths, which materialize here. + +\Y\P\D \37$\\{continue\_path}=25$\C{a label inside of \\{scan\_expression}}\par +\P\D \37$\\{finish\_path}=26$\C{another}\par +\Y\P$\4\X823:Declare the basic parsing subroutines\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{scan\_expression};\6 +\4\&{label} \37$\\{restart},\39\\{done},\39\\{continue},\39\\{continue\_path},% +\39\\{finish\_path},\39\\{exit}$;\6 +\4\&{var} \37$\|p,\39\|q,\39\|r,\39\\{pp},\39\\{qq}$: \37\\{pointer};\C{for +list manipulation}\6 +$\|c,\39\|d$: \37\\{halfword};\C{operation codes or modifiers}\6 +\\{my\_var\_flag}: \37$0\to\\{max\_command\_code}$;\C{initial value of \\{var% +\_flag}}\6 +\\{mac\_name}: \37\\{pointer};\C{token defined with \&{tertiarydef}}\6 +\\{cycle\_hit}: \37\\{boolean};\C{did a path expression just end with `% +\&{cycle}'?}\6 +$\|x,\39\|y$: \37\\{scaled};\C{explicit coordinates or tension at a path join}\6 +\|t: \37$\\{endpoint}\to\\{open}$;\C{knot type following a path join}\2\6 +\&{begin} \37$\\{my\_var\_flag}\K\\{var\_flag}$;\6 +\4\\{restart}: \37\&{if} $(\\{cur\_cmd}<\\{min\_primary\_command})\V\30(\\{cur% +\_cmd}>\\{max\_primary\_command})$ \1\&{then}\5 +$\\{bad\_exp}(\.{"An"})$;\2\6 +\\{scan\_tertiary};\6 +\4\\{continue}: \37\&{if} $\\{cur\_cmd}\L\\{max\_expression\_command}$ \1% +\&{then}\6 +\&{if} $\\{cur\_cmd}\G\\{min\_expression\_command}$ \1\&{then}\6 +\&{if} $(\\{cur\_cmd}\I\\{equals})\V(\\{my\_var\_flag}\I\\{assignment})$ \1% +\&{then}\6 +\&{begin} \37$\|p\K\\{stash\_cur\_exp}$;\5 +$\|c\K\\{cur\_mod}$;\5 +$\|d\K\\{cur\_cmd}$;\6 +\&{if} $\|d=\\{expression\_tertiary\_macro}$ \1\&{then}\6 +\&{begin} \37$\\{mac\_name}\K\\{cur\_sym}$;\5 +$\\{add\_mac\_ref}(\|c)$;\6 +\&{end};\2\6 +\&{if} $(\|d<\\{ampersand})\V((\|d=\\{ampersand})\W\30((\\{type}(\|p)=\\{pair% +\_type})\V(\\{type}(\|p)=\\{path\_type})))$ \1\&{then}\5 +\X869:Scan a path construction operation; but \&{return} if \|p has the wrong +type\X\6 +\4\&{else} \&{begin} \37\\{get\_x\_next};\5 +\\{scan\_tertiary};\6 +\&{if} $\|d\I\\{expression\_tertiary\_macro}$ \1\&{then}\5 +$\\{do\_binary}(\|p,\39\|c)$\6 +\4\&{else} \&{begin} \37\\{back\_input};\5 +$\\{binary\_mac}(\|p,\39\|c,\39\\{mac\_name})$;\5 +$\\{decr}(\\{ref\_count}(\|c))$;\5 +\\{get\_x\_next};\5 +\&{goto} \37\\{restart};\6 +\&{end};\2\6 +\&{end};\2\6 +\&{goto} \37\\{continue};\6 +\&{end};\2\2\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M869. The reader should review the data structure conventions for paths before +hoping to understand the next part of this code. + +\Y\P$\4\X869:Scan a path construction operation; but \&{return} if \|p has the +wrong type\X\S$\6 +\&{begin} \37$\\{cycle\_hit}\K\\{false}$;\5 +\X870:Convert the left operand, \|p, into a partial path ending at~\|q; but % +\&{return} if \|p doesn't have a suitable type\X;\6 +\4\\{continue\_path}: \37\X874:Determine the path join parameters; but \&{goto} +\\{finish\_path} if there's only a direction specifier\X;\6 +\&{if} $\\{cur\_cmd}=\\{cycle}$ \1\&{then}\5 +\X886:Get ready to close a cycle\X\6 +\4\&{else} \&{begin} \37\\{scan\_tertiary};\5 +\X885:Convert the right operand, \\{cur\_exp}, into a partial path from \\{pp} +to~\\{qq}\X;\6 +\&{end};\2\6 +\X887:Join the partial paths and reset \|p and \|q to the head and tail of the +result\X;\6 +\&{if} $\\{cur\_cmd}\G\\{min\_expression\_command}$ \1\&{then}\6 +\&{if} $\\{cur\_cmd}\L\\{ampersand}$ \1\&{then}\6 +\&{if} $\R\\{cycle\_hit}$ \1\&{then}\5 +\&{goto} \37\\{continue\_path};\2\2\2\6 +\4\\{finish\_path}: \37\X891:Choose control points for the path and put the +result into \\{cur\_exp}\X;\6 +\&{end}\par +\U868.\fi + +\M870. \P$\X870:Convert the left operand, \|p, into a partial path ending at~% +\|q; but \&{return} if \|p doesn't have a suitable type\X\S$\6 +\&{begin} \37$\\{unstash\_cur\_exp}(\|p)$;\6 +\&{if} $\\{cur\_type}=\\{pair\_type}$ \1\&{then}\5 +$\|p\K\\{new\_knot}$\6 +\4\&{else} \&{if} $\\{cur\_type}=\\{path\_type}$ \1\&{then}\5 +$\|p\K\\{cur\_exp}$\6 +\4\&{else} \&{return};\2\2\6 +$\|q\K\|p$;\6 +\&{while} $\\{link}(\|q)\I\|p$ \1\&{do}\5 +$\|q\K\\{link}(\|q)$;\2\6 +\&{if} $\\{left\_type}(\|p)\I\\{endpoint}$ \1\&{then}\C{open up a cycle}\6 +\&{begin} \37$\|r\K\\{copy\_knot}(\|p)$;\5 +$\\{link}(\|q)\K\|r$;\5 +$\|q\K\|r$;\6 +\&{end};\2\6 +$\\{left\_type}(\|p)\K\\{open}$;\5 +$\\{right\_type}(\|q)\K\\{open}$;\6 +\&{end}\par +\U869.\fi + +\M871. A pair of numeric values is changed into a knot node for a one-point +path +when \MF\ discovers that the pair is part of a path. + +\Y\P\hbox{\4}\X872:Declare the procedure called \\{known\_pair}\X\6 +\4\&{function}\1\ \37\\{new\_knot}: \37\\{pointer};\C{convert a pair to a knot +with two endpoints}\6 +\4\&{var} \37\|q: \37\\{pointer};\C{the new node}\2\6 +\&{begin} \37$\|q\K\\{get\_node}(\\{knot\_node\_size})$;\5 +$\\{left\_type}(\|q)\K\\{endpoint}$;\5 +$\\{right\_type}(\|q)\K\\{endpoint}$;\5 +$\\{link}(\|q)\K\|q$;\6 +\\{known\_pair};\5 +$\\{x\_coord}(\|q)\K\\{cur\_x}$;\5 +$\\{y\_coord}(\|q)\K\\{cur\_y}$;\5 +$\\{new\_knot}\K\|q$;\6 +\&{end};\par +\fi + +\M872. The \\{known\_pair} subroutine sets \\{cur\_x} and \\{cur\_y} to the +components +of the current expression, assuming that the current expression is a +pair of known numerics. Unknown components are zeroed, and the +current expression is flushed. + +\Y\P$\4\X872:Declare the procedure called \\{known\_pair}\X\S$\6 +\4\&{procedure}\1\ \37\\{known\_pair};\6 +\4\&{var} \37\|p: \37\\{pointer};\C{the pair node}\2\6 +\&{begin} \37\&{if} $\\{cur\_type}\I\\{pair\_type}$ \1\&{then}\6 +\&{begin} \37$\\{exp\_err}(\.{"Undefined\ coordinates\ have\ been\ replaced\ by% +\ (0,0)"})$;\5 +$\\{help5}(\.{"I\ need\ x\ and\ y\ numbers\ for\ this\ part\ of\ the\ path."})$% +\6 +$(\.{"The\ value\ I\ found\ (see\ above)\ was\ no\ good;"})$\6 +$(\.{"so\ I\'ll\ try\ to\ keep\ going\ by\ using\ zero\ instead."})$\6 +$(\.{"(Chapter\ 27\ of\ The\ METAFONTbook\ explains\ that"})$\6 +$(\.{"you\ might\ want\ to\ type\ \`I\ ???\'\ now.)"})$;\5 +$\\{put\_get\_flush\_error}(0)$;\5 +$\\{cur\_x}\K0$;\5 +$\\{cur\_y}\K0$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|p\K\\{value}(\\{cur\_exp})$;\5 +\X873:Make sure that both \|x and \|y parts of \|p are known; copy them into % +\\{cur\_x} and \\{cur\_y}\X;\6 +$\\{flush\_cur\_exp}(0)$;\6 +\&{end};\2\6 +\&{end};\par +\U871.\fi + +\M873. \P$\X873:Make sure that both \|x and \|y parts of \|p are known; copy +them into \\{cur\_x} and \\{cur\_y}\X\S$\6 +\&{if} $\\{type}(\\{x\_part\_loc}(\|p))=\\{known}$ \1\&{then}\5 +$\\{cur\_x}\K\\{value}(\\{x\_part\_loc}(\|p))$\6 +\4\&{else} \&{begin} \37$\\{disp\_err}(\\{x\_part\_loc}(\|p),\39\.{"Undefined\ +x\ coordinate\ has\ been\ replaced\ by\ 0"})$;\5 +$\\{help5}(\.{"I\ need\ a\ \`known\'\ x\ value\ for\ this\ part\ of\ the\ +path."})$\6 +$(\.{"The\ value\ I\ found\ (see\ above)\ was\ no\ good;"})$\6 +$(\.{"so\ I\'ll\ try\ to\ keep\ going\ by\ using\ zero\ instead."})$\6 +$(\.{"(Chapter\ 27\ of\ The\ METAFONTbook\ explains\ that"})$\6 +$(\.{"you\ might\ want\ to\ type\ \`I\ ???\'\ now.)"})$;\5 +\\{put\_get\_error};\5 +$\\{recycle\_value}(\\{x\_part\_loc}(\|p))$;\5 +$\\{cur\_x}\K0$;\6 +\&{end};\2\6 +\&{if} $\\{type}(\\{y\_part\_loc}(\|p))=\\{known}$ \1\&{then}\5 +$\\{cur\_y}\K\\{value}(\\{y\_part\_loc}(\|p))$\6 +\4\&{else} \&{begin} \37$\\{disp\_err}(\\{y\_part\_loc}(\|p),\39\.{"Undefined\ +y\ coordinate\ has\ been\ replaced\ by\ 0"})$;\5 +$\\{help5}(\.{"I\ need\ a\ \`known\'\ y\ value\ for\ this\ part\ of\ the\ +path."})$\6 +$(\.{"The\ value\ I\ found\ (see\ above)\ was\ no\ good;"})$\6 +$(\.{"so\ I\'ll\ try\ to\ keep\ going\ by\ using\ zero\ instead."})$\6 +$(\.{"(Chapter\ 27\ of\ The\ METAFONTbook\ explains\ that"})$\6 +$(\.{"you\ might\ want\ to\ type\ \`I\ ???\'\ now.)"})$;\5 +\\{put\_get\_error};\5 +$\\{recycle\_value}(\\{y\_part\_loc}(\|p))$;\5 +$\\{cur\_y}\K0$;\6 +\&{end}\2\par +\U872.\fi + +\M874. At this point \\{cur\_cmd} is either \\{ampersand}, \\{left\_brace}, or % +\\{path\_join}. + +\Y\P$\4\X874:Determine the path join parameters; but \&{goto} \\{finish\_path} +if there's only a direction specifier\X\S$\6 +\&{if} $\\{cur\_cmd}=\\{left\_brace}$ \1\&{then}\5 +\X879:Put the pre-join direction information into node \|q\X;\2\6 +$\|d\K\\{cur\_cmd}$;\6 +\&{if} $\|d=\\{path\_join}$ \1\&{then}\5 +\X881:Determine the tension and/or control points\X\6 +\4\&{else} \&{if} $\|d\I\\{ampersand}$ \1\&{then}\5 +\&{goto} \37\\{finish\_path};\2\2\6 +\\{get\_x\_next};\6 +\&{if} $\\{cur\_cmd}=\\{left\_brace}$ \1\&{then}\5 +\X880:Put the post-join direction information into \|x and \|t\X\6 +\4\&{else} \&{if} $\\{right\_type}(\|q)\I\\{explicit}$ \1\&{then}\6 +\&{begin} \37$\|t\K\\{open}$;\5 +$\|x\K0$;\6 +\&{end}\2\2\par +\U869.\fi + +\M875. The \\{scan\_direction} subroutine looks at the directional information +that is enclosed in braces, and also scans ahead to the following character. +A type code is returned, either \\{open} (if the direction was $(0,0)$), +or \\{curl} (if the direction was a curl of known value \\{cur\_exp}), or +\\{given} (if the direction is given by the \\{angle} value that now +appears in \\{cur\_exp}). + +There's nothing difficult about this subroutine, but the program is rather +lengthy because a variety of potential errors need to be nipped in the bud. + +\Y\P\4\&{function}\1\ \37\\{scan\_direction}: \37\\{small\_number};\6 +\4\&{var} \37\|t: \37$\\{given}\to\\{open}$;\C{the type of information found}\6 +\|x: \37\\{scaled};\C{an \|x coordinate}\2\6 +\&{begin} \37\\{get\_x\_next};\6 +\&{if} $\\{cur\_cmd}=\\{curl\_command}$ \1\&{then}\5 +\X876:Scan a curl specification\X\6 +\4\&{else} \X877:Scan a given direction\X;\2\6 +\&{if} $\\{cur\_cmd}\I\\{right\_brace}$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\.{"\}"})$;\6 +$\\{help3}(\.{"I\'ve\ scanned\ a\ direction\ spec\ for\ part\ of\ a\ path,"})$\6 +$(\.{"so\ a\ right\ brace\ should\ have\ come\ next."})$\6 +$(\.{"I\ shall\ pretend\ that\ one\ was\ there."})$;\6 +\\{back\_error};\6 +\&{end};\2\6 +\\{get\_x\_next};\5 +$\\{scan\_direction}\K\|t$;\6 +\&{end};\par +\fi + +\M876. \P$\X876:Scan a curl specification\X\S$\6 +\&{begin} \37\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $(\\{cur\_type}\I\\{known})\V(\\{cur\_exp}<0)$ \1\&{then}\6 +\&{begin} \37$\\{exp\_err}(\.{"Improper\ curl\ has\ been\ replaced\ by\ 1"})$;\5 +$\\{help1}(\.{"A\ curl\ must\ be\ a\ known,\ nonnegative\ number."})$;\5 +$\\{put\_get\_flush\_error}(\\{unity})$;\6 +\&{end};\2\6 +$\|t\K\\{curl}$;\6 +\&{end}\par +\U875.\fi + +\M877. \P$\X877:Scan a given direction\X\S$\6 +\&{begin} \37\\{scan\_expression};\6 +\&{if} $\\{cur\_type}>\\{pair\_type}$ \1\&{then}\5 +\X878:Get given directions separated by commas\X\6 +\4\&{else} \\{known\_pair};\2\6 +\&{if} $(\\{cur\_x}=0)\W(\\{cur\_y}=0)$ \1\&{then}\5 +$\|t\K\\{open}$\6 +\4\&{else} \&{begin} \37$\|t\K\\{given}$;\5 +$\\{cur\_exp}\K\\{n\_arg}(\\{cur\_x},\39\\{cur\_y})$;\6 +\&{end};\2\6 +\&{end}\par +\U875.\fi + +\M878. \P$\X878:Get given directions separated by commas\X\S$\6 +\&{begin} \37\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\6 +\&{begin} \37$\\{exp\_err}(\.{"Undefined\ x\ coordinate\ has\ been\ replaced\ +by\ 0"})$;\5 +$\\{help5}(\.{"I\ need\ a\ \`known\'\ x\ value\ for\ this\ part\ of\ the\ +path."})$\6 +$(\.{"The\ value\ I\ found\ (see\ above)\ was\ no\ good;"})$\6 +$(\.{"so\ I\'ll\ try\ to\ keep\ going\ by\ using\ zero\ instead."})$\6 +$(\.{"(Chapter\ 27\ of\ The\ METAFONTbook\ explains\ that"})$\6 +$(\.{"you\ might\ want\ to\ type\ \`I\ ???\'\ now.)"})$;\5 +$\\{put\_get\_flush\_error}(0)$;\6 +\&{end};\2\6 +$\|x\K\\{cur\_exp}$;\6 +\&{if} $\\{cur\_cmd}\I\\{comma}$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\.{","})$;\6 +$\\{help2}(\.{"I\'ve\ got\ the\ x\ coordinate\ of\ a\ path\ direction;"})$\6 +$(\.{"will\ look\ for\ the\ y\ coordinate\ next."})$;\5 +\\{back\_error};\6 +\&{end};\2\6 +\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\6 +\&{begin} \37$\\{exp\_err}(\.{"Undefined\ y\ coordinate\ has\ been\ replaced\ +by\ 0"})$;\5 +$\\{help5}(\.{"I\ need\ a\ \`known\'\ y\ value\ for\ this\ part\ of\ the\ +path."})$\6 +$(\.{"The\ value\ I\ found\ (see\ above)\ was\ no\ good;"})$\6 +$(\.{"so\ I\'ll\ try\ to\ keep\ going\ by\ using\ zero\ instead."})$\6 +$(\.{"(Chapter\ 27\ of\ The\ METAFONTbook\ explains\ that"})$\6 +$(\.{"you\ might\ want\ to\ type\ \`I\ ???\'\ now.)"})$;\5 +$\\{put\_get\_flush\_error}(0)$;\6 +\&{end};\2\6 +$\\{cur\_y}\K\\{cur\_exp}$;\5 +$\\{cur\_x}\K\|x$;\6 +\&{end}\par +\U877.\fi + +\M879. At this point $\\{right\_type}(\|q)$ is usually \\{open}, but it may +have been +set to some other value by a previous splicing operation. We must maintain +the value of $\\{right\_type}(\|q)$ in unusual cases such as +`\.{..z1\{z2\}\&\{z3\}z1\{0,0\}..}'. + +\Y\P$\4\X879:Put the pre-join direction information into node \|q\X\S$\6 +\&{begin} \37$\|t\K\\{scan\_direction}$;\6 +\&{if} $\|t\I\\{open}$ \1\&{then}\6 +\&{begin} \37$\\{right\_type}(\|q)\K\|t$;\5 +$\\{right\_given}(\|q)\K\\{cur\_exp}$;\6 +\&{if} $\\{left\_type}(\|q)=\\{open}$ \1\&{then}\6 +\&{begin} \37$\\{left\_type}(\|q)\K\|t$;\5 +$\\{left\_given}(\|q)\K\\{cur\_exp}$;\6 +\&{end};\C{note that $\\{left\_given}(\|q)=\\{left\_curl}(\|q)$}\2\6 +\&{end};\2\6 +\&{end}\par +\U874.\fi + +\M880. Since \\{left\_tension} and \\{left\_y} share the same position in knot +nodes, +and since \\{left\_given} is similarly equivalent to \\{left\_x}, we use +\|x and \|y to hold the given direction and tension information when +there are no explicit control points. + +\Y\P$\4\X880:Put the post-join direction information into \|x and \|t\X\S$\6 +\&{begin} \37$\|t\K\\{scan\_direction}$;\6 +\&{if} $\\{right\_type}(\|q)\I\\{explicit}$ \1\&{then}\5 +$\|x\K\\{cur\_exp}$\6 +\4\&{else} $\|t\K\\{explicit}$;\C{the direction information is superfluous}\2\6 +\&{end}\par +\U874.\fi + +\M881. \P$\X881:Determine the tension and/or control points\X\S$\6 +\&{begin} \37\\{get\_x\_next};\6 +\&{if} $\\{cur\_cmd}=\\{tension}$ \1\&{then}\5 +\X882:Set explicit tensions\X\6 +\4\&{else} \&{if} $\\{cur\_cmd}=\\{controls}$ \1\&{then}\5 +\X884:Set explicit control points\X\6 +\4\&{else} \&{begin} \37$\\{right\_tension}(\|q)\K\\{unity}$;\5 +$\|y\K\\{unity}$;\5 +\\{back\_input};\C{default tension}\6 +\&{goto} \37\\{done};\6 +\&{end};\2\2\6 +\&{if} $\\{cur\_cmd}\I\\{path\_join}$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\.{".."})$;\6 +$\\{help1}(\.{"A\ path\ join\ command\ should\ end\ with\ two\ dots."})$;\5 +\\{back\_error};\6 +\&{end};\2\6 +\4\\{done}: \37\&{end}\par +\U874.\fi + +\M882. \P$\X882:Set explicit tensions\X\S$\6 +\&{begin} \37\\{get\_x\_next};\5 +$\|y\K\\{cur\_cmd}$;\6 +\&{if} $\\{cur\_cmd}=\\{at\_least}$ \1\&{then}\5 +\\{get\_x\_next};\2\6 +\\{scan\_primary};\5 +\X883:Make sure that the current expression is a valid tension setting\X;\6 +\&{if} $\|y=\\{at\_least}$ \1\&{then}\5 +$\\{negate}(\\{cur\_exp})$;\2\6 +$\\{right\_tension}(\|q)\K\\{cur\_exp}$;\6 +\&{if} $\\{cur\_cmd}=\\{and\_command}$ \1\&{then}\6 +\&{begin} \37\\{get\_x\_next};\5 +$\|y\K\\{cur\_cmd}$;\6 +\&{if} $\\{cur\_cmd}=\\{at\_least}$ \1\&{then}\5 +\\{get\_x\_next};\2\6 +\\{scan\_primary};\5 +\X883:Make sure that the current expression is a valid tension setting\X;\6 +\&{if} $\|y=\\{at\_least}$ \1\&{then}\5 +$\\{negate}(\\{cur\_exp})$;\2\6 +\&{end};\2\6 +$\|y\K\\{cur\_exp}$;\6 +\&{end}\par +\U881.\fi + +\M883. \P\D \37$\\{min\_tension}\S\\{three\_quarter\_unit}$\par +\Y\P$\4\X883:Make sure that the current expression is a valid tension setting\X% +\S$\6 +\&{if} $(\\{cur\_type}\I\\{known})\V(\\{cur\_exp}<\\{min\_tension})$ \1\&{then}% +\6 +\&{begin} \37$\\{exp\_err}(\.{"Improper\ tension\ has\ been\ set\ to\ 1"})$;\5 +$\\{help1}(\.{"The\ expression\ above\ should\ have\ been\ a\ number\ +>=3/4."})$;\5 +$\\{put\_get\_flush\_error}(\\{unity})$;\6 +\&{end}\2\par +\Us882\ET882.\fi + +\M884. \P$\X884:Set explicit control points\X\S$\6 +\&{begin} \37$\\{right\_type}(\|q)\K\\{explicit}$;\5 +$\|t\K\\{explicit}$;\5 +\\{get\_x\_next};\5 +\\{scan\_primary};\6 +\\{known\_pair};\5 +$\\{right\_x}(\|q)\K\\{cur\_x}$;\5 +$\\{right\_y}(\|q)\K\\{cur\_y}$;\6 +\&{if} $\\{cur\_cmd}\I\\{and\_command}$ \1\&{then}\6 +\&{begin} \37$\|x\K\\{right\_x}(\|q)$;\5 +$\|y\K\\{right\_y}(\|q)$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37\\{get\_x\_next};\5 +\\{scan\_primary};\6 +\\{known\_pair};\5 +$\|x\K\\{cur\_x}$;\5 +$\|y\K\\{cur\_y}$;\6 +\&{end};\2\6 +\&{end}\par +\U881.\fi + +\M885. \P$\X885:Convert the right operand, \\{cur\_exp}, into a partial path +from \\{pp} to~\\{qq}\X\S$\6 +\&{begin} \37\&{if} $\\{cur\_type}\I\\{path\_type}$ \1\&{then}\5 +$\\{pp}\K\\{new\_knot}$\6 +\4\&{else} $\\{pp}\K\\{cur\_exp}$;\2\6 +$\\{qq}\K\\{pp}$;\6 +\&{while} $\\{link}(\\{qq})\I\\{pp}$ \1\&{do}\5 +$\\{qq}\K\\{link}(\\{qq})$;\2\6 +\&{if} $\\{left\_type}(\\{pp})\I\\{endpoint}$ \1\&{then}\C{open up a cycle}\6 +\&{begin} \37$\|r\K\\{copy\_knot}(\\{pp})$;\5 +$\\{link}(\\{qq})\K\|r$;\5 +$\\{qq}\K\|r$;\6 +\&{end};\2\6 +$\\{left\_type}(\\{pp})\K\\{open}$;\5 +$\\{right\_type}(\\{qq})\K\\{open}$;\6 +\&{end}\par +\U869.\fi + +\M886. If a person tries to define an entire path by saying `\.{(x,y)\&cycle}', +we silently change the specification to `\.{(x,y)..cycle}', since a cycle +shouldn't have length zero. + +\Y\P$\4\X886:Get ready to close a cycle\X\S$\6 +\&{begin} \37$\\{cycle\_hit}\K\\{true}$;\5 +\\{get\_x\_next};\5 +$\\{pp}\K\|p$;\5 +$\\{qq}\K\|p$;\6 +\&{if} $\|d=\\{ampersand}$ \1\&{then}\6 +\&{if} $\|p=\|q$ \1\&{then}\6 +\&{begin} \37$\|d\K\\{path\_join}$;\5 +$\\{right\_tension}(\|q)\K\\{unity}$;\5 +$\|y\K\\{unity}$;\6 +\&{end};\2\2\6 +\&{end}\par +\U869.\fi + +\M887. \P$\X887:Join the partial paths and reset \|p and \|q to the head and +tail of the result\X\S$\6 +\&{begin} \37\&{if} $\|d=\\{ampersand}$ \1\&{then}\6 +\&{if} $(\\{x\_coord}(\|q)\I\\{x\_coord}(\\{pp}))\V(\\{y\_coord}(\|q)\I\\{y% +\_coord}(\\{pp}))$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"Paths\ don\'t\ touch;\ \`\&\'\ will\ be\ +changed\ to\ \`..\'"})$;\5 +$\\{help3}(\.{"When\ you\ join\ paths\ \`p\&q\',\ the\ ending\ point\ of\ p"})$% +\6 +$(\.{"must\ be\ exactly\ equal\ to\ the\ starting\ point\ of\ q."})$\6 +$(\.{"So\ I\'m\ going\ to\ pretend\ that\ you\ said\ \`p..q\'\ instead."})$;\5 +\\{put\_get\_error};\5 +$\|d\K\\{path\_join}$;\5 +$\\{right\_tension}(\|q)\K\\{unity}$;\5 +$\|y\K\\{unity}$;\6 +\&{end};\2\2\6 +\X889:Plug an opening in $\\{right\_type}(\\{pp})$, if possible\X;\6 +\&{if} $\|d=\\{ampersand}$ \1\&{then}\5 +\X890:Splice independent paths together\X\6 +\4\&{else} \&{begin} \37\X888:Plug an opening in $\\{right\_type}(\|q)$, if +possible\X;\6 +$\\{link}(\|q)\K\\{pp}$;\5 +$\\{left\_y}(\\{pp})\K\|y$;\6 +\&{if} $\|t\I\\{open}$ \1\&{then}\6 +\&{begin} \37$\\{left\_x}(\\{pp})\K\|x$;\5 +$\\{left\_type}(\\{pp})\K\|t$;\6 +\&{end};\2\6 +\&{end};\2\6 +$\|q\K\\{qq}$;\6 +\&{end}\par +\U869.\fi + +\M888. \P$\X888:Plug an opening in $\\{right\_type}(\|q)$, if possible\X\S$\6 +\&{if} $\\{right\_type}(\|q)=\\{open}$ \1\&{then}\6 +\&{if} $(\\{left\_type}(\|q)=\\{curl})\V(\\{left\_type}(\|q)=\\{given})$ \1% +\&{then}\6 +\&{begin} \37$\\{right\_type}(\|q)\K\\{left\_type}(\|q)$;\5 +$\\{right\_given}(\|q)\K\\{left\_given}(\|q)$;\6 +\&{end}\2\2\par +\U887.\fi + +\M889. \P$\X889:Plug an opening in $\\{right\_type}(\\{pp})$, if possible\X\S$\6 +\&{if} $\\{right\_type}(\\{pp})=\\{open}$ \1\&{then}\6 +\&{if} $(\|t=\\{curl})\V(\|t=\\{given})$ \1\&{then}\6 +\&{begin} \37$\\{right\_type}(\\{pp})\K\|t$;\5 +$\\{right\_given}(\\{pp})\K\|x$;\6 +\&{end}\2\2\par +\U887.\fi + +\M890. \P$\X890:Splice independent paths together\X\S$\6 +\&{begin} \37\&{if} $\\{left\_type}(\|q)=\\{open}$ \1\&{then}\6 +\&{if} $\\{right\_type}(\|q)=\\{open}$ \1\&{then}\6 +\&{begin} \37$\\{left\_type}(\|q)\K\\{curl}$;\5 +$\\{left\_curl}(\|q)\K\\{unity}$;\6 +\&{end};\2\2\6 +\&{if} $\\{right\_type}(\\{pp})=\\{open}$ \1\&{then}\6 +\&{if} $\|t=\\{open}$ \1\&{then}\6 +\&{begin} \37$\\{right\_type}(\\{pp})\K\\{curl}$;\5 +$\\{right\_curl}(\\{pp})\K\\{unity}$;\6 +\&{end};\2\2\6 +$\\{right\_type}(\|q)\K\\{right\_type}(\\{pp})$;\5 +$\\{link}(\|q)\K\\{link}(\\{pp})$;\6 +$\\{right\_x}(\|q)\K\\{right\_x}(\\{pp})$;\5 +$\\{right\_y}(\|q)\K\\{right\_y}(\\{pp})$;\5 +$\\{free\_node}(\\{pp},\39\\{knot\_node\_size})$;\6 +\&{if} $\\{qq}=\\{pp}$ \1\&{then}\5 +$\\{qq}\K\|q$;\2\6 +\&{end}\par +\U887.\fi + +\M891. \P$\X891:Choose control points for the path and put the result into % +\\{cur\_exp}\X\S$\6 +\&{if} $\\{cycle\_hit}$ \1\&{then}\6 +\&{begin} \37\&{if} $\|d=\\{ampersand}$ \1\&{then}\5 +$\|p\K\|q$;\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{left\_type}(\|p)\K\\{endpoint}$;\6 +\&{if} $\\{right\_type}(\|p)=\\{open}$ \1\&{then}\6 +\&{begin} \37$\\{right\_type}(\|p)\K\\{curl}$;\5 +$\\{right\_curl}(\|p)\K\\{unity}$;\6 +\&{end};\2\6 +$\\{right\_type}(\|q)\K\\{endpoint}$;\6 +\&{if} $\\{left\_type}(\|q)=\\{open}$ \1\&{then}\6 +\&{begin} \37$\\{left\_type}(\|q)\K\\{curl}$;\5 +$\\{left\_curl}(\|q)\K\\{unity}$;\6 +\&{end};\2\6 +$\\{link}(\|q)\K\|p$;\6 +\&{end};\2\6 +$\\{make\_choices}(\|p)$;\5 +$\\{cur\_type}\K\\{path\_type}$;\5 +$\\{cur\_exp}\K\|p$\par +\U869.\fi + +\M892. Finally, we sometimes need to scan an expression whose value is +supposed to be either \\{true\_code} or \\{false\_code}. + +\Y\P$\4\X823:Declare the basic parsing subroutines\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{get\_boolean};\2\6 +\&{begin} \37\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_type}\I\\{boolean\_type}$ \1\&{then}\6 +\&{begin} \37$\\{exp\_err}(\.{"Undefined\ condition\ will\ be\ treated\ as\ % +\`false\'"})$;\5 +$\\{help2}(\.{"The\ expression\ shown\ above\ should\ have\ had\ a\ +definite"})$\6 +$(\.{"true-or-false\ value.\ I\'m\ changing\ it\ to\ \`false\'."})$;\6 +$\\{put\_get\_flush\_error}(\\{false\_code})$;\5 +$\\{cur\_type}\K\\{boolean\_type}$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\N893. \[42] Doing the operations. +The purpose of parsing is primarily to permit people to avoid piles of +parentheses. But the real work is done after the structure of an expression +has been recognized; that's when new expressions are generated. We +turn now to the guts of \MF, which handles individual operators that +have come through the parsing mechanism. + +We'll start with the easy ones that take no operands, then work our way +up to operators with one and ultimately two arguments. In other words, +we will write the three procedures \\{do\_nullary}, \\{do\_unary}, and \\{do% +\_binary} +that are invoked periodically by the expression scanners. + +First let's make sure that all of the primitive operators are in the +hash table. Although \\{scan\_primary} and its relatives made use of the +\\{cmd} code for these operators, the \\{do} routines base everything +on the \\{mod} code. For example, \\{do\_binary} doesn't care whether the +operation it performs is a \\{primary\_binary} or \\{secondary\_binary}, etc. + +\Y\P$\4\X192:Put each of \MF's primitives into the hash table\X\mathrel{+}\S$\6 +$\\{primitive}(\.{"true"},\39\\{nullary},\39\\{true\_code})$;\6 +$\\{primitive}(\.{"false"},\39\\{nullary},\39\\{false\_code})$;\6 +$\\{primitive}(\.{"nullpicture"},\39\\{nullary},\39\\{null\_picture\_code})$;\6 +$\\{primitive}(\.{"nullpen"},\39\\{nullary},\39\\{null\_pen\_code})$;\6 +$\\{primitive}(\.{"jobname"},\39\\{nullary},\39\\{job\_name\_op})$;\6 +$\\{primitive}(\.{"readstring"},\39\\{nullary},\39\\{read\_string\_op})$;\6 +$\\{primitive}(\.{"pencircle"},\39\\{nullary},\39\\{pen\_circle})$;\6 +$\\{primitive}(\.{"normaldeviate"},\39\\{nullary},\39\\{normal\_deviate})$;\6 +$\\{primitive}(\.{"odd"},\39\\{unary},\39\\{odd\_op})$;\6 +$\\{primitive}(\.{"known"},\39\\{unary},\39\\{known\_op})$;\6 +$\\{primitive}(\.{"unknown"},\39\\{unary},\39\\{unknown\_op})$;\6 +$\\{primitive}(\.{"not"},\39\\{unary},\39\\{not\_op})$;\6 +$\\{primitive}(\.{"decimal"},\39\\{unary},\39\\{decimal})$;\6 +$\\{primitive}(\.{"reverse"},\39\\{unary},\39\\{reverse})$;\6 +$\\{primitive}(\.{"makepath"},\39\\{unary},\39\\{make\_path\_op})$;\6 +$\\{primitive}(\.{"makepen"},\39\\{unary},\39\\{make\_pen\_op})$;\6 +$\\{primitive}(\.{"totalweight"},\39\\{unary},\39\\{total\_weight\_op})$;\6 +$\\{primitive}(\.{"oct"},\39\\{unary},\39\\{oct\_op})$;\6 +$\\{primitive}(\.{"hex"},\39\\{unary},\39\\{hex\_op})$;\6 +$\\{primitive}(\.{"ASCII"},\39\\{unary},\39\\{ASCII\_op})$;\6 +$\\{primitive}(\.{"char"},\39\\{unary},\39\\{char\_op})$;\6 +$\\{primitive}(\.{"length"},\39\\{unary},\39\\{length\_op})$;\6 +$\\{primitive}(\.{"turningnumber"},\39\\{unary},\39\\{turning\_op})$;\6 +$\\{primitive}(\.{"xpart"},\39\\{unary},\39\\{x\_part})$;\6 +$\\{primitive}(\.{"ypart"},\39\\{unary},\39\\{y\_part})$;\6 +$\\{primitive}(\.{"xxpart"},\39\\{unary},\39\\{xx\_part})$;\6 +$\\{primitive}(\.{"xypart"},\39\\{unary},\39\\{xy\_part})$;\6 +$\\{primitive}(\.{"yxpart"},\39\\{unary},\39\\{yx\_part})$;\6 +$\\{primitive}(\.{"yypart"},\39\\{unary},\39\\{yy\_part})$;\6 +$\\{primitive}(\.{"sqrt"},\39\\{unary},\39\\{sqrt\_op})$;\6 +$\\{primitive}(\.{"mexp"},\39\\{unary},\39\\{m\_exp\_op})$;\6 +$\\{primitive}(\.{"mlog"},\39\\{unary},\39\\{m\_log\_op})$;\6 +$\\{primitive}(\.{"sind"},\39\\{unary},\39\\{sin\_d\_op})$;\6 +$\\{primitive}(\.{"cosd"},\39\\{unary},\39\\{cos\_d\_op})$;\6 +$\\{primitive}(\.{"floor"},\39\\{unary},\39\\{floor\_op})$;\6 +$\\{primitive}(\.{"uniformdeviate"},\39\\{unary},\39\\{uniform\_deviate})$;\6 +$\\{primitive}(\.{"charexists"},\39\\{unary},\39\\{char\_exists\_op})$;\6 +$\\{primitive}(\.{"angle"},\39\\{unary},\39\\{angle\_op})$;\6 +$\\{primitive}(\.{"cycle"},\39\\{cycle},\39\\{cycle\_op})$;\6 +$\\{primitive}(\.{"+"},\39\\{plus\_or\_minus},\39\\{plus})$;\6 +$\\{primitive}(\.{"-"},\39\\{plus\_or\_minus},\39\\{minus})$;\6 +$\\{primitive}(\.{"*"},\39\\{secondary\_binary},\39\\{times})$;\6 +$\\{primitive}(\.{"/"},\39\\{slash},\39\\{over})$;\5 +$\\{eqtb}[\\{frozen\_slash}]\K\\{eqtb}[\\{cur\_sym}]$;\6 +$\\{primitive}(\.{"++"},\39\\{tertiary\_binary},\39\\{pythag\_add})$;\6 +$\\{primitive}(\.{"+-+"},\39\\{tertiary\_binary},\39\\{pythag\_sub})$;\6 +$\\{primitive}(\.{"and"},\39\\{and\_command},\39\\{and\_op})$;\6 +$\\{primitive}(\.{"or"},\39\\{tertiary\_binary},\39\\{or\_op})$;\6 +$\\{primitive}(\.{"<"},\39\\{expression\_binary},\39\\{less\_than})$;\6 +$\\{primitive}(\.{"<="},\39\\{expression\_binary},\39\\{less\_or\_equal})$;\6 +$\\{primitive}(\.{">"},\39\\{expression\_binary},\39\\{greater\_than})$;\6 +$\\{primitive}(\.{">="},\39\\{expression\_binary},\39\\{greater\_or\_equal})$;\6 +$\\{primitive}(\.{"="},\39\\{equals},\39\\{equal\_to})$;\6 +$\\{primitive}(\.{"<>"},\39\\{expression\_binary},\39\\{unequal\_to})$;\6 +$\\{primitive}(\.{"substring"},\39\\{primary\_binary},\39\\{substring\_of})$;\6 +$\\{primitive}(\.{"subpath"},\39\\{primary\_binary},\39\\{subpath\_of})$;\6 +$\\{primitive}(\.{"directiontime"},\39\\{primary\_binary},\39\\{direction\_time% +\_of})$;\6 +$\\{primitive}(\.{"point"},\39\\{primary\_binary},\39\\{point\_of})$;\6 +$\\{primitive}(\.{"precontrol"},\39\\{primary\_binary},\39\\{precontrol\_of})$;% +\6 +$\\{primitive}(\.{"postcontrol"},\39\\{primary\_binary},\39\\{postcontrol% +\_of})$;\6 +$\\{primitive}(\.{"penoffset"},\39\\{primary\_binary},\39\\{pen\_offset\_of})$;% +\6 +$\\{primitive}(\.{"\&"},\39\\{ampersand},\39\\{concatenate})$;\6 +$\\{primitive}(\.{"rotated"},\39\\{secondary\_binary},\39\\{rotated\_by})$;\6 +$\\{primitive}(\.{"slanted"},\39\\{secondary\_binary},\39\\{slanted\_by})$;\6 +$\\{primitive}(\.{"scaled"},\39\\{secondary\_binary},\39\\{scaled\_by})$;\6 +$\\{primitive}(\.{"shifted"},\39\\{secondary\_binary},\39\\{shifted\_by})$;\6 +$\\{primitive}(\.{"transformed"},\39\\{secondary\_binary},\39\\{transformed% +\_by})$;\6 +$\\{primitive}(\.{"xscaled"},\39\\{secondary\_binary},\39\\{x\_scaled})$;\6 +$\\{primitive}(\.{"yscaled"},\39\\{secondary\_binary},\39\\{y\_scaled})$;\6 +$\\{primitive}(\.{"zscaled"},\39\\{secondary\_binary},\39\\{z\_scaled})$;\6 +$\\{primitive}(\.{"intersectiontimes"},\39\\{tertiary\_binary},\39% +\\{intersect})$;\par +\fi + +\M894. \P$\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of +primitives\X\mathrel{+}\S$\6 +\4$\\{nullary},\39\\{unary},\39\\{primary\_binary},\39\\{secondary\_binary},\39% +\\{tertiary\_binary},\39\\{expression\_binary},\39\\{cycle},\39\\{plus\_or% +\_minus},\39\\{slash},\39\\{ampersand},\39\\{equals},\39\\{and\_command}$: \37$% +\\{print\_op}(\|m)$;\par +\fi + +\M895. OK, let's look at the simplest \\{do} procedure first. + +\Y\P\4\&{procedure}\1\ \37$\\{do\_nullary}(\|c:\\{quarterword})$;\6 +\4\&{var} \37\|k: \37\\{integer};\C{all-purpose loop index}\2\6 +\&{begin} \37\\{check\_arith};\6 +\&{if} $\\{internal}[\\{tracing\_commands}]>\\{two}$ \1\&{then}\5 +$\\{show\_cmd\_mod}(\\{nullary},\39\|c)$;\2\6 +\&{case} $\|c$ \1\&{of}\6 +\4$\\{true\_code},\39\\{false\_code}$: \37\&{begin} \37$\\{cur\_type}\K% +\\{boolean\_type}$;\5 +$\\{cur\_exp}\K\|c$;\6 +\&{end};\6 +\4\\{null\_picture\_code}: \37\&{begin} \37$\\{cur\_type}\K\\{picture\_type}$;\5 +$\\{cur\_exp}\K\\{get\_node}(\\{edge\_header\_size})$;\5 +$\\{init\_edges}(\\{cur\_exp})$;\6 +\&{end};\6 +\4\\{null\_pen\_code}: \37\&{begin} \37$\\{cur\_type}\K\\{pen\_type}$;\5 +$\\{cur\_exp}\K\\{null\_pen}$;\6 +\&{end};\6 +\4\\{normal\_deviate}: \37\&{begin} \37$\\{cur\_type}\K\\{known}$;\5 +$\\{cur\_exp}\K\\{norm\_rand}$;\6 +\&{end};\6 +\4\\{pen\_circle}: \37\X896:Make a special knot node for \&{pencircle}\X;\6 +\4\\{job\_name\_op}: \37\&{begin} \37\&{if} $\\{job\_name}=0$ \1\&{then}\5 +\\{open\_log\_file};\2\6 +$\\{cur\_type}\K\\{string\_type}$;\5 +$\\{cur\_exp}\K\\{job\_name}$;\6 +\&{end};\6 +\4\\{read\_string\_op}: \37\X897:Read a string from the terminal\X;\2\6 +\&{end};\C{there are no other cases}\6 +\\{check\_arith};\6 +\&{end};\par +\fi + +\M896. \P$\X896:Make a special knot node for \&{pencircle}\X\S$\6 +\&{begin} \37$\\{cur\_type}\K\\{future\_pen}$;\5 +$\\{cur\_exp}\K\\{get\_node}(\\{knot\_node\_size})$;\5 +$\\{left\_type}(\\{cur\_exp})\K\\{open}$;\5 +$\\{right\_type}(\\{cur\_exp})\K\\{open}$;\5 +$\\{link}(\\{cur\_exp})\K\\{cur\_exp}$;\6 +$\\{x\_coord}(\\{cur\_exp})\K0$;\5 +$\\{y\_coord}(\\{cur\_exp})\K0$;\6 +$\\{left\_x}(\\{cur\_exp})\K\\{unity}$;\5 +$\\{left\_y}(\\{cur\_exp})\K0$;\6 +$\\{right\_x}(\\{cur\_exp})\K0$;\5 +$\\{right\_y}(\\{cur\_exp})\K\\{unity}$;\6 +\&{end}\par +\U895.\fi + +\M897. \P$\X897:Read a string from the terminal\X\S$\6 +\&{begin} \37\&{if} $\\{interaction}\L\\{nonstop\_mode}$ \1\&{then}\5 +$\\{fatal\_error}(\.{"***\ (cannot\ readstring\ in\ nonstop\ modes)"})$;\2\6 +\\{begin\_file\_reading};\5 +$\\{name}\K1$;\5 +$\\{prompt\_input}(\.{""})$;\5 +$\\{str\_room}(\\{last}-\\{start})$;\6 +\&{for} $\|k\K\\{start}\mathrel{\&{to}}\\{last}-1$ \1\&{do}\5 +$\\{append\_char}(\\{buffer}[\|k])$;\2\6 +\\{end\_file\_reading};\5 +$\\{cur\_type}\K\\{string\_type}$;\5 +$\\{cur\_exp}\K\\{make\_string}$;\6 +\&{end}\par +\U895.\fi + +\M898. Things get a bit more interesting when there's an operand. The +operand to \\{do\_unary} appears in \\{cur\_type} and \\{cur\_exp}. + +\Y\P\hbox{\4}\X899:Declare unary action procedures\X\6 +\4\&{procedure}\1\ \37$\\{do\_unary}(\|c:\\{quarterword})$;\6 +\4\&{var} \37$\|p,\39\|q$: \37\\{pointer};\C{for list manipulation}\6 +\|x: \37\\{integer};\C{a temporary register}\2\6 +\&{begin} \37\\{check\_arith};\6 +\&{if} $\\{internal}[\\{tracing\_commands}]>\\{two}$ \1\&{then}\5 +\X902:Trace the current unary operation\X;\2\6 +\&{case} $\|c$ \1\&{of}\6 +\4\\{plus}: \37\&{if} $\\{cur\_type}<\\{pair\_type}$ \1\&{then}\6 +\&{if} $\\{cur\_type}\I\\{picture\_type}$ \1\&{then}\5 +$\\{bad\_unary}(\\{plus})$;\2\2\6 +\4\\{minus}: \37\X903:Negate the current expression\X;\6 +\hbox{\4}\X905:Additional cases of unary operators\X\2\6 +\&{end};\C{there are no other cases}\6 +\\{check\_arith};\6 +\&{end};\par +\fi + +\M899. The \\{nice\_pair} function returns \\{true} if both components of a +pair +are known. + +\Y\P$\4\X899:Declare unary action procedures\X\S$\6 +\4\&{function}\1\ \37$\\{nice\_pair}(\|p:\\{integer};\,\35\|t:% +\\{quarterword})$: \37\\{boolean};\6 +\4\&{label} \37\\{exit};\2\6 +\&{begin} \37\&{if} $\|t=\\{pair\_type}$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{value}(\|p)$;\6 +\&{if} $\\{type}(\\{x\_part\_loc}(\|p))=\\{known}$ \1\&{then}\6 +\&{if} $\\{type}(\\{y\_part\_loc}(\|p))=\\{known}$ \1\&{then}\6 +\&{begin} \37$\\{nice\_pair}\K\\{true}$;\5 +\&{return};\6 +\&{end};\2\2\6 +\&{end};\2\6 +$\\{nice\_pair}\K\\{false}$;\6 +\4\\{exit}: \37\&{end};\par +\As900, 901, 904, 908, 910, 913, 916\ETs919. +\U898.\fi + +\M900. \P$\X899:Declare unary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{print\_known\_or\_unknown\_type}(\|t:\\{small% +\_number};\,\35\|v:\\{integer})$;\2\6 +\&{begin} \37$\\{print\_char}(\.{"("})$;\6 +\&{if} $\|t<\\{dependent}$ \1\&{then}\6 +\&{if} $\|t\I\\{pair\_type}$ \1\&{then}\5 +$\\{print\_type}(\|t)$\6 +\4\&{else} \&{if} $\\{nice\_pair}(\|v,\39\\{pair\_type})$ \1\&{then}\5 +$\\{print}(\.{"pair"})$\6 +\4\&{else} $\\{print}(\.{"unknown\ pair"})$\2\2\6 +\4\&{else} $\\{print}(\.{"unknown\ numeric"})$;\2\6 +$\\{print\_char}(\.{")"})$;\6 +\&{end};\par +\fi + +\M901. \P$\X899:Declare unary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{bad\_unary}(\|c:\\{quarterword})$;\2\6 +\&{begin} \37$\\{exp\_err}(\.{"Not\ implemented:\ "})$;\5 +$\\{print\_op}(\|c)$;\5 +$\\{print\_known\_or\_unknown\_type}(\\{cur\_type},\39\\{cur\_exp})$;\5 +$\\{help3}(\.{"I\'m\ afraid\ I\ don\'t\ know\ how\ to\ apply\ that\ operation\ +to\ that"})$\6 +$(\.{"particular\ type.\ Continue,\ and\ I\'ll\ simply\ return\ the"})$\6 +$(\.{"argument\ (shown\ above)\ as\ the\ result\ of\ the\ operation."})$;\5 +\\{put\_get\_error};\6 +\&{end};\par +\fi + +\M902. \P$\X902:Trace the current unary operation\X\S$\6 +\&{begin} \37\\{begin\_diagnostic};\5 +$\\{print\_nl}(\.{"\{"})$;\5 +$\\{print\_op}(\|c)$;\5 +$\\{print\_char}(\.{"("})$;\6 +$\\{print\_exp}(\\{null},\390)$;\C{show the operand, but not verbosely}\6 +$\\{print}(\.{")\}"})$;\5 +$\\{end\_diagnostic}(\\{false})$;\6 +\&{end}\par +\U898.\fi + +\M903. Negation is easy except when the current expression +is of type \\{independent}, or when it is a pair with one or more +\\{independent} components. + +It is tempting to argue that the negative of an independent variable +is an independent variable, hence we don't have to do anything when +negating it. The fallacy is that other dependent variables pointing +to the current expression must change the sign of their +coefficients if we make no change to the current expression. + +Instead, we work around the problem by copying the current expression +and recycling it afterwards (cf.~the \\{stash\_in} routine). + +\Y\P$\4\X903:Negate the current expression\X\S$\6 +\&{case} $\\{cur\_type}$ \1\&{of}\6 +\4$\\{pair\_type},\39\\{independent}$: \37\&{begin} \37$\|q\K\\{cur\_exp}$;\5 +$\\{make\_exp\_copy}(\|q)$;\6 +\&{if} $\\{cur\_type}=\\{dependent}$ \1\&{then}\5 +$\\{negate\_dep\_list}(\\{dep\_list}(\\{cur\_exp}))$\6 +\4\&{else} \&{if} $\\{cur\_type}=\\{pair\_type}$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{value}(\\{cur\_exp})$;\6 +\&{if} $\\{type}(\\{x\_part\_loc}(\|p))=\\{known}$ \1\&{then}\5 +$\\{negate}(\\{value}(\\{x\_part\_loc}(\|p)))$\6 +\4\&{else} $\\{negate\_dep\_list}(\\{dep\_list}(\\{x\_part\_loc}(\|p)))$;\2\6 +\&{if} $\\{type}(\\{y\_part\_loc}(\|p))=\\{known}$ \1\&{then}\5 +$\\{negate}(\\{value}(\\{y\_part\_loc}(\|p)))$\6 +\4\&{else} $\\{negate\_dep\_list}(\\{dep\_list}(\\{y\_part\_loc}(\|p)))$;\2\6 +\&{end};\C{if $\\{cur\_type}=\\{known}$ then $\\{cur\_exp}=0$}\2\2\6 +$\\{recycle\_value}(\|q)$;\5 +$\\{free\_node}(\|q,\39\\{value\_node\_size})$;\6 +\&{end};\6 +\4$\\{dependent},\39\\{proto\_dependent}$: \37$\\{negate\_dep\_list}(\\{dep% +\_list}(\\{cur\_exp}))$;\6 +\4\\{known}: \37$\\{negate}(\\{cur\_exp})$;\6 +\4\\{picture\_type}: \37$\\{negate\_edges}(\\{cur\_exp})$;\6 +\4\&{othercases} \37$\\{bad\_unary}(\\{minus})$\2\6 +\&{endcases}\par +\U898.\fi + +\M904. \P$\X899:Declare unary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{negate\_dep\_list}(\|p:\\{pointer})$;\6 +\4\&{label} \37\\{exit};\2\6 +\&{begin} \37\~ \1\&{loop}\ \&{begin} \37$\\{negate}(\\{value}(\|p))$;\6 +\&{if} $\\{info}(\|p)=\\{null}$ \1\&{then}\5 +\&{return};\2\6 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M905. \P$\X905:Additional cases of unary operators\X\S$\6 +\4\\{not\_op}: \37\&{if} $\\{cur\_type}\I\\{boolean\_type}$ \1\&{then}\5 +$\\{bad\_unary}(\\{not\_op})$\6 +\4\&{else} $\\{cur\_exp}\K\\{true\_code}+\\{false\_code}-\\{cur\_exp}$;\2\par +\As906, 907, 909, 912, 915, 917, 918, 920\ETs921. +\U898.\fi + +\M906. \P\D \37$\\{three\_sixty\_units}\S23592960$\C{that's $360\ast\\{unity}$}% +\par +\P\D \37$\\{boolean\_reset}(\#)\S$\1\6 +\&{if} $\#$ \1\&{then}\5 +$\\{cur\_exp}\K\\{true\_code}$\ \&{else} $\\{cur\_exp}\K\\{false\_code}$\2\2\par +\Y\P$\4\X905:Additional cases of unary operators\X\mathrel{+}\S$\6 +\4$\\{sqrt\_op},\39\\{m\_exp\_op},\39\\{m\_log\_op},\39\\{sin\_d\_op},\39\\{cos% +\_d\_op},\39\\{floor\_op},\39\\{uniform\_deviate},\39\\{odd\_op},\39\\{char% +\_exists\_op}$: \37\hbox{}\6 +\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\5 +$\\{bad\_unary}(\|c)$\6 +\4\&{else} \&{case} $\|c$ \1\&{of}\6 +\4\\{sqrt\_op}: \37$\\{cur\_exp}\K\\{square\_rt}(\\{cur\_exp})$;\6 +\4\\{m\_exp\_op}: \37$\\{cur\_exp}\K\\{m\_exp}(\\{cur\_exp})$;\6 +\4\\{m\_log\_op}: \37$\\{cur\_exp}\K\\{m\_log}(\\{cur\_exp})$;\6 +\4$\\{sin\_d\_op},\39\\{cos\_d\_op}$: \37\&{begin} \37$\\{n\_sin\_cos}((\\{cur% +\_exp}\mathbin{\&{mod}}\\{three\_sixty\_units})\ast16)$;\6 +\&{if} $\|c=\\{sin\_d\_op}$ \1\&{then}\5 +$\\{cur\_exp}\K\\{round\_fraction}(\\{n\_sin})$\6 +\4\&{else} $\\{cur\_exp}\K\\{round\_fraction}(\\{n\_cos})$;\2\6 +\&{end};\6 +\4\\{floor\_op}: \37$\\{cur\_exp}\K\\{floor\_scaled}(\\{cur\_exp})$;\6 +\4\\{uniform\_deviate}: \37$\\{cur\_exp}\K\\{unif\_rand}(\\{cur\_exp})$;\6 +\4\\{odd\_op}: \37\&{begin} \37$\\{boolean\_reset}(\\{odd}(\\{round\_unscaled}(% +\\{cur\_exp})))$;\5 +$\\{cur\_type}\K\\{boolean\_type}$;\6 +\&{end};\6 +\4\\{char\_exists\_op}: \37\X1181:Determine if a character has been shipped out% +\X;\2\6 +\&{end};\C{there are no other cases}\2\par +\fi + +\M907. \P$\X905:Additional cases of unary operators\X\mathrel{+}\S$\6 +\4\\{angle\_op}: \37\&{if} $\\{nice\_pair}(\\{cur\_exp},\39\\{cur\_type})$ \1% +\&{then}\6 +\&{begin} \37$\|p\K\\{value}(\\{cur\_exp})$;\5 +$\|x\K\\{n\_arg}(\\{value}(\\{x\_part\_loc}(\|p)),\39\\{value}(\\{y\_part% +\_loc}(\|p)))$;\6 +\&{if} $\|x\G0$ \1\&{then}\5 +$\\{flush\_cur\_exp}((\|x+8)\mathbin{\&{div}}16)$\6 +\4\&{else} $\\{flush\_cur\_exp}(-((-\|x+8)\mathbin{\&{div}}16))$;\2\6 +\&{end}\6 +\4\&{else} $\\{bad\_unary}(\\{angle\_op})$;\2\par +\fi + +\M908. If the current expression is a pair, but the context wants it to +be a path, we call \\{pair\_to\_path}. + +\Y\P$\4\X899:Declare unary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{pair\_to\_path};\2\6 +\&{begin} \37$\\{cur\_exp}\K\\{new\_knot}$;\5 +$\\{cur\_type}\K\\{path\_type}$;\6 +\&{end};\par +\fi + +\M909. \P$\X905:Additional cases of unary operators\X\mathrel{+}\S$\6 +\4$\\{x\_part},\39\\{y\_part}$: \37\&{if} $(\\{cur\_type}\L\\{pair\_type})\W(% +\\{cur\_type}\G\\{transform\_type})$ \1\&{then}\5 +$\\{take\_part}(\|c)$\6 +\4\&{else} $\\{bad\_unary}(\|c)$;\2\6 +\4$\\{xx\_part},\39\\{xy\_part},\39\\{yx\_part},\39\\{yy\_part}$: \37\&{if} $% +\\{cur\_type}=\\{transform\_type}$ \1\&{then}\5 +$\\{take\_part}(\|c)$\6 +\4\&{else} $\\{bad\_unary}(\|c)$;\2\par +\fi + +\M910. In the following procedure, \\{cur\_exp} points to a capsule, which +points to +a big node. We want to delete all but one part of the big node. + +\Y\P$\4\X899:Declare unary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{take\_part}(\|c:\\{quarterword})$;\6 +\4\&{var} \37\|p: \37\\{pointer};\C{the big node}\2\6 +\&{begin} \37$\|p\K\\{value}(\\{cur\_exp})$;\5 +$\\{value}(\\{temp\_val})\K\|p$;\5 +$\\{type}(\\{temp\_val})\K\\{cur\_type}$;\5 +$\\{link}(\|p)\K\\{temp\_val}$;\5 +$\\{free\_node}(\\{cur\_exp},\39\\{value\_node\_size})$;\5 +$\\{make\_exp\_copy}(\|p+2\ast(\|c-\\{x\_part}))$;\5 +$\\{recycle\_value}(\\{temp\_val})$;\6 +\&{end};\par +\fi + +\M911. \P$\X176:Initialize table entries (done by \.{INIMF} only)\X\mathrel{+}% +\S$\6 +$\\{name\_type}(\\{temp\_val})\K\\{capsule}$;\par +\fi + +\M912. \P$\X905:Additional cases of unary operators\X\mathrel{+}\S$\6 +\4\\{char\_op}: \37\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\5 +$\\{bad\_unary}(\\{char\_op})$\6 +\4\&{else} \&{begin} \37$\\{cur\_exp}\K\\{round\_unscaled}(\\{cur\_exp})% +\mathbin{\&{mod}}256$;\5 +$\\{cur\_type}\K\\{string\_type}$;\6 +\&{if} $\\{cur\_exp}<0$ \1\&{then}\5 +$\\{cur\_exp}\K\\{cur\_exp}+256$;\2\6 +\&{if} $\\{length}(\\{cur\_exp})\I1$ \1\&{then}\6 +\&{begin} \37$\\{str\_room}(1)$;\5 +$\\{append\_char}(\\{cur\_exp})$;\5 +$\\{cur\_exp}\K\\{make\_string}$;\6 +\&{end};\2\6 +\&{end};\2\6 +\4\\{decimal}: \37\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\5 +$\\{bad\_unary}(\\{decimal})$\6 +\4\&{else} \&{begin} \37$\\{old\_setting}\K\\{selector}$;\5 +$\\{selector}\K\\{new\_string}$;\5 +$\\{print\_scaled}(\\{cur\_exp})$;\5 +$\\{cur\_exp}\K\\{make\_string}$;\5 +$\\{selector}\K\\{old\_setting}$;\5 +$\\{cur\_type}\K\\{string\_type}$;\6 +\&{end};\2\6 +\4$\\{oct\_op},\39\\{hex\_op},\39\\{ASCII\_op}$: \37\&{if} $\\{cur\_type}\I% +\\{string\_type}$ \1\&{then}\5 +$\\{bad\_unary}(\|c)$\6 +\4\&{else} $\\{str\_to\_num}(\|c)$;\2\par +\fi + +\M913. \P$\X899:Declare unary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{str\_to\_num}(\|c:\\{quarterword})$;\C{converts a +string to a number}\6 +\4\&{var} \37\|n: \37\\{integer};\C{accumulator}\6 +\|m: \37\\{ASCII\_code};\C{current character}\6 +\|k: \37\\{pool\_pointer};\C{index into \\{str\_pool}}\6 +\|b: \37$8\to16$;\C{radix of conversion}\6 +\\{bad\_char}: \37\\{boolean};\C{did the string contain an invalid digit?}\2\6 +\&{begin} \37\&{if} $\|c=\\{ASCII\_op}$ \1\&{then}\6 +\&{if} $\\{length}(\\{cur\_exp})=0$ \1\&{then}\5 +$\|n\K-1$\6 +\4\&{else} $\|n\K\\{so}(\\{str\_pool}[\\{str\_start}[\\{cur\_exp}]])$\2\6 +\4\&{else} \&{begin} \37\&{if} $\|c=\\{oct\_op}$ \1\&{then}\5 +$\|b\K8$\ \&{else} $\|b\K16$;\2\6 +$\|n\K0$;\5 +$\\{bad\_char}\K\\{false}$;\6 +\&{for} $\|k\K\\{str\_start}[\\{cur\_exp}]\mathrel{\&{to}}\\{str\_start}[\\{cur% +\_exp}+1]-1$ \1\&{do}\6 +\&{begin} \37$\|m\K\\{so}(\\{str\_pool}[\|k])$;\6 +\&{if} $(\|m\G\.{"0"})\W(\|m\L\.{"9"})$ \1\&{then}\5 +$\|m\K\|m-\.{"0"}$\6 +\4\&{else} \&{if} $(\|m\G\.{"A"})\W(\|m\L\.{"F"})$ \1\&{then}\5 +$\|m\K\|m-\.{"A"}+10$\6 +\4\&{else} \&{if} $(\|m\G\.{"a"})\W(\|m\L\.{"f"})$ \1\&{then}\5 +$\|m\K\|m-\.{"a"}+10$\6 +\4\&{else} \&{begin} \37$\\{bad\_char}\K\\{true}$;\5 +$\|m\K0$;\6 +\&{end};\2\2\2\6 +\&{if} $\|m\G\|b$ \1\&{then}\6 +\&{begin} \37$\\{bad\_char}\K\\{true}$;\5 +$\|m\K0$;\6 +\&{end};\2\6 +\&{if} $\|n<32768\mathbin{\&{div}}\|b$ \1\&{then}\5 +$\|n\K\|n\ast\|b+\|m$\ \&{else} $\|n\K32767$;\2\6 +\&{end};\2\6 +\X914:Give error messages if \\{bad\_char} or $\|n\G4096$\X;\6 +\&{end};\2\6 +$\\{flush\_cur\_exp}(\|n\ast\\{unity})$;\6 +\&{end};\par +\fi + +\M914. \P$\X914:Give error messages if \\{bad\_char} or $\|n\G4096$\X\S$\6 +\&{if} $\\{bad\_char}$ \1\&{then}\6 +\&{begin} \37$\\{exp\_err}(\.{"String\ contains\ illegal\ digits"})$;\6 +\&{if} $\|c=\\{oct\_op}$ \1\&{then}\5 +$\\{help1}(\.{"I\ zeroed\ out\ characters\ that\ weren\'t\ in\ the\ range\ +0..7."})$\6 +\4\&{else} $\\{help1}(\.{"I\ zeroed\ out\ characters\ that\ weren\'t\ hex\ +digits."})$;\2\6 +\\{put\_get\_error};\6 +\&{end};\2\6 +\&{if} $\|n>4095$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"Number\ too\ large\ ("})$;\5 +$\\{print\_int}(\|n)$;\5 +$\\{print\_char}(\.{")"})$;\5 +$\\{help1}(\.{"I\ have\ trouble\ with\ numbers\ greater\ than\ 4095;\ watch\ +out."})$;\5 +\\{put\_get\_error};\6 +\&{end}\2\par +\U913.\fi + +\M915. The length operation is somewhat unusual in that it applies to a variety +of different types of operands. + +\Y\P$\4\X905:Additional cases of unary operators\X\mathrel{+}\S$\6 +\4\\{length\_op}: \37\&{if} $\\{cur\_type}=\\{string\_type}$ \1\&{then}\5 +$\\{flush\_cur\_exp}(\\{length}(\\{cur\_exp})\ast\\{unity})$\6 +\4\&{else} \&{if} $\\{cur\_type}=\\{path\_type}$ \1\&{then}\5 +$\\{flush\_cur\_exp}(\\{path\_length})$\6 +\4\&{else} \&{if} $\\{cur\_type}=\\{known}$ \1\&{then}\5 +$\\{cur\_exp}\K\\{abs}(\\{cur\_exp})$\6 +\4\&{else} \&{if} $\\{nice\_pair}(\\{cur\_exp},\39\\{cur\_type})$ \1\&{then}\5 +$\\{flush\_cur\_exp}(\\{pyth\_add}(\\{value}(\\{x\_part\_loc}(\\{value}(\\{cur% +\_exp}))),\39\30\\{value}(\\{y\_part\_loc}(\\{value}(\\{cur\_exp})))))$\6 +\4\&{else} $\\{bad\_unary}(\|c)$;\2\2\2\2\par +\fi + +\M916. \P$\X899:Declare unary action procedures\X\mathrel{+}\S$\6 +\4\&{function}\1\ \37\\{path\_length}: \37\\{scaled};\C{computes the length of +the current path}\6 +\4\&{var} \37\|n: \37\\{scaled};\C{the path length so far}\6 +\|p: \37\\{pointer};\C{traverser}\2\6 +\&{begin} \37$\|p\K\\{cur\_exp}$;\6 +\&{if} $\\{left\_type}(\|p)=\\{endpoint}$ \1\&{then}\5 +$\|n\K-\\{unity}$\ \&{else} $\|n\K0$;\2\6 +\1\&{repeat} \37$\|p\K\\{link}(\|p)$;\5 +$\|n\K\|n+\\{unity}$;\6 +\4\&{until}\5 +$\|p=\\{cur\_exp}$;\2\6 +$\\{path\_length}\K\|n$;\6 +\&{end};\par +\fi + +\M917. The turning number is computed only with respect to null pens. A +different +pen might affect the turning number, in degenerate cases, because autorounding +will produce a slightly different path, or because excessively large +coordinates +might be truncated. + +\Y\P$\4\X905:Additional cases of unary operators\X\mathrel{+}\S$\6 +\4\\{turning\_op}: \37\&{if} $\\{cur\_type}=\\{pair\_type}$ \1\&{then}\5 +$\\{flush\_cur\_exp}(0)$\6 +\4\&{else} \&{if} $\\{cur\_type}\I\\{path\_type}$ \1\&{then}\5 +$\\{bad\_unary}(\\{turning\_op})$\6 +\4\&{else} \&{if} $\\{left\_type}(\\{cur\_exp})=\\{endpoint}$ \1\&{then}\5 +$\\{flush\_cur\_exp}(0)$\C{not a cyclic path}\6 +\4\&{else} \&{begin} \37$\\{cur\_pen}\K\\{null\_pen}$;\5 +$\\{cur\_path\_type}\K\\{contour\_code}$;\5 +$\\{cur\_exp}\K\\{make\_spec}(\\{cur\_exp},\39\\{fraction\_one}-\\{half% +\_unit}-1-\\{el\_gordo},\390)$;\5 +$\\{flush\_cur\_exp}(\\{turning\_number}\ast\\{unity})$;\C{convert to % +\\{scaled}}\6 +\&{end};\2\2\2\par +\fi + +\M918. \P\D \37$\\{type\_test\_end}\S\\{flush\_cur\_exp}(\\{true\_code})$\6 +\4\&{else} \37$\\{flush\_cur\_exp}(\\{false\_code})$;\5 +$\\{cur\_type}\K\\{boolean\_type}$; \6 +\&{end} \par +\P\D $\\{type\_range\_end}(\#)\S(\\{cur\_type}\L\#)$ \&{then} \\{type\_test% +\_end}\par +\P\D $\\{type\_range}(\#)\S$ \6 +\&{begin} \6 +\&{if} $(\\{cur\_type}\G\#)\W\\{type\_range\_end}$\par +\P\D $\\{type\_test}(\#)\S$ \6 +\&{begin} \37\&{if} $\\{cur\_type}=\#$ \1\&{then}\5 +\\{type\_test\_end}\2\par +\Y\P$\4\X905:Additional cases of unary operators\X\mathrel{+}\S$\6 +\4\\{boolean\_type}: \37$\\{type\_range}(\\{boolean\_type})(\\{unknown% +\_boolean})$;\6 +\4\\{string\_type}: \37$\\{type\_range}(\\{string\_type})(\\{unknown% +\_string})$;\6 +\4\\{pen\_type}: \37$\\{type\_range}(\\{pen\_type})(\\{future\_pen})$;\6 +\4\\{path\_type}: \37$\\{type\_range}(\\{path\_type})(\\{unknown\_path})$;\6 +\4\\{picture\_type}: \37$\\{type\_range}(\\{picture\_type})(\\{unknown% +\_picture})$;\6 +\4$\\{transform\_type},\39\\{pair\_type}$: \37$\\{type\_test}(\|c)$;\6 +\4\\{numeric\_type}: \37$\\{type\_range}(\\{known})(\\{independent})$;\6 +\4$\\{known\_op},\39\\{unknown\_op}$: \37$\\{test\_known}(\|c)$;\par +\fi + +\M919. \P$\X899:Declare unary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{test\_known}(\|c:\\{quarterword})$;\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37\|b: \37$\\{true\_code}\to\\{false\_code}$;\C{is the current +expression known?}\6 +$\|p,\39\|q$: \37\\{pointer};\C{locations in a big node}\2\6 +\&{begin} \37$\|b\K\\{false\_code}$;\6 +\&{case} $\\{cur\_type}$ \1\&{of}\6 +\4$\\{vacuous},\39\\{boolean\_type},\39\\{string\_type},\39\\{pen\_type},\39% +\\{future\_pen},\39\\{path\_type},\39\\{picture\_type},\39\\{known}$: \37$\|b\K% +\\{true\_code}$;\6 +\4$\\{transform\_type},\39\\{pair\_type}$: \37\&{begin} \37$\|p\K\\{value}(% +\\{cur\_exp})$;\5 +$\|q\K\|p+\\{big\_node\_size}[\\{cur\_type}]$;\6 +\1\&{repeat} \37$\|q\K\|q-2$;\6 +\&{if} $\\{type}(\|q)\I\\{known}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +\4\&{until}\5 +$\|q=\|p$;\2\6 +$\|b\K\\{true\_code}$;\6 +\4\\{done}: \37\&{end};\6 +\4\&{othercases} \37\\{do\_nothing}\2\6 +\&{endcases};\6 +\&{if} $\|c=\\{known\_op}$ \1\&{then}\5 +$\\{flush\_cur\_exp}(\|b)$\6 +\4\&{else} $\\{flush\_cur\_exp}(\\{true\_code}+\\{false\_code}-\|b)$;\2\6 +$\\{cur\_type}\K\\{boolean\_type}$;\6 +\&{end};\par +\fi + +\M920. \P$\X905:Additional cases of unary operators\X\mathrel{+}\S$\6 +\4\\{cycle\_op}: \37\&{begin} \37\&{if} $\\{cur\_type}\I\\{path\_type}$ \1% +\&{then}\5 +$\\{flush\_cur\_exp}(\\{false\_code})$\6 +\4\&{else} \&{if} $\\{left\_type}(\\{cur\_exp})\I\\{endpoint}$ \1\&{then}\5 +$\\{flush\_cur\_exp}(\\{true\_code})$\6 +\4\&{else} $\\{flush\_cur\_exp}(\\{false\_code})$;\2\2\6 +$\\{cur\_type}\K\\{boolean\_type}$;\6 +\&{end};\par +\fi + +\M921. \P$\X905:Additional cases of unary operators\X\mathrel{+}\S$\6 +\4\\{make\_pen\_op}: \37\&{begin} \37\&{if} $\\{cur\_type}=\\{pair\_type}$ \1% +\&{then}\5 +\\{pair\_to\_path};\2\6 +\&{if} $\\{cur\_type}=\\{path\_type}$ \1\&{then}\5 +$\\{cur\_type}\K\\{future\_pen}$\6 +\4\&{else} $\\{bad\_unary}(\\{make\_pen\_op})$;\2\6 +\&{end};\6 +\4\\{make\_path\_op}: \37\&{begin} \37\&{if} $\\{cur\_type}=\\{future\_pen}$ \1% +\&{then}\5 +\\{materialize\_pen};\2\6 +\&{if} $\\{cur\_type}\I\\{pen\_type}$ \1\&{then}\5 +$\\{bad\_unary}(\\{make\_path\_op})$\6 +\4\&{else} \&{begin} \37$\\{flush\_cur\_exp}(\\{make\_path}(\\{cur\_exp}))$;\5 +$\\{cur\_type}\K\\{path\_type}$;\6 +\&{end};\2\6 +\&{end};\6 +\4\\{total\_weight\_op}: \37\&{if} $\\{cur\_type}\I\\{picture\_type}$ \1% +\&{then}\5 +$\\{bad\_unary}(\\{total\_weight\_op})$\6 +\4\&{else} $\\{flush\_cur\_exp}(\\{total\_weight}(\\{cur\_exp}))$;\2\6 +\4\\{reverse}: \37\&{if} $\\{cur\_type}=\\{path\_type}$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{htap\_ypoc}(\\{cur\_exp})$;\6 +\&{if} $\\{right\_type}(\|p)=\\{endpoint}$ \1\&{then}\5 +$\|p\K\\{link}(\|p)$;\2\6 +$\\{toss\_knot\_list}(\\{cur\_exp})$;\5 +$\\{cur\_exp}\K\|p$;\6 +\&{end}\6 +\4\&{else} \&{if} $\\{cur\_type}=\\{pair\_type}$ \1\&{then}\5 +\\{pair\_to\_path}\6 +\4\&{else} $\\{bad\_unary}(\\{reverse})$;\2\2\par +\fi + +\M922. Finally, we have the operations that combine a capsule~\|p +with the current expression. + +\Y\P\hbox{\4}\X923:Declare binary action procedures\X\6 +\4\&{procedure}\1\ \37$\\{do\_binary}(\|p:\\{pointer};\,\35\|c:% +\\{quarterword})$;\6 +\4\&{label} \37$\\{done},\39\\{done1},\39\\{exit}$;\6 +\4\&{var} \37$\|q,\39\|r,\39\\{rr}$: \37\\{pointer};\C{for list manipulation}\6 +$\\{old\_p},\39\\{old\_exp}$: \37\\{pointer};\C{capsules to recycle}\6 +\|v: \37\\{integer};\C{for numeric manipulation}\2\6 +\&{begin} \37\\{check\_arith};\6 +\&{if} $\\{internal}[\\{tracing\_commands}]>\\{two}$ \1\&{then}\5 +\X924:Trace the current binary operation\X;\2\6 +\X926:Sidestep \\{independent} cases in capsule \|p\X;\6 +\X927:Sidestep \\{independent} cases in the current expression\X;\6 +\&{case} $\|c$ \1\&{of}\6 +\4$\\{plus},\39\\{minus}$: \37\X929:Add or subtract the current expression from +\|p\X;\6 +\hbox{\4}\X936:Additional cases of binary operators\X\2\6 +\&{end};\C{there are no other cases}\6 +$\\{recycle\_value}(\|p)$;\5 +$\\{free\_node}(\|p,\39\\{value\_node\_size})$;\C{\&{return} to avoid this}\6 +\4\\{exit}: \37\\{check\_arith};\5 +\X925:Recycle any sidestepped \\{independent} capsules\X;\6 +\&{end};\par +\fi + +\M923. \P$\X923:Declare binary action procedures\X\S$\6 +\4\&{procedure}\1\ \37$\\{bad\_binary}(\|p:\\{pointer};\,\35\|c:% +\\{quarterword})$;\2\6 +\&{begin} \37$\\{disp\_err}(\|p,\39\.{""})$;\5 +$\\{exp\_err}(\.{"Not\ implemented:\ "})$;\6 +\&{if} $\|c\G\\{min\_of}$ \1\&{then}\5 +$\\{print\_op}(\|c)$;\2\6 +$\\{print\_known\_or\_unknown\_type}(\\{type}(\|p),\39\|p)$;\6 +\&{if} $\|c\G\\{min\_of}$ \1\&{then}\5 +$\\{print}(\.{"of"})$\ \&{else} $\\{print\_op}(\|c)$;\2\6 +$\\{print\_known\_or\_unknown\_type}(\\{cur\_type},\39\\{cur\_exp})$;\6 +$\\{help3}(\.{"I\'m\ afraid\ I\ don\'t\ know\ how\ to\ apply\ that\ operation\ +to\ that"})$\6 +$(\.{"combination\ of\ types.\ Continue,\ and\ I\'ll\ return\ the\ second"})$\6 +$(\.{"argument\ (see\ above)\ as\ the\ result\ of\ the\ operation."})$;\5 +\\{put\_get\_error};\6 +\&{end};\par +\As928, 930, 943, 946, 949, 953, 960, 961, 962, 963, 966, 976, 977, 978, 982, +984\ETs985. +\U922.\fi + +\M924. \P$\X924:Trace the current binary operation\X\S$\6 +\&{begin} \37\\{begin\_diagnostic};\5 +$\\{print\_nl}(\.{"\{("})$;\5 +$\\{print\_exp}(\|p,\390)$;\C{show the operand, but not verbosely}\6 +$\\{print\_char}(\.{")"})$;\5 +$\\{print\_op}(\|c)$;\5 +$\\{print\_char}(\.{"("})$;\6 +$\\{print\_exp}(\\{null},\390)$;\5 +$\\{print}(\.{")\}"})$;\5 +$\\{end\_diagnostic}(\\{false})$;\6 +\&{end}\par +\U922.\fi + +\M925. Several of the binary operations are potentially complicated by the +fact that \\{independent} values can sneak into capsules. For example, +we've seen an instance of this difficulty in the unary operation +of negation. In order to reduce the number of cases that need to be +handled, we first change the two operands (if necessary) +to rid them of \\{independent} components. The original operands are +put into capsules called \\{old\_p} and \\{old\_exp}, which will be +recycled after the binary operation has been safely carried out. + +\Y\P$\4\X925:Recycle any sidestepped \\{independent} capsules\X\S$\6 +\&{if} $\\{old\_p}\I\\{null}$ \1\&{then}\6 +\&{begin} \37$\\{recycle\_value}(\\{old\_p})$;\5 +$\\{free\_node}(\\{old\_p},\39\\{value\_node\_size})$;\6 +\&{end};\2\6 +\&{if} $\\{old\_exp}\I\\{null}$ \1\&{then}\6 +\&{begin} \37$\\{recycle\_value}(\\{old\_exp})$;\5 +$\\{free\_node}(\\{old\_exp},\39\\{value\_node\_size})$;\6 +\&{end}\2\par +\U922.\fi + +\M926. A big node is considered to be ``tarnished'' if it contains at least one +independent component. We will define a simple function called `\\{tarnished}' +that returns \\{null} if and only if its argument is not tarnished. + +\Y\P$\4\X926:Sidestep \\{independent} cases in capsule \|p\X\S$\6 +\&{case} $\\{type}(\|p)$ \1\&{of}\6 +\4$\\{transform\_type},\39\\{pair\_type}$: \37$\\{old\_p}\K\\{tarnished}(\|p)$;% +\6 +\4\\{independent}: \37$\\{old\_p}\K\\{void}$;\6 +\4\&{othercases} \37$\\{old\_p}\K\\{null}$\2\6 +\&{endcases};\6 +\&{if} $\\{old\_p}\I\\{null}$ \1\&{then}\6 +\&{begin} \37$\|q\K\\{stash\_cur\_exp}$;\5 +$\\{old\_p}\K\|p$;\5 +$\\{make\_exp\_copy}(\\{old\_p})$;\5 +$\|p\K\\{stash\_cur\_exp}$;\5 +$\\{unstash\_cur\_exp}(\|q)$;\6 +\&{end};\2\par +\U922.\fi + +\M927. \P$\X927:Sidestep \\{independent} cases in the current expression\X\S$\6 +\&{case} $\\{cur\_type}$ \1\&{of}\6 +\4$\\{transform\_type},\39\\{pair\_type}$: \37$\\{old\_exp}\K\\{tarnished}(% +\\{cur\_exp})$;\6 +\4\\{independent}: \37$\\{old\_exp}\K\\{void}$;\6 +\4\&{othercases} \37$\\{old\_exp}\K\\{null}$\2\6 +\&{endcases};\6 +\&{if} $\\{old\_exp}\I\\{null}$ \1\&{then}\6 +\&{begin} \37$\\{old\_exp}\K\\{cur\_exp}$;\5 +$\\{make\_exp\_copy}(\\{old\_exp})$;\6 +\&{end}\2\par +\U922.\fi + +\M928. \P$\X923:Declare binary action procedures\X\mathrel{+}\S$\6 +\4\&{function}\1\ \37$\\{tarnished}(\|p:\\{pointer})$: \37\\{pointer};\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37\|q: \37\\{pointer};\C{beginning of the big node}\6 +\|r: \37\\{pointer};\C{current position in the big node}\2\6 +\&{begin} \37$\|q\K\\{value}(\|p)$;\5 +$\|r\K\|q+\\{big\_node\_size}[\\{type}(\|p)]$;\6 +\1\&{repeat} \37$\|r\K\|r-2$;\6 +\&{if} $\\{type}(\|r)=\\{independent}$ \1\&{then}\6 +\&{begin} \37$\\{tarnished}\K\\{void}$;\5 +\&{return};\6 +\&{end};\2\6 +\4\&{until}\5 +$\|r=\|q$;\2\6 +$\\{tarnished}\K\\{null}$;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M929. \P$\X929:Add or subtract the current expression from \|p\X\S$\6 +\&{if} $(\\{cur\_type}<\\{pair\_type})\V(\\{type}(\|p)<\\{pair\_type})$ \1% +\&{then}\6 +\&{if} $(\\{cur\_type}=\\{picture\_type})\W(\\{type}(\|p)=\\{picture\_type})$ % +\1\&{then}\6 +\&{begin} \37\&{if} $\|c=\\{minus}$ \1\&{then}\5 +$\\{negate\_edges}(\\{cur\_exp})$;\2\6 +$\\{cur\_edges}\K\\{cur\_exp}$;\5 +$\\{merge\_edges}(\\{value}(\|p))$;\6 +\&{end}\6 +\4\&{else} $\\{bad\_binary}(\|p,\39\|c)$\2\6 +\4\&{else} \&{if} $\\{cur\_type}=\\{pair\_type}$ \1\&{then}\6 +\&{if} $\\{type}(\|p)\I\\{pair\_type}$ \1\&{then}\5 +$\\{bad\_binary}(\|p,\39\|c)$\6 +\4\&{else} \&{begin} \37$\|q\K\\{value}(\|p)$;\5 +$\|r\K\\{value}(\\{cur\_exp})$;\5 +$\\{add\_or\_subtract}(\\{x\_part\_loc}(\|q),\39\\{x\_part\_loc}(\|r),\39\|c)$;% +\5 +$\\{add\_or\_subtract}(\\{y\_part\_loc}(\|q),\39\\{y\_part\_loc}(\|r),\39\|c)$;% +\6 +\&{end}\2\6 +\4\&{else} \&{if} $\\{type}(\|p)=\\{pair\_type}$ \1\&{then}\5 +$\\{bad\_binary}(\|p,\39\|c)$\6 +\4\&{else} $\\{add\_or\_subtract}(\|p,\39\\{null},\39\|c)$\2\2\2\par +\U922.\fi + +\M930. The first argument to \\{add\_or\_subtract} is the location of a value +node +in a capsule or pair node that will soon be recycled. The second argument +is either a location within a pair or transform node of \\{cur\_exp}, +or it is null (which means that \\{cur\_exp} itself should be the second +argument). The third argument is either \\{plus} or \\{minus}. + +The sum or difference of the numeric quantities will replace the second +operand. Arithmetic overflow may go undetected; users aren't supposed to +be monkeying around with really big values. + +\Y\P$\4\X923:Declare binary action procedures\X\mathrel{+}\S$\6 +\hbox{\4}\X935:Declare the procedure called \\{dep\_finish}\X\6 +\4\&{procedure}\1\ \37$\\{add\_or\_subtract}(\|p,\39\|q:\\{pointer};\,\35\|c:% +\\{quarterword})$;\6 +\4\&{label} \37$\\{done},\39\\{exit}$;\6 +\4\&{var} \37$\|s,\39\|t$: \37\\{small\_number};\C{operand types}\6 +\|r: \37\\{pointer};\C{list traverser}\6 +\|v: \37\\{integer};\C{second operand value}\2\6 +\&{begin} \37\&{if} $\|q=\\{null}$ \1\&{then}\6 +\&{begin} \37$\|t\K\\{cur\_type}$;\6 +\&{if} $\|t<\\{dependent}$ \1\&{then}\5 +$\|v\K\\{cur\_exp}$\ \&{else} $\|v\K\\{dep\_list}(\\{cur\_exp})$;\2\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|t\K\\{type}(\|q)$;\6 +\&{if} $\|t<\\{dependent}$ \1\&{then}\5 +$\|v\K\\{value}(\|q)$\ \&{else} $\|v\K\\{dep\_list}(\|q)$;\2\6 +\&{end};\2\6 +\&{if} $\|t=\\{known}$ \1\&{then}\6 +\&{begin} \37\&{if} $\|c=\\{minus}$ \1\&{then}\5 +$\\{negate}(\|v)$;\2\6 +\&{if} $\\{type}(\|p)=\\{known}$ \1\&{then}\6 +\&{begin} \37$\|v\K\\{slow\_add}(\\{value}(\|p),\39\|v)$;\6 +\&{if} $\|q=\\{null}$ \1\&{then}\5 +$\\{cur\_exp}\K\|v$\ \&{else} $\\{value}(\|q)\K\|v$;\2\6 +\&{return};\6 +\&{end};\2\6 +\X931:Add a known value to the constant term of $\\{dep\_list}(\|p)$\X;\6 +\&{end}\6 +\4\&{else} \&{begin} \37\&{if} $\|c=\\{minus}$ \1\&{then}\5 +$\\{negate\_dep\_list}(\|v)$;\2\6 +\X932:Add operand \|p to the dependency list \|v\X;\6 +\&{end};\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M931. \P$\X931:Add a known value to the constant term of $\\{dep\_list}(\|p)$% +\X\S$\6 +$\|r\K\\{dep\_list}(\|p)$;\6 +\&{while} $\\{info}(\|r)\I\\{null}$ \1\&{do}\5 +$\|r\K\\{link}(\|r)$;\2\6 +$\\{value}(\|r)\K\\{slow\_add}(\\{value}(\|r),\39\|v)$;\6 +\&{if} $\|q=\\{null}$ \1\&{then}\6 +\&{begin} \37$\|q\K\\{get\_node}(\\{value\_node\_size})$;\5 +$\\{cur\_exp}\K\|q$;\5 +$\\{cur\_type}\K\\{type}(\|p)$;\5 +$\\{name\_type}(\|q)\K\\{capsule}$;\6 +\&{end};\2\6 +$\\{dep\_list}(\|q)\K\\{dep\_list}(\|p)$;\5 +$\\{type}(\|q)\K\\{type}(\|p)$;\5 +$\\{prev\_dep}(\|q)\K\\{prev\_dep}(\|p)$;\5 +$\\{link}(\\{prev\_dep}(\|p))\K\|q$;\5 +$\\{type}(\|p)\K\\{known}$;\C{this will keep the recycler from collecting +non-garbage}\par +\U930.\fi + +\M932. We prefer \\{dependent} lists to \\{proto\_dependent} ones, because it +is +nice to retain the extra accuracy of \\{fraction} coefficients. +But we have to handle both kinds, and mixtures too. + +\Y\P$\4\X932:Add operand \|p to the dependency list \|v\X\S$\6 +\&{if} $\\{type}(\|p)=\\{known}$ \1\&{then}\5 +\X933:Add the known $\\{value}(\|p)$ to the constant term of \|v\X\6 +\4\&{else} \&{begin} \37$\|s\K\\{type}(\|p)$;\5 +$\|r\K\\{dep\_list}(\|p)$;\6 +\&{if} $\|t=\\{dependent}$ \1\&{then}\6 +\&{begin} \37\&{if} $\|s=\\{dependent}$ \1\&{then}\6 +\&{if} $\\{max\_coef}(\|r)+\\{max\_coef}(\|v)<\\{coef\_bound}$ \1\&{then}\6 +\&{begin} \37$\|v\K\\{p\_plus\_q}(\|v,\39\|r,\39\\{dependent})$;\5 +\&{goto} \37\\{done};\6 +\&{end};\C{\\{fix\_needed} will necessarily be false}\2\2\6 +$\|t\K\\{proto\_dependent}$;\5 +$\|v\K\\{p\_over\_v}(\|v,\39\\{unity},\39\\{dependent},\39\\{proto% +\_dependent})$;\6 +\&{end};\2\6 +\&{if} $\|s=\\{proto\_dependent}$ \1\&{then}\5 +$\|v\K\\{p\_plus\_q}(\|v,\39\|r,\39\\{proto\_dependent})$\6 +\4\&{else} $\|v\K\\{p\_plus\_fq}(\|v,\39\\{unity},\39\|r,\39\\{proto% +\_dependent},\39\\{dependent})$;\2\6 +\4\\{done}: \37\X934:Output the answer, \|v (which might have become \\{known})% +\X;\6 +\&{end}\2\par +\U930.\fi + +\M933. \P$\X933:Add the known $\\{value}(\|p)$ to the constant term of \|v\X\S$% +\6 +\&{begin} \37\&{while} $\\{info}(\|v)\I\\{null}$ \1\&{do}\5 +$\|v\K\\{link}(\|v)$;\2\6 +$\\{value}(\|v)\K\\{slow\_add}(\\{value}(\|p),\39\\{value}(\|v))$;\6 +\&{end}\par +\U932.\fi + +\M934. \P$\X934:Output the answer, \|v (which might have become \\{known})\X\S$% +\6 +\&{if} $\|q\I\\{null}$ \1\&{then}\5 +$\\{dep\_finish}(\|v,\39\|q,\39\|t)$\6 +\4\&{else} \&{begin} \37$\\{cur\_type}\K\|t$;\5 +$\\{dep\_finish}(\|v,\39\\{null},\39\|t)$;\6 +\&{end}\2\par +\U932.\fi + +\M935. Here's the current situation: The dependency list \|v of type \|t +should either be put into the current expression (if $\|q=\\{null}$) or +into location \|q within a pair node (otherwise). The destination (\\{cur\_exp} +or \|q) formerly held a dependency list with the same +final pointer as the list \|v. + +\Y\P$\4\X935:Declare the procedure called \\{dep\_finish}\X\S$\6 +\4\&{procedure}\1\ \37$\\{dep\_finish}(\|v,\39\|q:\\{pointer};\,\35\|t:% +\\{small\_number})$;\6 +\4\&{var} \37\|p: \37\\{pointer};\C{the destination}\6 +\\{vv}: \37\\{scaled};\C{the value, if it is \\{known}}\2\6 +\&{begin} \37\&{if} $\|q=\\{null}$ \1\&{then}\5 +$\|p\K\\{cur\_exp}$\ \&{else} $\|p\K\|q$;\2\6 +$\\{dep\_list}(\|p)\K\|v$;\5 +$\\{type}(\|p)\K\|t$;\6 +\&{if} $\\{info}(\|v)=\\{null}$ \1\&{then}\6 +\&{begin} \37$\\{vv}\K\\{value}(\|v)$;\6 +\&{if} $\|q=\\{null}$ \1\&{then}\5 +$\\{flush\_cur\_exp}(\\{vv})$\6 +\4\&{else} \&{begin} \37$\\{recycle\_value}(\|p)$;\5 +$\\{type}(\|q)\K\\{known}$;\5 +$\\{value}(\|q)\K\\{vv}$;\6 +\&{end};\2\6 +\&{end}\6 +\4\&{else} \&{if} $\|q=\\{null}$ \1\&{then}\5 +$\\{cur\_type}\K\|t$;\2\2\6 +\&{if} $\\{fix\_needed}$ \1\&{then}\5 +\\{fix\_dependencies};\2\6 +\&{end};\par +\U930.\fi + +\M936. Let's turn now to the six basic relations of comparison. + +\Y\P$\4\X936:Additional cases of binary operators\X\S$\6 +\4$\\{less\_than},\39\\{less\_or\_equal},\39\\{greater\_than},\39\\{greater\_or% +\_equal},\39\\{equal\_to},\39\\{unequal\_to}$: \37\&{begin} \37\hbox{}\6 +\&{if} $(\\{cur\_type}>\\{pair\_type})\W(\\{type}(\|p)>\\{pair\_type})$ \1% +\&{then}\5 +$\\{add\_or\_subtract}(\|p,\39\\{null},\39\\{minus})$\C{$\\{cur\_exp}\K(\|p)-% +\\{cur\_exp}$}\6 +\4\&{else} \&{if} $\\{cur\_type}\I\\{type}(\|p)$ \1\&{then}\6 +\&{begin} \37$\\{bad\_binary}(\|p,\39\|c)$;\5 +\&{goto} \37\\{done};\6 +\&{end}\6 +\4\&{else} \&{if} $\\{cur\_type}=\\{string\_type}$ \1\&{then}\5 +$\\{flush\_cur\_exp}(\\{str\_vs\_str}(\\{value}(\|p),\39\\{cur\_exp}))$\6 +\4\&{else} \&{if} $(\\{cur\_type}=\\{unknown\_string})\V(\\{cur\_type}=% +\\{unknown\_boolean})$ \1\&{then}\5 +\X938:Check if unknowns have been equated\X\6 +\4\&{else} \&{if} $(\\{cur\_type}=\\{pair\_type})\V(\\{cur\_type}=\\{transform% +\_type})$ \1\&{then}\5 +\X939:Reduce comparison of big nodes to comparison of scalars\X\6 +\4\&{else} \&{if} $\\{cur\_type}=\\{boolean\_type}$ \1\&{then}\5 +$\\{flush\_cur\_exp}(\\{cur\_exp}-\\{value}(\|p))$\6 +\4\&{else} \&{begin} \37$\\{bad\_binary}(\|p,\39\|c)$;\5 +\&{goto} \37\\{done};\6 +\&{end};\2\2\2\2\2\2\6 +\X937:Compare the current expression with zero\X;\6 +\4\\{done}: \37\&{end};\par +\As940, 941, 948, 951, 952, 975, 983\ETs988. +\U922.\fi + +\M937. \P$\X937:Compare the current expression with zero\X\S$\6 +\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{cur\_type}<\\{known}$ \1\&{then}\6 +\&{begin} \37$\\{disp\_err}(\|p,\39\.{""})$;\5 +$\\{help1}(\.{"The\ quantities\ shown\ above\ have\ not\ been\ equated."})$\6 +\&{end}\6 +\4\&{else} $\\{help2}(\.{"Oh\ dear.\ I\ can\'t\ decide\ if\ the\ expression\ +above\ is\ positive,"})$\2\6 +$(\.{"negative,\ or\ zero.\ So\ this\ comparison\ test\ won\'t\ be\ \`true% +\'."})$;\5 +$\\{exp\_err}(\.{"Unknown\ relation\ will\ be\ considered\ false"})$;\5 +$\\{put\_get\_flush\_error}(\\{false\_code})$;\6 +\&{end}\6 +\4\&{else} \&{case} $\|c$ \1\&{of}\6 +\4\\{less\_than}: \37$\\{boolean\_reset}(\\{cur\_exp}<0)$;\6 +\4\\{less\_or\_equal}: \37$\\{boolean\_reset}(\\{cur\_exp}\L0)$;\6 +\4\\{greater\_than}: \37$\\{boolean\_reset}(\\{cur\_exp}>0)$;\6 +\4\\{greater\_or\_equal}: \37$\\{boolean\_reset}(\\{cur\_exp}\G0)$;\6 +\4\\{equal\_to}: \37$\\{boolean\_reset}(\\{cur\_exp}=0)$;\6 +\4\\{unequal\_to}: \37$\\{boolean\_reset}(\\{cur\_exp}\I0)$;\2\6 +\&{end};\C{there are no other cases}\2\6 +$\\{cur\_type}\K\\{boolean\_type}$\par +\U936.\fi + +\M938. When two unknown strings are in the same ring, we know that they are +equal. Otherwise, we don't know whether they are equal or not, so we +make no change. + +\Y\P$\4\X938:Check if unknowns have been equated\X\S$\6 +\&{begin} \37$\|q\K\\{value}(\\{cur\_exp})$;\6 +\&{while} $(\|q\I\\{cur\_exp})\W(\|q\I\|p)$ \1\&{do}\5 +$\|q\K\\{value}(\|q)$;\2\6 +\&{if} $\|q=\|p$ \1\&{then}\5 +$\\{flush\_cur\_exp}(0)$;\2\6 +\&{end}\par +\U936.\fi + +\M939. \P$\X939:Reduce comparison of big nodes to comparison of scalars\X\S$\6 +\&{begin} \37$\|q\K\\{value}(\|p)$;\5 +$\|r\K\\{value}(\\{cur\_exp})$;\5 +$\\{rr}\K\|r+\\{big\_node\_size}[\\{cur\_type}]-2$;\6 +\~ \1\&{loop}\ \&{begin} \37$\\{add\_or\_subtract}(\|q,\39\|r,\39\\{minus})$;\6 +\&{if} $\\{type}(\|r)\I\\{known}$ \1\&{then}\5 +\&{goto} \37\\{done1};\2\6 +\&{if} $\\{value}(\|r)\I0$ \1\&{then}\5 +\&{goto} \37\\{done1};\2\6 +\&{if} $\|r=\\{rr}$ \1\&{then}\5 +\&{goto} \37\\{done1};\2\6 +$\|q\K\|q+2$;\5 +$\|r\K\|r+2$;\6 +\&{end};\2\6 +\4\\{done1}: \37$\\{take\_part}(\\{x\_part}+\\{half}(\|r-\\{value}(\\{cur% +\_exp})))$;\6 +\&{end}\par +\U936.\fi + +\M940. Here we use the sneaky fact that $\\{and\_op}-\\{false\_code}=\\{or% +\_op}-\\{true\_code}$. + +\Y\P$\4\X936:Additional cases of binary operators\X\mathrel{+}\S$\6 +\4$\\{and\_op},\39\\{or\_op}$: \37\&{if} $(\\{type}(\|p)\I\\{boolean\_type})\V(% +\\{cur\_type}\I\\{boolean\_type})$ \1\&{then}\5 +$\\{bad\_binary}(\|p,\39\|c)$\6 +\4\&{else} \&{if} $\\{value}(\|p)=\|c+\\{false\_code}-\\{and\_op}$ \1\&{then}\5 +$\\{cur\_exp}\K\\{value}(\|p)$;\2\2\par +\fi + +\M941. \P$\X936:Additional cases of binary operators\X\mathrel{+}\S$\6 +\4\\{times}: \37\&{if} $(\\{cur\_type}<\\{pair\_type})\V(\\{type}(\|p)<\\{pair% +\_type})$ \1\&{then}\5 +$\\{bad\_binary}(\|p,\39\\{times})$\6 +\4\&{else} \&{if} $(\\{cur\_type}=\\{known})\V(\\{type}(\|p)=\\{known})$ \1% +\&{then}\5 +\X942:Multiply when at least one operand is known\X\6 +\4\&{else} \&{if} $(\\{nice\_pair}(\|p,\39\\{type}(\|p))\W(\\{cur\_type}>% +\\{pair\_type}))\V(\\{nice\_pair}(\\{cur\_exp},\39\\{cur\_type})\W(\\{type}(% +\|p)>\\{pair\_type}))$ \1\&{then}\6 +\&{begin} \37$\\{hard\_times}(\|p)$;\5 +\&{return};\6 +\&{end}\6 +\4\&{else} $\\{bad\_binary}(\|p,\39\\{times})$;\2\2\2\par +\fi + +\M942. \P$\X942:Multiply when at least one operand is known\X\S$\6 +\&{begin} \37\&{if} $\\{type}(\|p)=\\{known}$ \1\&{then}\6 +\&{begin} \37$\|v\K\\{value}(\|p)$;\5 +$\\{free\_node}(\|p,\39\\{value\_node\_size})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|v\K\\{cur\_exp}$;\5 +$\\{unstash\_cur\_exp}(\|p)$;\6 +\&{end};\2\6 +\&{if} $\\{cur\_type}=\\{known}$ \1\&{then}\5 +$\\{cur\_exp}\K\\{take\_scaled}(\\{cur\_exp},\39\|v)$\6 +\4\&{else} \&{if} $\\{cur\_type}=\\{pair\_type}$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{value}(\\{cur\_exp})$;\5 +$\\{dep\_mult}(\\{x\_part\_loc}(\|p),\39\|v,\39\\{true})$;\5 +$\\{dep\_mult}(\\{y\_part\_loc}(\|p),\39\|v,\39\\{true})$;\6 +\&{end}\6 +\4\&{else} $\\{dep\_mult}(\\{null},\39\|v,\39\\{true})$;\2\2\6 +\&{return};\6 +\&{end}\par +\U941.\fi + +\M943. \P$\X923:Declare binary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{dep\_mult}(\|p:\\{pointer};\,\35\|v:\\{integer};\,% +\35\\{v\_is\_scaled}:\\{boolean})$;\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37\|q: \37\\{pointer};\C{the dependency list being multiplied by % +\|v}\6 +$\|s,\39\|t$: \37\\{small\_number};\C{its type, before and after}\2\6 +\&{begin} \37\&{if} $\|p=\\{null}$ \1\&{then}\5 +$\|q\K\\{cur\_exp}$\6 +\4\&{else} \&{if} $\\{type}(\|p)\I\\{known}$ \1\&{then}\5 +$\|q\K\|p$\6 +\4\&{else} \&{begin} \37\&{if} $\\{v\_is\_scaled}$ \1\&{then}\5 +$\\{value}(\|p)\K\\{take\_scaled}(\\{value}(\|p),\39\|v)$\6 +\4\&{else} $\\{value}(\|p)\K\\{take\_fraction}(\\{value}(\|p),\39\|v)$;\2\6 +\&{return};\6 +\&{end};\2\2\6 +$\|t\K\\{type}(\|q)$;\5 +$\|q\K\\{dep\_list}(\|q)$;\5 +$\|s\K\|t$;\6 +\&{if} $\|t=\\{dependent}$ \1\&{then}\6 +\&{if} $\\{v\_is\_scaled}$ \1\&{then}\6 +\&{if} $\\{ab\_vs\_cd}(\\{max\_coef}(\|q),\39\\{abs}(\|v),\39\\{coef\_bound}-1,% +\39\\{unity})\G0$ \1\&{then}\5 +$\|t\K\\{proto\_dependent}$;\2\2\2\6 +$\|q\K\\{p\_times\_v}(\|q,\39\|v,\39\|s,\39\|t,\39\\{v\_is\_scaled})$;\5 +$\\{dep\_finish}(\|q,\39\|p,\39\|t)$;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M944. Here is a routine that is similar to \\{times}; but it is invoked only +internally, when \|v is a \\{fraction} whose magnitude is at most~1, +and when $\\{cur\_type}\G\\{pair\_type}$. + +\Y\P\4\&{procedure}\1\ \37$\\{frac\_mult}(\|n,\39\|d:\\{scaled})$;% +\C{multiplies \\{cur\_exp} by $\|n/\|d$}\6 +\4\&{var} \37\|p: \37\\{pointer};\C{a pair node}\6 +\\{old\_exp}: \37\\{pointer};\C{a capsule to recycle}\6 +\|v: \37\\{fraction};\C{$\|n/\|d$}\2\6 +\&{begin} \37\&{if} $\\{internal}[\\{tracing\_commands}]>\\{two}$ \1\&{then}\5 +\X945:Trace the fraction multiplication\X;\2\6 +\&{case} $\\{cur\_type}$ \1\&{of}\6 +\4$\\{transform\_type},\39\\{pair\_type}$: \37$\\{old\_exp}\K\\{tarnished}(% +\\{cur\_exp})$;\6 +\4\\{independent}: \37$\\{old\_exp}\K\\{void}$;\6 +\4\&{othercases} \37$\\{old\_exp}\K\\{null}$\2\6 +\&{endcases};\6 +\&{if} $\\{old\_exp}\I\\{null}$ \1\&{then}\6 +\&{begin} \37$\\{old\_exp}\K\\{cur\_exp}$;\5 +$\\{make\_exp\_copy}(\\{old\_exp})$;\6 +\&{end};\2\6 +$\|v\K\\{make\_fraction}(\|n,\39\|d)$;\6 +\&{if} $\\{cur\_type}=\\{known}$ \1\&{then}\5 +$\\{cur\_exp}\K\\{take\_fraction}(\\{cur\_exp},\39\|v)$\6 +\4\&{else} \&{if} $\\{cur\_type}=\\{pair\_type}$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{value}(\\{cur\_exp})$;\5 +$\\{dep\_mult}(\\{x\_part\_loc}(\|p),\39\|v,\39\\{false})$;\5 +$\\{dep\_mult}(\\{y\_part\_loc}(\|p),\39\|v,\39\\{false})$;\6 +\&{end}\6 +\4\&{else} $\\{dep\_mult}(\\{null},\39\|v,\39\\{false})$;\2\2\6 +\&{if} $\\{old\_exp}\I\\{null}$ \1\&{then}\6 +\&{begin} \37$\\{recycle\_value}(\\{old\_exp})$;\5 +$\\{free\_node}(\\{old\_exp},\39\\{value\_node\_size})$;\6 +\&{end}\2\6 +\&{end};\par +\fi + +\M945. \P$\X945:Trace the fraction multiplication\X\S$\6 +\&{begin} \37\\{begin\_diagnostic};\5 +$\\{print\_nl}(\.{"\{("})$;\5 +$\\{print\_scaled}(\|n)$;\5 +$\\{print\_char}(\.{"/"})$;\5 +$\\{print\_scaled}(\|d)$;\5 +$\\{print}(\.{")*("})$;\5 +$\\{print\_exp}(\\{null},\390)$;\5 +$\\{print}(\.{")\}"})$;\5 +$\\{end\_diagnostic}(\\{false})$;\6 +\&{end}\par +\U944.\fi + +\M946. The \\{hard\_times} routine multiplies a nice pair by a dependency list. + +\Y\P$\4\X923:Declare binary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{hard\_times}(\|p:\\{pointer})$;\6 +\4\&{var} \37\|q: \37\\{pointer};\C{a copy of the dependent variable \|p}\6 +\|r: \37\\{pointer};\C{the big node for the nice pair}\6 +$\|u,\39\|v$: \37\\{scaled};\C{the known values of the nice pair}\2\6 +\&{begin} \37\&{if} $\\{type}(\|p)=\\{pair\_type}$ \1\&{then}\6 +\&{begin} \37$\|q\K\\{stash\_cur\_exp}$;\5 +$\\{unstash\_cur\_exp}(\|p)$;\5 +$\|p\K\|q$;\6 +\&{end};\C{now $\\{cur\_type}=\\{pair\_type}$}\2\6 +$\|r\K\\{value}(\\{cur\_exp})$;\5 +$\|u\K\\{value}(\\{x\_part\_loc}(\|r))$;\5 +$\|v\K\\{value}(\\{y\_part\_loc}(\|r))$;\5 +\X947:Move the dependent variable \|p into both parts of the pair node \|r\X;\6 +$\\{dep\_mult}(\\{x\_part\_loc}(\|r),\39\|u,\39\\{true})$;\5 +$\\{dep\_mult}(\\{y\_part\_loc}(\|r),\39\|v,\39\\{true})$;\6 +\&{end};\par +\fi + +\M947. \P$\X947:Move the dependent variable \|p into both parts of the pair +node \|r\X\S$\6 +$\\{type}(\\{y\_part\_loc}(\|r))\K\\{type}(\|p)$;\5 +$\\{new\_dep}(\\{y\_part\_loc}(\|r),\39\\{copy\_dep\_list}(\\{dep\_list}(% +\|p)))$;\6 +$\\{type}(\\{x\_part\_loc}(\|r))\K\\{type}(\|p)$;\5 +$\\{mem}[\\{value\_loc}(\\{x\_part\_loc}(\|r))]\K\\{mem}[\\{value\_loc}(\|p)]$;% +\5 +$\\{link}(\\{prev\_dep}(\|p))\K\\{x\_part\_loc}(\|r)$;\5 +$\\{free\_node}(\|p,\39\\{value\_node\_size})$\par +\U946.\fi + +\M948. \P$\X936:Additional cases of binary operators\X\mathrel{+}\S$\6 +\4\\{over}: \37\&{if} $(\\{cur\_type}\I\\{known})\V(\\{type}(\|p)<\\{pair% +\_type})$ \1\&{then}\5 +$\\{bad\_binary}(\|p,\39\\{over})$\6 +\4\&{else} \&{begin} \37$\|v\K\\{cur\_exp}$;\5 +$\\{unstash\_cur\_exp}(\|p)$;\6 +\&{if} $\|v=0$ \1\&{then}\5 +\X950:Squeal about division by zero\X\6 +\4\&{else} \&{begin} \37\&{if} $\\{cur\_type}=\\{known}$ \1\&{then}\5 +$\\{cur\_exp}\K\\{make\_scaled}(\\{cur\_exp},\39\|v)$\6 +\4\&{else} \&{if} $\\{cur\_type}=\\{pair\_type}$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{value}(\\{cur\_exp})$;\5 +$\\{dep\_div}(\\{x\_part\_loc}(\|p),\39\|v)$;\5 +$\\{dep\_div}(\\{y\_part\_loc}(\|p),\39\|v)$;\6 +\&{end}\6 +\4\&{else} $\\{dep\_div}(\\{null},\39\|v)$;\2\2\6 +\&{end};\2\6 +\&{return};\6 +\&{end};\2\par +\fi + +\M949. \P$\X923:Declare binary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{dep\_div}(\|p:\\{pointer};\,\35\|v:\\{scaled})$;\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37\|q: \37\\{pointer};\C{the dependency list being divided by \|v}\6 +$\|s,\39\|t$: \37\\{small\_number};\C{its type, before and after}\2\6 +\&{begin} \37\&{if} $\|p=\\{null}$ \1\&{then}\5 +$\|q\K\\{cur\_exp}$\6 +\4\&{else} \&{if} $\\{type}(\|p)\I\\{known}$ \1\&{then}\5 +$\|q\K\|p$\6 +\4\&{else} \&{begin} \37$\\{value}(\|p)\K\\{make\_scaled}(\\{value}(\|p),\39% +\|v)$;\5 +\&{return};\6 +\&{end};\2\2\6 +$\|t\K\\{type}(\|q)$;\5 +$\|q\K\\{dep\_list}(\|q)$;\5 +$\|s\K\|t$;\6 +\&{if} $\|t=\\{dependent}$ \1\&{then}\6 +\&{if} $\\{ab\_vs\_cd}(\\{max\_coef}(\|q),\39\\{unity},\39\\{coef\_bound}-1,\39% +\\{abs}(\|v))\G0$ \1\&{then}\5 +$\|t\K\\{proto\_dependent}$;\2\2\6 +$\|q\K\\{p\_over\_v}(\|q,\39\|v,\39\|s,\39\|t)$;\5 +$\\{dep\_finish}(\|q,\39\|p,\39\|t)$;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M950. \P$\X950:Squeal about division by zero\X\S$\6 +\&{begin} \37$\\{exp\_err}(\.{"Division\ by\ zero"})$;\5 +$\\{help2}(\.{"You\'re\ trying\ to\ divide\ the\ quantity\ shown\ above\ the\ +error"})$\6 +$(\.{"message\ by\ zero.\ I\'m\ going\ to\ divide\ it\ by\ one\ instead."})$;\5 +\\{put\_get\_error};\6 +\&{end}\par +\U948.\fi + +\M951. \P$\X936:Additional cases of binary operators\X\mathrel{+}\S$\6 +\4$\\{pythag\_add},\39\\{pythag\_sub}$: \37\&{if} $(\\{cur\_type}=\\{known})\W(% +\\{type}(\|p)=\\{known})$ \1\&{then}\6 +\&{if} $\|c=\\{pythag\_add}$ \1\&{then}\5 +$\\{cur\_exp}\K\\{pyth\_add}(\\{value}(\|p),\39\\{cur\_exp})$\6 +\4\&{else} $\\{cur\_exp}\K\\{pyth\_sub}(\\{value}(\|p),\39\\{cur\_exp})$\2\6 +\4\&{else} $\\{bad\_binary}(\|p,\39\|c)$;\2\par +\fi + +\M952. The next few sections of the program deal with affine transformations +of coordinate data. + +\Y\P$\4\X936:Additional cases of binary operators\X\mathrel{+}\S$\6 +\4$\\{rotated\_by},\39\\{slanted\_by},\39\\{scaled\_by},\39\\{shifted\_by},\39% +\\{transformed\_by},\39\\{x\_scaled},\39\\{y\_scaled},\39\\{z\_scaled}$: \37% +\hbox{}\6 +\&{if} $(\\{type}(\|p)=\\{path\_type})\V(\\{type}(\|p)=\\{future\_pen})\V(% +\\{type}(\|p)=\\{pen\_type})$ \1\&{then}\6 +\&{begin} \37$\\{path\_trans}(\|p,\39\|c)$;\5 +\&{return};\6 +\&{end}\6 +\4\&{else} \&{if} $(\\{type}(\|p)=\\{pair\_type})\V(\\{type}(\|p)=\\{transform% +\_type})$ \1\&{then}\5 +$\\{big\_trans}(\|p,\39\|c)$\6 +\4\&{else} \&{if} $\\{type}(\|p)=\\{picture\_type}$ \1\&{then}\6 +\&{begin} \37$\\{edges\_trans}(\|p,\39\|c)$;\5 +\&{return};\6 +\&{end}\6 +\4\&{else} $\\{bad\_binary}(\|p,\39\|c)$;\2\2\2\par +\fi + +\M953. Let \|c be one of the eight transform operators. The procedure call +$\\{set\_up\_trans}(\|c)$ first changes \\{cur\_exp} to a transform that +corresponds to +\|c and the original value of \\{cur\_exp}. (In particular, \\{cur\_exp} +doesn't +change at all if $\|c=\\{transformed\_by}$.) + +Then, if all components of the resulting transform are \\{known}, they are +moved to the global variables \\{txx}, \\{txy}, \\{tyx}, \\{tyy}, \\{tx}, % +\\{ty}; +and \\{cur\_exp} is changed to the known value zero. + +\Y\P$\4\X923:Declare binary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{set\_up\_trans}(\|c:\\{quarterword})$;\6 +\4\&{label} \37$\\{done},\39\\{exit}$;\6 +\4\&{var} \37$\|p,\39\|q,\39\|r$: \37\\{pointer};\C{list manipulation +registers}\2\6 +\&{begin} \37\&{if} $(\|c\I\\{transformed\_by})\V(\\{cur\_type}\I\\{transform% +\_type})$ \1\&{then}\5 +\X955:Put the current transform into \\{cur\_exp}\X;\2\6 +\X956:If the current transform is entirely known, stash it in global variables; +otherwise \&{return}\X;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M954. \P$\X13:Global variables\X\mathrel{+}\S$\6 +\4$\\{txx},\39\\{txy},\39\\{tyx},\39\\{tyy},\39\\{tx},\39\\{ty}$: \37% +\\{scaled};\C{current transform coefficients}\par +\fi + +\M955. \P$\X955:Put the current transform into \\{cur\_exp}\X\S$\6 +\&{begin} \37$\|p\K\\{stash\_cur\_exp}$;\5 +$\\{cur\_exp}\K\\{id\_transform}$;\5 +$\\{cur\_type}\K\\{transform\_type}$;\5 +$\|q\K\\{value}(\\{cur\_exp})$;\6 +\&{case} $\|c$ \1\&{of}\6 +\X957:For each of the eight cases, change the relevant fields of \\{cur\_exp} +and \&{goto} \\{done}; but do nothing if capsule \|p doesn't have the +appropriate type\X\2\6 +\&{end};\C{there are no other cases}\6 +$\\{disp\_err}(\|p,\39\.{"Improper\ transformation\ argument"})$;\5 +$\\{help3}(\.{"The\ expression\ shown\ above\ has\ the\ wrong\ type,"})$\6 +$(\.{"so\ I\ can\'t\ transform\ anything\ using\ it."})$\6 +$(\.{"Proceed,\ and\ I\'ll\ omit\ the\ transformation."})$;\5 +\\{put\_get\_error};\6 +\4\\{done}: \37$\\{recycle\_value}(\|p)$;\5 +$\\{free\_node}(\|p,\39\\{value\_node\_size})$;\6 +\&{end}\par +\U953.\fi + +\M956. \P$\X956:If the current transform is entirely known, stash it in global +variables; otherwise \&{return}\X\S$\6 +$\|q\K\\{value}(\\{cur\_exp})$;\5 +$\|r\K\|q+\\{transform\_node\_size}$;\6 +\1\&{repeat} \37$\|r\K\|r-2$;\6 +\&{if} $\\{type}(\|r)\I\\{known}$ \1\&{then}\5 +\&{return};\2\6 +\4\&{until}\5 +$\|r=\|q$;\2\6 +$\\{txx}\K\\{value}(\\{xx\_part\_loc}(\|q))$;\5 +$\\{txy}\K\\{value}(\\{xy\_part\_loc}(\|q))$;\5 +$\\{tyx}\K\\{value}(\\{yx\_part\_loc}(\|q))$;\5 +$\\{tyy}\K\\{value}(\\{yy\_part\_loc}(\|q))$;\5 +$\\{tx}\K\\{value}(\\{x\_part\_loc}(\|q))$;\5 +$\\{ty}\K\\{value}(\\{y\_part\_loc}(\|q))$;\5 +$\\{flush\_cur\_exp}(0)$\par +\U953.\fi + +\M957. \P$\X957:For each of the eight cases, change the relevant fields of % +\\{cur\_exp} and \&{goto} \\{done}; but do nothing if capsule \|p doesn't have +the appropriate type\X\S$\6 +\4\\{rotated\_by}: \37\&{if} $\\{type}(\|p)=\\{known}$ \1\&{then}\5 +\X958:Install sines and cosines, then \&{goto} \\{done}\X;\2\6 +\4\\{slanted\_by}: \37\&{if} $\\{type}(\|p)>\\{pair\_type}$ \1\&{then}\6 +\&{begin} \37$\\{install}(\\{xy\_part\_loc}(\|q),\39\|p)$;\5 +\&{goto} \37\\{done};\6 +\&{end};\2\6 +\4\\{scaled\_by}: \37\&{if} $\\{type}(\|p)>\\{pair\_type}$ \1\&{then}\6 +\&{begin} \37$\\{install}(\\{xx\_part\_loc}(\|q),\39\|p)$;\5 +$\\{install}(\\{yy\_part\_loc}(\|q),\39\|p)$;\5 +\&{goto} \37\\{done};\6 +\&{end};\2\6 +\4\\{shifted\_by}: \37\&{if} $\\{type}(\|p)=\\{pair\_type}$ \1\&{then}\6 +\&{begin} \37$\|r\K\\{value}(\|p)$;\5 +$\\{install}(\\{x\_part\_loc}(\|q),\39\\{x\_part\_loc}(\|r))$;\5 +$\\{install}(\\{y\_part\_loc}(\|q),\39\\{y\_part\_loc}(\|r))$;\5 +\&{goto} \37\\{done};\6 +\&{end};\2\6 +\4\\{x\_scaled}: \37\&{if} $\\{type}(\|p)>\\{pair\_type}$ \1\&{then}\6 +\&{begin} \37$\\{install}(\\{xx\_part\_loc}(\|q),\39\|p)$;\5 +\&{goto} \37\\{done};\6 +\&{end};\2\6 +\4\\{y\_scaled}: \37\&{if} $\\{type}(\|p)>\\{pair\_type}$ \1\&{then}\6 +\&{begin} \37$\\{install}(\\{yy\_part\_loc}(\|q),\39\|p)$;\5 +\&{goto} \37\\{done};\6 +\&{end};\2\6 +\4\\{z\_scaled}: \37\&{if} $\\{type}(\|p)=\\{pair\_type}$ \1\&{then}\5 +\X959:Install a complex multiplier, then \&{goto} \\{done}\X;\2\6 +\4\\{transformed\_by}: \37\\{do\_nothing};\par +\U955.\fi + +\M958. \P$\X958:Install sines and cosines, then \&{goto} \\{done}\X\S$\6 +\&{begin} \37$\\{n\_sin\_cos}((\\{value}(\|p)\mathbin{\&{mod}}\\{three\_sixty% +\_units})\ast16)$;\5 +$\\{value}(\\{xx\_part\_loc}(\|q))\K\\{round\_fraction}(\\{n\_cos})$;\5 +$\\{value}(\\{yx\_part\_loc}(\|q))\K\\{round\_fraction}(\\{n\_sin})$;\5 +$\\{value}(\\{xy\_part\_loc}(\|q))\K-\\{value}(\\{yx\_part\_loc}(\|q))$;\5 +$\\{value}(\\{yy\_part\_loc}(\|q))\K\\{value}(\\{xx\_part\_loc}(\|q))$;\5 +\&{goto} \37\\{done};\6 +\&{end}\par +\U957.\fi + +\M959. \P$\X959:Install a complex multiplier, then \&{goto} \\{done}\X\S$\6 +\&{begin} \37$\|r\K\\{value}(\|p)$;\5 +$\\{install}(\\{xx\_part\_loc}(\|q),\39\\{x\_part\_loc}(\|r))$;\5 +$\\{install}(\\{yy\_part\_loc}(\|q),\39\\{x\_part\_loc}(\|r))$;\5 +$\\{install}(\\{yx\_part\_loc}(\|q),\39\\{y\_part\_loc}(\|r))$;\6 +\&{if} $\\{type}(\\{y\_part\_loc}(\|r))=\\{known}$ \1\&{then}\5 +$\\{negate}(\\{value}(\\{y\_part\_loc}(\|r)))$\6 +\4\&{else} $\\{negate\_dep\_list}(\\{dep\_list}(\\{y\_part\_loc}(\|r)))$;\2\6 +$\\{install}(\\{xy\_part\_loc}(\|q),\39\\{y\_part\_loc}(\|r))$;\5 +\&{goto} \37\\{done};\6 +\&{end}\par +\U957.\fi + +\M960. Procedure \\{set\_up\_known\_trans} is like \\{set\_up\_trans}, but it +insists that the transformation be entirely known. + +\Y\P$\4\X923:Declare binary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{set\_up\_known\_trans}(\|c:\\{quarterword})$;\2\6 +\&{begin} \37$\\{set\_up\_trans}(\|c)$;\6 +\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\6 +\&{begin} \37$\\{exp\_err}(\.{"Transform\ components\ aren\'t\ all\ known"})$;\5 +$\\{help3}(\.{"I\'m\ unable\ to\ apply\ a\ partially\ specified\ +transformation"})$\6 +$(\.{"except\ to\ a\ fully\ known\ pair\ or\ transform."})$\6 +$(\.{"Proceed,\ and\ I\'ll\ omit\ the\ transformation."})$;\5 +$\\{put\_get\_flush\_error}(0)$;\5 +$\\{txx}\K\\{unity}$;\5 +$\\{txy}\K0$;\5 +$\\{tyx}\K0$;\5 +$\\{tyy}\K\\{unity}$;\5 +$\\{tx}\K0$;\5 +$\\{ty}\K0$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M961. Here's a procedure that applies the transform $\\{txx}\to\\{ty}$ to a +pair of +coordinates in locations \|p and~\|q. + +\Y\P$\4\X923:Declare binary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{trans}(\|p,\39\|q:\\{pointer})$;\6 +\4\&{var} \37\|v: \37\\{scaled};\C{the new \|x value}\2\6 +\&{begin} \37$\|v\K\\{take\_scaled}(\\{mem}[\|p].\\{sc},\39\\{txx})+\\{take% +\_scaled}(\\{mem}[\|q].\\{sc},\39\\{txy})+\\{tx}$;\5 +$\\{mem}[\|q].\\{sc}\K\\{take\_scaled}(\\{mem}[\|p].\\{sc},\39\\{tyx})+\\{take% +\_scaled}(\\{mem}[\|q].\\{sc},\39\\{tyy})+\\{ty}$;\5 +$\\{mem}[\|p].\\{sc}\K\|v$;\6 +\&{end};\par +\fi + +\M962. The simplest transformation procedure applies a transform to all +coordinates of a path. The \\{null\_pen} remains unchanged if it isn't +being shifted. + +\Y\P$\4\X923:Declare binary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{path\_trans}(\|p:\\{pointer};\,\35\|c:% +\\{quarterword})$;\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37\|q: \37\\{pointer};\C{list traverser}\2\6 +\&{begin} \37$\\{set\_up\_known\_trans}(\|c)$;\5 +$\\{unstash\_cur\_exp}(\|p)$;\6 +\&{if} $\\{cur\_type}=\\{pen\_type}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{max\_offset}(\\{cur\_exp})=0$ \1\&{then}\6 +\&{if} $\\{tx}=0$ \1\&{then}\6 +\&{if} $\\{ty}=0$ \1\&{then}\5 +\&{return};\2\2\2\6 +$\\{flush\_cur\_exp}(\\{make\_path}(\\{cur\_exp}))$;\5 +$\\{cur\_type}\K\\{future\_pen}$;\6 +\&{end};\2\6 +$\|q\K\\{cur\_exp}$;\6 +\1\&{repeat} \37\&{if} $\\{left\_type}(\|q)\I\\{endpoint}$ \1\&{then}\5 +$\\{trans}(\|q+3,\39\|q+4)$;\C{that's \\{left\_x} and \\{left\_y}}\2\6 +$\\{trans}(\|q+1,\39\|q+2)$;\C{that's \\{x\_coord} and \\{y\_coord}}\6 +\&{if} $\\{right\_type}(\|q)\I\\{endpoint}$ \1\&{then}\5 +$\\{trans}(\|q+5,\39\|q+6)$;\C{that's \\{right\_x} and \\{right\_y}}\2\6 +$\|q\K\\{link}(\|q)$;\6 +\4\&{until}\5 +$\|q=\\{cur\_exp}$;\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M963. The next simplest transformation procedure applies to edges. +It is simple primarily because \MF\ doesn't allow very general +transformations to be made, and because the tricky subroutines +for edge transformation have already been written. + +\Y\P$\4\X923:Declare binary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{edges\_trans}(\|p:\\{pointer};\,\35\|c:% +\\{quarterword})$;\6 +\4\&{label} \37\\{exit};\2\6 +\&{begin} \37$\\{set\_up\_known\_trans}(\|c)$;\5 +$\\{unstash\_cur\_exp}(\|p)$;\5 +$\\{cur\_edges}\K\\{cur\_exp}$;\6 +\&{if} $\\{empty\_edges}(\\{cur\_edges})$ \1\&{then}\5 +\&{return};\C{the empty set is easy to transform}\2\6 +\&{if} $\\{txx}=0$ \1\&{then}\6 +\&{if} $\\{tyy}=0$ \1\&{then}\6 +\&{if} $\\{txy}\mathbin{\&{mod}}\\{unity}=0$ \1\&{then}\6 +\&{if} $\\{tyx}\mathbin{\&{mod}}\\{unity}=0$ \1\&{then}\6 +\&{begin} \37\\{xy\_swap\_edges};\5 +$\\{txx}\K\\{txy}$;\5 +$\\{tyy}\K\\{tyx}$;\5 +$\\{txy}\K0$;\5 +$\\{tyx}\K0$;\6 +\&{if} $\\{empty\_edges}(\\{cur\_edges})$ \1\&{then}\5 +\&{return};\2\6 +\&{end};\2\2\2\2\6 +\&{if} $\\{txy}=0$ \1\&{then}\6 +\&{if} $\\{tyx}=0$ \1\&{then}\6 +\&{if} $\\{txx}\mathbin{\&{mod}}\\{unity}=0$ \1\&{then}\6 +\&{if} $\\{tyy}\mathbin{\&{mod}}\\{unity}=0$ \1\&{then}\5 +\X964:Scale the edges, shift them, and \&{return}\X;\2\2\2\2\6 +$\\{print\_err}(\.{"That\ transformation\ is\ too\ hard"})$;\5 +$\\{help3}(\.{"I\ can\ apply\ complicated\ transformations\ to\ paths,"})$\6 +$(\.{"but\ I\ can\ only\ do\ integer\ operations\ on\ pictures."})$\6 +$(\.{"Proceed,\ and\ I\'ll\ omit\ the\ transformation."})$;\5 +\\{put\_get\_error};\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M964. \P$\X964:Scale the edges, shift them, and \&{return}\X\S$\6 +\&{begin} \37\&{if} $(\\{txx}=0)\V(\\{tyy}=0)$ \1\&{then}\6 +\&{begin} \37$\\{toss\_edges}(\\{cur\_edges})$;\5 +$\\{cur\_exp}\K\\{get\_node}(\\{edge\_header\_size})$;\5 +$\\{init\_edges}(\\{cur\_exp})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37\&{if} $\\{txx}<0$ \1\&{then}\6 +\&{begin} \37\\{x\_reflect\_edges};\5 +$\\{txx}\K-\\{txx}$;\6 +\&{end};\2\6 +\&{if} $\\{tyy}<0$ \1\&{then}\6 +\&{begin} \37\\{y\_reflect\_edges};\5 +$\\{tyy}\K-\\{tyy}$;\6 +\&{end};\2\6 +\&{if} $\\{txx}\I\\{unity}$ \1\&{then}\5 +$\\{x\_scale\_edges}(\\{txx}\mathbin{\&{div}}\\{unity})$;\2\6 +\&{if} $\\{tyy}\I\\{unity}$ \1\&{then}\5 +$\\{y\_scale\_edges}(\\{tyy}\mathbin{\&{div}}\\{unity})$;\2\6 +\X965:Shift the edges by $(\\{tx},\\{ty})$, rounded\X;\6 +\&{end};\2\6 +\&{return};\6 +\&{end}\par +\U963.\fi + +\M965. \P$\X965:Shift the edges by $(\\{tx},\\{ty})$, rounded\X\S$\6 +$\\{tx}\K\\{round\_unscaled}(\\{tx})$;\5 +$\\{ty}\K\\{round\_unscaled}(\\{ty})$;\6 +\&{if} $(\\{m\_min}(\\{cur\_edges})+\\{tx}\L0)\V(\\{m\_max}(\\{cur\_edges})+% +\\{tx}\G8192)\V\30(\\{n\_min}(\\{cur\_edges})+\\{ty}\L0)\V(\\{n\_max}(\\{cur% +\_edges})+\\{ty}\G8191)\V\30(\\{abs}(\\{tx})\G4096)\V(\\{abs}(\\{ty})\G4096)$ % +\1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"Too\ far\ to\ shift"})$;\5 +$\\{help3}(\.{"I\ can\'t\ shift\ the\ picture\ as\ requested---it\ would"})$\6 +$(\.{"make\ some\ coordinates\ too\ large\ or\ too\ small."})$\6 +$(\.{"Proceed,\ and\ I\'ll\ omit\ the\ transformation."})$;\5 +\\{put\_get\_error};\6 +\&{end}\6 +\4\&{else} \&{begin} \37\&{if} $\\{tx}\I0$ \1\&{then}\6 +\&{begin} \37\&{if} $\R\\{valid\_range}(\\{m\_offset}(\\{cur\_edges})-\\{tx})$ % +\1\&{then}\5 +\\{fix\_offset};\2\6 +$\\{m\_min}(\\{cur\_edges})\K\\{m\_min}(\\{cur\_edges})+\\{tx}$;\5 +$\\{m\_max}(\\{cur\_edges})\K\\{m\_max}(\\{cur\_edges})+\\{tx}$;\5 +$\\{m\_offset}(\\{cur\_edges})\K\\{m\_offset}(\\{cur\_edges})-\\{tx}$;\5 +$\\{last\_window\_time}(\\{cur\_edges})\K0$;\6 +\&{end};\2\6 +\&{if} $\\{ty}\I0$ \1\&{then}\6 +\&{begin} \37$\\{n\_min}(\\{cur\_edges})\K\\{n\_min}(\\{cur\_edges})+\\{ty}$;\5 +$\\{n\_max}(\\{cur\_edges})\K\\{n\_max}(\\{cur\_edges})+\\{ty}$;\5 +$\\{n\_pos}(\\{cur\_edges})\K\\{n\_pos}(\\{cur\_edges})+\\{ty}$;\5 +$\\{last\_window\_time}(\\{cur\_edges})\K0$;\6 +\&{end};\2\6 +\&{end}\2\par +\U964.\fi + +\M966. The hard cases of transformation occur when big nodes are involved, +and when some of their components are unknown. + +\Y\P$\4\X923:Declare binary action procedures\X\mathrel{+}\S$\6 +\hbox{\4}\X968:Declare subroutines needed by \\{big\_trans}\X\6 +\4\&{procedure}\1\ \37$\\{big\_trans}(\|p:\\{pointer};\,\35\|c:% +\\{quarterword})$;\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37$\|q,\39\|r,\39\\{pp},\39\\{qq}$: \37\\{pointer};\C{list +manipulation registers}\6 +\|s: \37\\{small\_number};\C{size of a big node}\2\6 +\&{begin} \37$\|s\K\\{big\_node\_size}[\\{type}(\|p)]$;\5 +$\|q\K\\{value}(\|p)$;\5 +$\|r\K\|q+\|s$;\6 +\1\&{repeat} \37$\|r\K\|r-2$;\6 +\&{if} $\\{type}(\|r)\I\\{known}$ \1\&{then}\5 +\X967:Transform an unknown big node and \&{return}\X;\2\6 +\4\&{until}\5 +$\|r=\|q$;\2\6 +\X970:Transform a known big node\X;\6 +\4\\{exit}: \37\&{end};\C{node \|p will now be recycled by \\{do\_binary}}\par +\fi + +\M967. \P$\X967:Transform an unknown big node and \&{return}\X\S$\6 +\&{begin} \37$\\{set\_up\_known\_trans}(\|c)$;\5 +$\\{make\_exp\_copy}(\|p)$;\5 +$\|r\K\\{value}(\\{cur\_exp})$;\6 +\&{if} $\\{cur\_type}=\\{transform\_type}$ \1\&{then}\6 +\&{begin} \37$\\{bilin1}(\\{yy\_part\_loc}(\|r),\39\\{tyy},\39\\{xy\_part% +\_loc}(\|q),\39\\{tyx},\390)$;\5 +$\\{bilin1}(\\{yx\_part\_loc}(\|r),\39\\{tyy},\39\\{xx\_part\_loc}(\|q),\39% +\\{tyx},\390)$;\5 +$\\{bilin1}(\\{xy\_part\_loc}(\|r),\39\\{txx},\39\\{yy\_part\_loc}(\|q),\39% +\\{txy},\390)$;\5 +$\\{bilin1}(\\{xx\_part\_loc}(\|r),\39\\{txx},\39\\{yx\_part\_loc}(\|q),\39% +\\{txy},\390)$;\6 +\&{end};\2\6 +$\\{bilin1}(\\{y\_part\_loc}(\|r),\39\\{tyy},\39\\{x\_part\_loc}(\|q),\39% +\\{tyx},\39\\{ty})$;\5 +$\\{bilin1}(\\{x\_part\_loc}(\|r),\39\\{txx},\39\\{y\_part\_loc}(\|q),\39% +\\{txy},\39\\{tx})$;\5 +\&{return};\6 +\&{end}\par +\U966.\fi + +\M968. Let \|p point to a two-word value field inside a big node of \\{cur% +\_exp}, +and let \|q point to a another value field. The \\{bilin1} procedure +replaces \|p by $p\cdot t+q\cdot u+\delta$. + +\Y\P$\4\X968:Declare subroutines needed by \\{big\_trans}\X\S$\6 +\4\&{procedure}\1\ \37$\\{bilin1}(\|p:\\{pointer};\,\35\|t:\\{scaled};\,\35% +\|q:\\{pointer};\,\35\|u,\39\\{delta}:\\{scaled})$;\6 +\4\&{var} \37\|r: \37\\{pointer};\C{list traverser}\2\6 +\&{begin} \37\&{if} $\|t\I\\{unity}$ \1\&{then}\5 +$\\{dep\_mult}(\|p,\39\|t,\39\\{true})$;\2\6 +\&{if} $\|u\I0$ \1\&{then}\6 +\&{if} $\\{type}(\|q)=\\{known}$ \1\&{then}\5 +$\\{delta}\K\\{delta}+\\{take\_scaled}(\\{value}(\|q),\39\|u)$\6 +\4\&{else} \&{begin} \37\X969:Ensure that $\\{type}(\|p)=\\{proto\_dependent}$% +\X;\6 +$\\{dep\_list}(\|p)\K\\{p\_plus\_fq}(\\{dep\_list}(\|p),\39\|u,\39\\{dep% +\_list}(\|q),\39\\{proto\_dependent},\39\\{type}(\|q))$;\6 +\&{end};\2\2\6 +\&{if} $\\{type}(\|p)=\\{known}$ \1\&{then}\5 +$\\{value}(\|p)\K\\{value}(\|p)+\\{delta}$\6 +\4\&{else} \&{begin} \37$\|r\K\\{dep\_list}(\|p)$;\6 +\&{while} $\\{info}(\|r)\I\\{null}$ \1\&{do}\5 +$\|r\K\\{link}(\|r)$;\2\6 +$\\{delta}\K\\{value}(\|r)+\\{delta}$;\6 +\&{if} $\|r\I\\{dep\_list}(\|p)$ \1\&{then}\5 +$\\{value}(\|r)\K\\{delta}$\6 +\4\&{else} \&{begin} \37$\\{recycle\_value}(\|p)$;\5 +$\\{type}(\|p)\K\\{known}$;\5 +$\\{value}(\|p)\K\\{delta}$;\6 +\&{end};\2\6 +\&{end};\2\6 +\&{if} $\\{fix\_needed}$ \1\&{then}\5 +\\{fix\_dependencies};\2\6 +\&{end};\par +\As971, 972\ETs974. +\U966.\fi + +\M969. \P$\X969:Ensure that $\\{type}(\|p)=\\{proto\_dependent}$\X\S$\6 +\&{if} $\\{type}(\|p)\I\\{proto\_dependent}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{type}(\|p)=\\{known}$ \1\&{then}\5 +$\\{new\_dep}(\|p,\39\\{const\_dependency}(\\{value}(\|p)))$\6 +\4\&{else} $\\{dep\_list}(\|p)\K\\{p\_times\_v}(\\{dep\_list}(\|p),\39% +\\{unity},\39\\{dependent},\39\\{proto\_dependent},\39\\{true})$;\2\6 +$\\{type}(\|p)\K\\{proto\_dependent}$;\6 +\&{end}\2\par +\U968.\fi + +\M970. \P$\X970:Transform a known big node\X\S$\6 +$\\{set\_up\_trans}(\|c)$;\6 +\&{if} $\\{cur\_type}=\\{known}$ \1\&{then}\5 +\X973:Transform known by known\X\6 +\4\&{else} \&{begin} \37$\\{pp}\K\\{stash\_cur\_exp}$;\5 +$\\{qq}\K\\{value}(\\{pp})$;\5 +$\\{make\_exp\_copy}(\|p)$;\5 +$\|r\K\\{value}(\\{cur\_exp})$;\6 +\&{if} $\\{cur\_type}=\\{transform\_type}$ \1\&{then}\6 +\&{begin} \37$\\{bilin2}(\\{yy\_part\_loc}(\|r),\39\\{yy\_part\_loc}(\\{qq}),% +\39\\{value}(\\{xy\_part\_loc}(\|q)),\39\\{yx\_part\_loc}(\\{qq}),\39% +\\{null})$;\5 +$\\{bilin2}(\\{yx\_part\_loc}(\|r),\39\\{yy\_part\_loc}(\\{qq}),\39\\{value}(% +\\{xx\_part\_loc}(\|q)),\39\\{yx\_part\_loc}(\\{qq}),\39\\{null})$;\5 +$\\{bilin2}(\\{xy\_part\_loc}(\|r),\39\\{xx\_part\_loc}(\\{qq}),\39\\{value}(% +\\{yy\_part\_loc}(\|q)),\39\\{xy\_part\_loc}(\\{qq}),\39\\{null})$;\5 +$\\{bilin2}(\\{xx\_part\_loc}(\|r),\39\\{xx\_part\_loc}(\\{qq}),\39\\{value}(% +\\{yx\_part\_loc}(\|q)),\39\\{xy\_part\_loc}(\\{qq}),\39\\{null})$;\6 +\&{end};\2\6 +$\\{bilin2}(\\{y\_part\_loc}(\|r),\39\\{yy\_part\_loc}(\\{qq}),\39\\{value}(% +\\{x\_part\_loc}(\|q)),\39\\{yx\_part\_loc}(\\{qq}),\39\\{y\_part\_loc}(% +\\{qq}))$;\5 +$\\{bilin2}(\\{x\_part\_loc}(\|r),\39\\{xx\_part\_loc}(\\{qq}),\39\\{value}(% +\\{y\_part\_loc}(\|q)),\39\\{xy\_part\_loc}(\\{qq}),\39\\{x\_part\_loc}(% +\\{qq}))$;\5 +$\\{recycle\_value}(\\{pp})$;\5 +$\\{free\_node}(\\{pp},\39\\{value\_node\_size})$;\6 +\&{end};\2\par +\U966.\fi + +\M971. Let \|p be a \\{proto\_dependent} value whose dependency list ends +at \\{dep\_final}. The following procedure adds \|v times another +numeric quantity to~\|p. + +\Y\P$\4\X968:Declare subroutines needed by \\{big\_trans}\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{add\_mult\_dep}(\|p:\\{pointer};\,\35\|v:\\{scaled};% +\,\35\|r:\\{pointer})$;\2\6 +\&{begin} \37\&{if} $\\{type}(\|r)=\\{known}$ \1\&{then}\5 +$\\{value}(\\{dep\_final})\K\\{value}(\\{dep\_final})+\\{take\_scaled}(% +\\{value}(\|r),\39\|v)$\6 +\4\&{else} \&{begin} \37$\\{dep\_list}(\|p)\K\\{p\_plus\_fq}(\\{dep\_list}(% +\|p),\39\|v,\39\\{dep\_list}(\|r),\39\\{proto\_dependent},\39\\{type}(\|r))$;\6 +\&{if} $\\{fix\_needed}$ \1\&{then}\5 +\\{fix\_dependencies};\2\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M972. The \\{bilin2} procedure is something like \\{bilin1}, but with known +and unknown quantities reversed. Parameter \|p points to a value field +within the big node for \\{cur\_exp}; and $\\{type}(\|p)=\\{known}$. Parameters +\|t and~\|u point to value fields elsewhere; so does parameter~\|q, +unless it is \\{null} (which stands for zero). Location~\|p will be +replaced by $p\cdot t+v\cdot u+q$. + +\Y\P$\4\X968:Declare subroutines needed by \\{big\_trans}\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{bilin2}(\|p,\39\|t:\\{pointer};\,\35\|v:\\{scaled};% +\,\35\|u,\39\|q:\\{pointer})$;\6 +\4\&{var} \37\\{vv}: \37\\{scaled};\C{temporary storage for $\\{value}(\|p)$}\2% +\6 +\&{begin} \37$\\{vv}\K\\{value}(\|p)$;\5 +$\\{type}(\|p)\K\\{proto\_dependent}$;\5 +$\\{new\_dep}(\|p,\39\\{const\_dependency}(0))$;\C{this sets \\{dep\_final}}\6 +\&{if} $\\{vv}\I0$ \1\&{then}\5 +$\\{add\_mult\_dep}(\|p,\39\\{vv},\39\|t)$;\C{\\{dep\_final} doesn't change}\2\6 +\&{if} $\|v\I0$ \1\&{then}\5 +$\\{add\_mult\_dep}(\|p,\39\|v,\39\|u)$;\2\6 +\&{if} $\|q\I\\{null}$ \1\&{then}\5 +$\\{add\_mult\_dep}(\|p,\39\\{unity},\39\|q)$;\2\6 +\&{if} $\\{dep\_list}(\|p)=\\{dep\_final}$ \1\&{then}\6 +\&{begin} \37$\\{vv}\K\\{value}(\\{dep\_final})$;\5 +$\\{recycle\_value}(\|p)$;\5 +$\\{type}(\|p)\K\\{known}$;\5 +$\\{value}(\|p)\K\\{vv}$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M973. \P$\X973:Transform known by known\X\S$\6 +\&{begin} \37$\\{make\_exp\_copy}(\|p)$;\5 +$\|r\K\\{value}(\\{cur\_exp})$;\6 +\&{if} $\\{cur\_type}=\\{transform\_type}$ \1\&{then}\6 +\&{begin} \37$\\{bilin3}(\\{yy\_part\_loc}(\|r),\39\\{tyy},\39\\{value}(\\{xy% +\_part\_loc}(\|q)),\39\\{tyx},\390)$;\5 +$\\{bilin3}(\\{yx\_part\_loc}(\|r),\39\\{tyy},\39\\{value}(\\{xx\_part\_loc}(% +\|q)),\39\\{tyx},\390)$;\5 +$\\{bilin3}(\\{xy\_part\_loc}(\|r),\39\\{txx},\39\\{value}(\\{yy\_part\_loc}(% +\|q)),\39\\{txy},\390)$;\5 +$\\{bilin3}(\\{xx\_part\_loc}(\|r),\39\\{txx},\39\\{value}(\\{yx\_part\_loc}(% +\|q)),\39\\{txy},\390)$;\6 +\&{end};\2\6 +$\\{bilin3}(\\{y\_part\_loc}(\|r),\39\\{tyy},\39\\{value}(\\{x\_part\_loc}(% +\|q)),\39\\{tyx},\39\\{ty})$;\5 +$\\{bilin3}(\\{x\_part\_loc}(\|r),\39\\{txx},\39\\{value}(\\{y\_part\_loc}(% +\|q)),\39\\{txy},\39\\{tx})$;\6 +\&{end}\par +\U970.\fi + +\M974. Finally, in \\{bilin3} everything is \\{known}. + +\Y\P$\4\X968:Declare subroutines needed by \\{big\_trans}\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{bilin3}(\|p:\\{pointer};\,\35\|t,\39\|v,\39\|u,\39% +\\{delta}:\\{scaled})$;\2\6 +\&{begin} \37\&{if} $\|t\I\\{unity}$ \1\&{then}\5 +$\\{delta}\K\\{delta}+\\{take\_scaled}(\\{value}(\|p),\39\|t)$\6 +\4\&{else} $\\{delta}\K\\{delta}+\\{value}(\|p)$;\2\6 +\&{if} $\|u\I0$ \1\&{then}\5 +$\\{value}(\|p)\K\\{delta}+\\{take\_scaled}(\|v,\39\|u)$\6 +\4\&{else} $\\{value}(\|p)\K\\{delta}$;\2\6 +\&{end};\par +\fi + +\M975. \P$\X936:Additional cases of binary operators\X\mathrel{+}\S$\6 +\4\\{concatenate}: \37\&{if} $(\\{cur\_type}=\\{string\_type})\W(\\{type}(\|p)=% +\\{string\_type})$ \1\&{then}\5 +$\\{cat}(\|p)$\6 +\4\&{else} $\\{bad\_binary}(\|p,\39\\{concatenate})$;\2\6 +\4\\{substring\_of}: \37\&{if} $\\{nice\_pair}(\|p,\39\\{type}(\|p))\W(\\{cur% +\_type}=\\{string\_type})$ \1\&{then}\5 +$\\{chop\_string}(\\{value}(\|p))$\6 +\4\&{else} $\\{bad\_binary}(\|p,\39\\{substring\_of})$;\2\6 +\4\\{subpath\_of}: \37\&{begin} \37\&{if} $\\{cur\_type}=\\{pair\_type}$ \1% +\&{then}\5 +\\{pair\_to\_path};\2\6 +\&{if} $\\{nice\_pair}(\|p,\39\\{type}(\|p))\W(\\{cur\_type}=\\{path\_type})$ % +\1\&{then}\5 +$\\{chop\_path}(\\{value}(\|p))$\6 +\4\&{else} $\\{bad\_binary}(\|p,\39\\{subpath\_of})$;\2\6 +\&{end};\par +\fi + +\M976. \P$\X923:Declare binary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{cat}(\|p:\\{pointer})$;\6 +\4\&{var} \37$\|a,\39\|b$: \37\\{str\_number};\C{the strings being +concatenated}\6 +\|k: \37\\{pool\_pointer};\C{index into \\{str\_pool}}\2\6 +\&{begin} \37$\|a\K\\{value}(\|p)$;\5 +$\|b\K\\{cur\_exp}$;\5 +$\\{str\_room}(\\{length}(\|a)+\\{length}(\|b))$;\6 +\&{for} $\|k\K\\{str\_start}[\|a]\mathrel{\&{to}}\\{str\_start}[\|a+1]-1$ \1% +\&{do}\5 +$\\{append\_char}(\\{so}(\\{str\_pool}[\|k]))$;\2\6 +\&{for} $\|k\K\\{str\_start}[\|b]\mathrel{\&{to}}\\{str\_start}[\|b+1]-1$ \1% +\&{do}\5 +$\\{append\_char}(\\{so}(\\{str\_pool}[\|k]))$;\2\6 +$\\{cur\_exp}\K\\{make\_string}$;\5 +$\\{delete\_str\_ref}(\|b)$;\6 +\&{end};\par +\fi + +\M977. \P$\X923:Declare binary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{chop\_string}(\|p:\\{pointer})$;\6 +\4\&{var} \37$\|a,\39\|b$: \37\\{integer};\C{start and stop points}\6 +\|l: \37\\{integer};\C{length of the original string}\6 +\|k: \37\\{integer};\C{runs from \|a to \|b}\6 +\|s: \37\\{str\_number};\C{the original string}\6 +\\{reversed}: \37\\{boolean};\C{was $\|a>\|b$?}\2\6 +\&{begin} \37$\|a\K\\{round\_unscaled}(\\{value}(\\{x\_part\_loc}(\|p)))$;\5 +$\|b\K\\{round\_unscaled}(\\{value}(\\{y\_part\_loc}(\|p)))$;\6 +\&{if} $\|a\L\|b$ \1\&{then}\5 +$\\{reversed}\K\\{false}$\6 +\4\&{else} \&{begin} \37$\\{reversed}\K\\{true}$;\5 +$\|k\K\|a$;\5 +$\|a\K\|b$;\5 +$\|b\K\|k$;\6 +\&{end};\2\6 +$\|s\K\\{cur\_exp}$;\5 +$\|l\K\\{length}(\|s)$;\6 +\&{if} $\|a<0$ \1\&{then}\6 +\&{begin} \37$\|a\K0$;\6 +\&{if} $\|b<0$ \1\&{then}\5 +$\|b\K0$;\2\6 +\&{end};\2\6 +\&{if} $\|b>\|l$ \1\&{then}\6 +\&{begin} \37$\|b\K\|l$;\6 +\&{if} $\|a>\|l$ \1\&{then}\5 +$\|a\K\|l$;\2\6 +\&{end};\2\6 +$\\{str\_room}(\|b-\|a)$;\6 +\&{if} $\\{reversed}$ \1\&{then}\6 +\&{for} $\|k\K\\{str\_start}[\|s]+\|b-1\mathrel{\&{downto}}\\{str\_start}[\|s]+% +\|a$ \1\&{do}\5 +$\\{append\_char}(\\{so}(\\{str\_pool}[\|k]))$\2\6 +\4\&{else} \&{for} $\|k\K\\{str\_start}[\|s]+\|a\mathrel{\&{to}}\\{str\_start}[% +\|s]+\|b-1$ \1\&{do}\5 +$\\{append\_char}(\\{so}(\\{str\_pool}[\|k]))$;\2\2\6 +$\\{cur\_exp}\K\\{make\_string}$;\5 +$\\{delete\_str\_ref}(\|s)$;\6 +\&{end};\par +\fi + +\M978. \P$\X923:Declare binary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{chop\_path}(\|p:\\{pointer})$;\6 +\4\&{var} \37\|q: \37\\{pointer};\C{a knot in the original path}\6 +$\\{pp},\39\\{qq},\39\\{rr},\39\\{ss}$: \37\\{pointer};\C{link variables for +copies of path nodes}\6 +$\|a,\39\|b,\39\|k,\39\|l$: \37\\{scaled};\C{indices for chopping}\6 +\\{reversed}: \37\\{boolean};\C{was $\|a>\|b$?}\2\6 +\&{begin} \37$\|l\K\\{path\_length}$;\5 +$\|a\K\\{value}(\\{x\_part\_loc}(\|p))$;\5 +$\|b\K\\{value}(\\{y\_part\_loc}(\|p))$;\6 +\&{if} $\|a\L\|b$ \1\&{then}\5 +$\\{reversed}\K\\{false}$\6 +\4\&{else} \&{begin} \37$\\{reversed}\K\\{true}$;\5 +$\|k\K\|a$;\5 +$\|a\K\|b$;\5 +$\|b\K\|k$;\6 +\&{end};\2\6 +\X979:Dispense with the cases $\|a<0$ and/or $\|b>\|l$\X;\6 +$\|q\K\\{cur\_exp}$;\6 +\&{while} $\|a\G\\{unity}$ \1\&{do}\6 +\&{begin} \37$\|q\K\\{link}(\|q)$;\5 +$\|a\K\|a-\\{unity}$;\5 +$\|b\K\|b-\\{unity}$;\6 +\&{end};\2\6 +\&{if} $\|b=\|a$ \1\&{then}\5 +\X981:Construct a path from \\{pp} to \\{qq} of length zero\X\6 +\4\&{else} \X980:Construct a path from \\{pp} to \\{qq} of length $\lceil b% +\rceil$\X;\2\6 +$\\{left\_type}(\\{pp})\K\\{endpoint}$;\5 +$\\{right\_type}(\\{qq})\K\\{endpoint}$;\5 +$\\{link}(\\{qq})\K\\{pp}$;\5 +$\\{toss\_knot\_list}(\\{cur\_exp})$;\6 +\&{if} $\\{reversed}$ \1\&{then}\6 +\&{begin} \37$\\{cur\_exp}\K\\{link}(\\{htap\_ypoc}(\\{pp}))$;\5 +$\\{toss\_knot\_list}(\\{pp})$;\6 +\&{end}\6 +\4\&{else} $\\{cur\_exp}\K\\{pp}$;\2\6 +\&{end};\par +\fi + +\M979. \P$\X979:Dispense with the cases $\|a<0$ and/or $\|b>\|l$\X\S$\6 +\&{if} $\|a<0$ \1\&{then}\6 +\&{if} $\\{left\_type}(\\{cur\_exp})=\\{endpoint}$ \1\&{then}\6 +\&{begin} \37$\|a\K0$;\6 +\&{if} $\|b<0$ \1\&{then}\5 +$\|b\K0$;\2\6 +\&{end}\6 +\4\&{else} \1\&{repeat} \37$\|a\K\|a+\|l$;\5 +$\|b\K\|b+\|l$;\6 +\4\&{until}\5 +$\|a\G0$;\C{a cycle always has length $\|l>0$}\2\2\2\6 +\&{if} $\|b>\|l$ \1\&{then}\6 +\&{if} $\\{left\_type}(\\{cur\_exp})=\\{endpoint}$ \1\&{then}\6 +\&{begin} \37$\|b\K\|l$;\6 +\&{if} $\|a>\|l$ \1\&{then}\5 +$\|a\K\|l$;\2\6 +\&{end}\6 +\4\&{else} \&{while} $\|a\G\|l$ \1\&{do}\6 +\&{begin} \37$\|a\K\|a-\|l$;\5 +$\|b\K\|b-\|l$;\6 +\&{end}\2\2\2\par +\U978.\fi + +\M980. \P$\X980:Construct a path from \\{pp} to \\{qq} of length $\lceil b% +\rceil$\X\S$\6 +\&{begin} \37$\\{pp}\K\\{copy\_knot}(\|q)$;\5 +$\\{qq}\K\\{pp}$;\6 +\1\&{repeat} \37$\|q\K\\{link}(\|q)$;\5 +$\\{rr}\K\\{qq}$;\5 +$\\{qq}\K\\{copy\_knot}(\|q)$;\5 +$\\{link}(\\{rr})\K\\{qq}$;\5 +$\|b\K\|b-\\{unity}$;\6 +\4\&{until}\5 +$\|b\L0$;\2\6 +\&{if} $\|a>0$ \1\&{then}\6 +\&{begin} \37$\\{ss}\K\\{pp}$;\5 +$\\{pp}\K\\{link}(\\{pp})$;\5 +$\\{split\_cubic}(\\{ss},\39\|a\ast\O{10000},\39\\{x\_coord}(\\{pp}),\39\\{y% +\_coord}(\\{pp}))$;\5 +$\\{pp}\K\\{link}(\\{ss})$;\5 +$\\{free\_node}(\\{ss},\39\\{knot\_node\_size})$;\6 +\&{if} $\\{rr}=\\{ss}$ \1\&{then}\6 +\&{begin} \37$\|b\K\\{make\_scaled}(\|b,\39\\{unity}-\|a)$;\5 +$\\{rr}\K\\{pp}$;\6 +\&{end};\2\6 +\&{end};\2\6 +\&{if} $\|b<0$ \1\&{then}\6 +\&{begin} \37$\\{split\_cubic}(\\{rr},\39(\|b+\\{unity})\ast\O{10000},\39\\{x% +\_coord}(\\{qq}),\39\\{y\_coord}(\\{qq}))$;\5 +$\\{free\_node}(\\{qq},\39\\{knot\_node\_size})$;\5 +$\\{qq}\K\\{link}(\\{rr})$;\6 +\&{end};\2\6 +\&{end}\par +\U978.\fi + +\M981. \P$\X981:Construct a path from \\{pp} to \\{qq} of length zero\X\S$\6 +\&{begin} \37\&{if} $\|a>0$ \1\&{then}\6 +\&{begin} \37$\\{qq}\K\\{link}(\|q)$;\5 +$\\{split\_cubic}(\|q,\39\|a\ast\O{10000},\39\\{x\_coord}(\\{qq}),\39\\{y% +\_coord}(\\{qq}))$;\5 +$\|q\K\\{link}(\|q)$;\6 +\&{end};\2\6 +$\\{pp}\K\\{copy\_knot}(\|q)$;\5 +$\\{qq}\K\\{pp}$;\6 +\&{end}\par +\U978.\fi + +\M982. The \\{pair\_value} routine changes the current expression to a +given ordered pair of values. + +\Y\P$\4\X923:Declare binary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{pair\_value}(\|x,\39\|y:\\{scaled})$;\6 +\4\&{var} \37\|p: \37\\{pointer};\C{a pair node}\2\6 +\&{begin} \37$\|p\K\\{get\_node}(\\{value\_node\_size})$;\5 +$\\{flush\_cur\_exp}(\|p)$;\5 +$\\{cur\_type}\K\\{pair\_type}$;\5 +$\\{type}(\|p)\K\\{pair\_type}$;\5 +$\\{name\_type}(\|p)\K\\{capsule}$;\5 +$\\{init\_big\_node}(\|p)$;\5 +$\|p\K\\{value}(\|p)$;\6 +$\\{type}(\\{x\_part\_loc}(\|p))\K\\{known}$;\5 +$\\{value}(\\{x\_part\_loc}(\|p))\K\|x$;\6 +$\\{type}(\\{y\_part\_loc}(\|p))\K\\{known}$;\5 +$\\{value}(\\{y\_part\_loc}(\|p))\K\|y$;\6 +\&{end};\par +\fi + +\M983. \P$\X936:Additional cases of binary operators\X\mathrel{+}\S$\6 +\4$\\{point\_of},\39\\{precontrol\_of},\39\\{postcontrol\_of}$: \37\&{begin} % +\37\&{if} $\\{cur\_type}=\\{pair\_type}$ \1\&{then}\5 +\\{pair\_to\_path};\2\6 +\&{if} $(\\{cur\_type}=\\{path\_type})\W(\\{type}(\|p)=\\{known})$ \1\&{then}\5 +$\\{find\_point}(\\{value}(\|p),\39\|c)$\6 +\4\&{else} $\\{bad\_binary}(\|p,\39\|c)$;\2\6 +\&{end};\6 +\4\\{pen\_offset\_of}: \37\&{begin} \37\&{if} $\\{cur\_type}=\\{future\_pen}$ % +\1\&{then}\5 +\\{materialize\_pen};\2\6 +\&{if} $(\\{cur\_type}=\\{pen\_type})\W\\{nice\_pair}(\|p,\39\\{type}(\|p))$ \1% +\&{then}\5 +$\\{set\_up\_offset}(\\{value}(\|p))$\6 +\4\&{else} $\\{bad\_binary}(\|p,\39\\{pen\_offset\_of})$;\2\6 +\&{end};\6 +\4\\{direction\_time\_of}: \37\&{begin} \37\&{if} $\\{cur\_type}=\\{pair% +\_type}$ \1\&{then}\5 +\\{pair\_to\_path};\2\6 +\&{if} $(\\{cur\_type}=\\{path\_type})\W\\{nice\_pair}(\|p,\39\\{type}(\|p))$ % +\1\&{then}\5 +$\\{set\_up\_direction\_time}(\\{value}(\|p))$\6 +\4\&{else} $\\{bad\_binary}(\|p,\39\\{direction\_time\_of})$;\2\6 +\&{end};\par +\fi + +\M984. \P$\X923:Declare binary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{set\_up\_offset}(\|p:\\{pointer})$;\2\6 +\&{begin} \37$\\{find\_offset}(\\{value}(\\{x\_part\_loc}(\|p)),\39\\{value}(% +\\{y\_part\_loc}(\|p)),\39\\{cur\_exp})$;\5 +$\\{pair\_value}(\\{cur\_x},\39\\{cur\_y})$;\6 +\&{end};\7 +\4\&{procedure}\1\ \37$\\{set\_up\_direction\_time}(\|p:\\{pointer})$;\2\6 +\&{begin} \37$\\{flush\_cur\_exp}(\\{find\_direction\_time}(\\{value}(\\{x% +\_part\_loc}(\|p)),\39\\{value}(\\{y\_part\_loc}(\|p)),\39\\{cur\_exp}))$;\6 +\&{end};\par +\fi + +\M985. \P$\X923:Declare binary action procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{find\_point}(\|v:\\{scaled};\,\35\|c:% +\\{quarterword})$;\6 +\4\&{var} \37\|p: \37\\{pointer};\C{the path}\6 +\|n: \37\\{scaled};\C{its length}\6 +\|q: \37\\{pointer};\C{successor of \|p}\2\6 +\&{begin} \37$\|p\K\\{cur\_exp}$;\6 +\&{if} $\\{left\_type}(\|p)=\\{endpoint}$ \1\&{then}\5 +$\|n\K-\\{unity}$\ \&{else} $\|n\K0$;\2\6 +\1\&{repeat} \37$\|p\K\\{link}(\|p)$;\5 +$\|n\K\|n+\\{unity}$;\6 +\4\&{until}\5 +$\|p=\\{cur\_exp}$;\2\6 +\&{if} $\|n=0$ \1\&{then}\5 +$\|v\K0$\6 +\4\&{else} \&{if} $\|v<0$ \1\&{then}\6 +\&{if} $\\{left\_type}(\|p)=\\{endpoint}$ \1\&{then}\5 +$\|v\K0$\6 +\4\&{else} $\|v\K\|n-1-((-\|v-1)\mathbin{\&{mod}}\|n)$\2\6 +\4\&{else} \&{if} $\|v>\|n$ \1\&{then}\6 +\&{if} $\\{left\_type}(\|p)=\\{endpoint}$ \1\&{then}\5 +$\|v\K\|n$\6 +\4\&{else} $\|v\K\|v\mathbin{\&{mod}}\|n$;\2\2\2\2\6 +$\|p\K\\{cur\_exp}$;\6 +\&{while} $\|v\G\\{unity}$ \1\&{do}\6 +\&{begin} \37$\|p\K\\{link}(\|p)$;\5 +$\|v\K\|v-\\{unity}$;\6 +\&{end};\2\6 +\&{if} $\|v\I0$ \1\&{then}\5 +\X986:Insert a fractional node by splitting the cubic\X;\2\6 +\X987:Set the current expression to the desired path coordinates\X;\6 +\&{end};\par +\fi + +\M986. \P$\X986:Insert a fractional node by splitting the cubic\X\S$\6 +\&{begin} \37$\|q\K\\{link}(\|p)$;\5 +$\\{split\_cubic}(\|p,\39\|v\ast\O{10000},\39\\{x\_coord}(\|q),\39\\{y\_coord}(% +\|q))$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{end}\par +\U985.\fi + +\M987. \P$\X987:Set the current expression to the desired path coordinates\X\S$% +\6 +\&{case} $\|c$ \1\&{of}\6 +\4\\{point\_of}: \37$\\{pair\_value}(\\{x\_coord}(\|p),\39\\{y\_coord}(\|p))$;\6 +\4\\{precontrol\_of}: \37\&{if} $\\{left\_type}(\|p)=\\{endpoint}$ \1\&{then}\5 +$\\{pair\_value}(\\{x\_coord}(\|p),\39\\{y\_coord}(\|p))$\6 +\4\&{else} $\\{pair\_value}(\\{left\_x}(\|p),\39\\{left\_y}(\|p))$;\2\6 +\4\\{postcontrol\_of}: \37\&{if} $\\{right\_type}(\|p)=\\{endpoint}$ \1\&{then}% +\5 +$\\{pair\_value}(\\{x\_coord}(\|p),\39\\{y\_coord}(\|p))$\6 +\4\&{else} $\\{pair\_value}(\\{right\_x}(\|p),\39\\{right\_y}(\|p))$;\2\2\6 +\&{end}\C{there are no other cases}\par +\U985.\fi + +\M988. \P$\X936:Additional cases of binary operators\X\mathrel{+}\S$\6 +\4\\{intersect}: \37\&{begin} \37\&{if} $\\{type}(\|p)=\\{pair\_type}$ \1% +\&{then}\6 +\&{begin} \37$\|q\K\\{stash\_cur\_exp}$;\5 +$\\{unstash\_cur\_exp}(\|p)$;\5 +\\{pair\_to\_path};\5 +$\|p\K\\{stash\_cur\_exp}$;\5 +$\\{unstash\_cur\_exp}(\|q)$;\6 +\&{end};\2\6 +\&{if} $\\{cur\_type}=\\{pair\_type}$ \1\&{then}\5 +\\{pair\_to\_path};\2\6 +\&{if} $(\\{cur\_type}=\\{path\_type})\W(\\{type}(\|p)=\\{path\_type})$ \1% +\&{then}\6 +\&{begin} \37$\\{path\_intersection}(\\{value}(\|p),\39\\{cur\_exp})$;\5 +$\\{pair\_value}(\\{cur\_t},\39\\{cur\_tt})$;\6 +\&{end}\6 +\4\&{else} $\\{bad\_binary}(\|p,\39\\{intersect})$;\2\6 +\&{end};\par +\fi + +\N989. \[43] Statements and commands. +The chief executive of \MF\ is the \\{do\_statement} routine, which +contains the master switch that causes all the various pieces of \MF\ +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 structure of \\{do\_statement} itself is quite simple. The first token +of the statement is fetched using \\{get\_x\_next}. If it can be the first +token of an expression, we look for an equation, an assignment, or a +title. Otherwise we use a \&{case} construction to branch at high speed to +the appropriate routine for various and sundry other types of commands, +each of which has an ``action procedure'' that does the necessary work. + +The program uses the fact that +$$\hbox{$\\{min\_primary\_command}=\\{max\_statement\_command}=\\{type% +\_name}$}$$ +to interpret a statement that starts with, e.g., `\&{string}', +as a type declaration rather than a boolean expression. + +\Y\P\hbox{\4}\X1154:Declare generic font output procedures\X\6 +\hbox{\4}\X995:Declare action procedures for use by \\{do\_statement}\X\6 +\4\&{procedure}\1\ \37\\{do\_statement};\C{governs \MF's activities}\2\6 +\&{begin} \37$\\{cur\_type}\K\\{vacuous}$;\5 +\\{get\_x\_next};\6 +\&{if} $\\{cur\_cmd}>\\{max\_primary\_command}$ \1\&{then}\5 +\X990:Worry about bad statement\X\6 +\4\&{else} \&{if} $\\{cur\_cmd}>\\{max\_statement\_command}$ \1\&{then}\5 +\X993:Do an equation, assignment, title, or `$\langle\,$expression$\,\rangle\,$% +\&{endgroup}'\X\6 +\4\&{else} \X992:Do a statement that doesn't begin with an expression\X;\2\2\6 +\&{if} $\\{cur\_cmd}<\\{semicolon}$ \1\&{then}\5 +\X991:Flush unparsable junk that was found after the statement\X;\2\6 +$\\{error\_count}\K0$;\6 +\&{end};\par +\fi + +\M990. The only command codes $>\\{max\_primary\_command}$ that can be present +at the beginning of a statement are \\{semicolon} and higher; these +occur when the statement is null. + +\Y\P$\4\X990:Worry about bad statement\X\S$\6 +\&{begin} \37\&{if} $\\{cur\_cmd}<\\{semicolon}$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"A\ statement\ can\'t\ begin\ with\ \`"})$;\5 +$\\{print\_cmd\_mod}(\\{cur\_cmd},\39\\{cur\_mod})$;\5 +$\\{print\_char}(\.{"\'"})$;\5 +$\\{help5}(\.{"I\ was\ looking\ for\ the\ beginning\ of\ a\ new\ statement."})$% +\6 +$(\.{"If\ you\ just\ proceed\ without\ changing\ anything,\ I\'ll\ ignore"})$\6 +$(\.{"everything\ up\ to\ the\ next\ \`;\'.\ Please\ insert\ a\ semicolon"})$\6 +$(\.{"now\ in\ front\ of\ anything\ that\ you\ don\'t\ want\ me\ to\ +delete."})$\6 +$(\.{"(See\ Chapter\ 27\ of\ The\ METAFONTbook\ for\ an\ example.)"})$;\6 +\\{back\_error};\5 +\\{get\_x\_next};\6 +\&{end};\2\6 +\&{end}\par +\U989.\fi + +\M991. The help message printed here says that everything is flushed up to +a semicolon, but actually the commands \\{end\_group} and \\{stop} will +also terminate a statement. + +\Y\P$\4\X991:Flush unparsable junk that was found after the statement\X\S$\6 +\&{begin} \37$\\{print\_err}(\.{"Extra\ tokens\ will\ be\ flushed"})$;\5 +$\\{help6}(\.{"I\'ve\ just\ read\ as\ much\ of\ that\ statement\ as\ I\ could\ +fathom,"})$\6 +$(\.{"so\ a\ semicolon\ should\ have\ been\ next.\ It\'s\ very\ puzzling..."})$% +\6 +$(\.{"but\ I\'ll\ try\ to\ get\ myself\ back\ together,\ by\ ignoring"})$\6 +$(\.{"everything\ up\ to\ the\ next\ \`;\'.\ Please\ insert\ a\ semicolon"})$\6 +$(\.{"now\ in\ front\ of\ anything\ that\ you\ don\'t\ want\ me\ to\ +delete."})$\6 +$(\.{"(See\ Chapter\ 27\ of\ The\ METAFONTbook\ for\ an\ example.)"})$;\6 +\\{back\_error};\5 +$\\{scanner\_status}\K\\{flushing}$;\6 +\1\&{repeat} \37\\{get\_next};\5 +\X743:Decrease the string reference count, if the current token is a string\X;\6 +\4\&{until}\5 +\\{end\_of\_statement};\C{$\\{cur\_cmd}=\\{semicolon}$, \\{end\_group}, or % +\\{stop}}\2\6 +$\\{scanner\_status}\K\\{normal}$;\6 +\&{end}\par +\U989.\fi + +\M992. If \\{do\_statement} ends with $\\{cur\_cmd}=\\{end\_group}$, we should +have +$\\{cur\_type}=\\{vacuous}$ unless the statement was simply an expression; +in the latter case, \\{cur\_type} and \\{cur\_exp} should represent that +expression. + +\Y\P$\4\X992:Do a statement that doesn't begin with an expression\X\S$\6 +\&{begin} \37\&{if} $\\{internal}[\\{tracing\_commands}]>0$ \1\&{then}\5 +\\{show\_cur\_cmd\_mod};\2\6 +\&{case} $\\{cur\_cmd}$ \1\&{of}\6 +\4\\{type\_name}: \37\\{do\_type\_declaration};\6 +\4\\{macro\_def}: \37\&{if} $\\{cur\_mod}>\\{var\_def}$ \1\&{then}\5 +\\{make\_op\_def}\6 +\4\&{else} \&{if} $\\{cur\_mod}>\\{end\_def}$ \1\&{then}\5 +\\{scan\_def};\2\2\6 +\hbox{\4}\X1020:Cases of \\{do\_statement} that invoke particular commands\X\2\6 +\&{end};\C{there are no other cases}\6 +$\\{cur\_type}\K\\{vacuous}$;\6 +\&{end}\par +\U989.\fi + +\M993. The most important statements begin with expressions. + +\Y\P$\4\X993:Do an equation, assignment, title, or `$\langle\,$expression$\,% +\rangle\,$\&{endgroup}'\X\S$\6 +\&{begin} \37$\\{var\_flag}\K\\{assignment}$;\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_cmd}<\\{end\_group}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{cur\_cmd}=\\{equals}$ \1\&{then}\5 +\\{do\_equation}\6 +\4\&{else} \&{if} $\\{cur\_cmd}=\\{assignment}$ \1\&{then}\5 +\\{do\_assignment}\6 +\4\&{else} \&{if} $\\{cur\_type}=\\{string\_type}$ \1\&{then}\5 +\X994:Do a title\X\6 +\4\&{else} \&{if} $\\{cur\_type}\I\\{vacuous}$ \1\&{then}\6 +\&{begin} \37$\\{exp\_err}(\.{"Isolated\ expression"})$;\5 +$\\{help3}(\.{"I\ couldn\'t\ find\ an\ \`=\'\ or\ \`:=\'\ after\ the"})$\6 +$(\.{"expression\ that\ is\ shown\ above\ this\ error\ message,"})$\6 +$(\.{"so\ I\ guess\ I\'ll\ just\ ignore\ it\ and\ carry\ on."})$;\5 +\\{put\_get\_error};\6 +\&{end};\2\2\2\2\6 +$\\{flush\_cur\_exp}(0)$;\5 +$\\{cur\_type}\K\\{vacuous}$;\6 +\&{end};\2\6 +\&{end}\par +\U989.\fi + +\M994. \P$\X994:Do a title\X\S$\6 +\&{begin} \37\&{if} $\\{internal}[\\{tracing\_titles}]>0$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{""})$;\5 +$\\{slow\_print}(\\{cur\_exp})$;\5 +\\{update\_terminal};\6 +\&{end};\2\6 +\&{if} $\\{internal}[\\{proofing}]>0$ \1\&{then}\5 +\X1179:Send the current expression as a title to the output file\X;\2\6 +\&{end}\par +\U993.\fi + +\M995. Equations and assignments are performed by the pair of mutually +recursive +routines \\{do\_equation} and \\{do\_assignment}. These routines are called +when +$\\{cur\_cmd}=\\{equals}$ and when $\\{cur\_cmd}=\\{assignment}$, respectively; +the left-hand +side is in \\{cur\_type} and \\{cur\_exp}, while the right-hand side is yet +to be scanned. After the routines are finished, \\{cur\_type} and \\{cur\_exp} +will be equal to the right-hand side (which will normally be equal +to the left-hand side). + +\Y\P$\4\X995:Declare action procedures for use by \\{do\_statement}\X\S$\6 +\hbox{\4}\X1006:Declare the procedure called \\{try\_eq}\X\6 +\hbox{\4}\X1001:Declare the procedure called \\{make\_eq}\X\6 +\4\&{procedure}\1\ \37\\{do\_assignment};\5 +\\{forward};\5 +\hbox{\2}\6 +\4\&{procedure}\1\ \37\\{do\_equation};\6 +\4\&{var} \37\\{lhs}: \37\\{pointer};\C{capsule for the left-hand side}\6 +\|p: \37\\{pointer};\C{temporary register}\2\6 +\&{begin} \37$\\{lhs}\K\\{stash\_cur\_exp}$;\5 +\\{get\_x\_next};\5 +$\\{var\_flag}\K\\{assignment}$;\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_cmd}=\\{equals}$ \1\&{then}\5 +\\{do\_equation}\6 +\4\&{else} \&{if} $\\{cur\_cmd}=\\{assignment}$ \1\&{then}\5 +\\{do\_assignment};\2\2\6 +\&{if} $\\{internal}[\\{tracing\_commands}]>\\{two}$ \1\&{then}\5 +\X997:Trace the current equation\X;\2\6 +\&{if} $\\{cur\_type}=\\{unknown\_path}$ \1\&{then}\6 +\&{if} $\\{type}(\\{lhs})=\\{pair\_type}$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{stash\_cur\_exp}$;\5 +$\\{unstash\_cur\_exp}(\\{lhs})$;\5 +$\\{lhs}\K\|p$;\6 +\&{end};\C{in this case \\{make\_eq} will change the pair to a path}\2\2\6 +$\\{make\_eq}(\\{lhs})$;\C{equate \\{lhs} to $(\\{cur\_type},\\{cur\_exp})$}\6 +\&{end};\par +\As996, 1015, 1021, 1029, 1031, 1034, 1035, 1036, 1040, 1041, 1044, 1045, 1046, +1049, 1050, 1051, 1054, 1057, 1059, 1070, 1071, 1072, 1073, 1074, 1082, 1103, +1104, 1106, 1177\ETs1186. +\U989.\fi + +\M996. And \\{do\_assignment} is similar to \\{do\_expression}: + +\Y\P$\4\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_assignment};\6 +\4\&{var} \37\\{lhs}: \37\\{pointer};\C{token list for the left-hand side}\6 +\|p: \37\\{pointer};\C{where the left-hand value is stored}\6 +\|q: \37\\{pointer};\C{temporary capsule for the right-hand value}\2\6 +\&{begin} \37\&{if} $\\{cur\_type}\I\\{token\_list}$ \1\&{then}\6 +\&{begin} \37$\\{exp\_err}(\.{"Improper\ \`:=\'\ will\ be\ changed\ to\ \`=% +\'"})$;\5 +$\\{help2}(\.{"I\ didn\'t\ find\ a\ variable\ name\ at\ the\ left\ of\ the\ % +\`:=\',"})$\6 +$(\.{"so\ I\'m\ going\ to\ pretend\ that\ you\ said\ \`=\'\ instead."})$;\6 +\\{error};\5 +\\{do\_equation};\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{lhs}\K\\{cur\_exp}$;\5 +$\\{cur\_type}\K\\{vacuous}$;\6 +\\{get\_x\_next};\5 +$\\{var\_flag}\K\\{assignment}$;\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_cmd}=\\{equals}$ \1\&{then}\5 +\\{do\_equation}\6 +\4\&{else} \&{if} $\\{cur\_cmd}=\\{assignment}$ \1\&{then}\5 +\\{do\_assignment};\2\2\6 +\&{if} $\\{internal}[\\{tracing\_commands}]>\\{two}$ \1\&{then}\5 +\X998:Trace the current assignment\X;\2\6 +\&{if} $\\{info}(\\{lhs})>\\{hash\_end}$ \1\&{then}\5 +\X999:Assign the current expression to an internal variable\X\6 +\4\&{else} \X1000:Assign the current expression to the variable \\{lhs}\X;\2\6 +$\\{flush\_node\_list}(\\{lhs})$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M997. \P$\X997:Trace the current equation\X\S$\6 +\&{begin} \37\\{begin\_diagnostic};\5 +$\\{print\_nl}(\.{"\{("})$;\5 +$\\{print\_exp}(\\{lhs},\390)$;\5 +$\\{print}(\.{")=("})$;\5 +$\\{print\_exp}(\\{null},\390)$;\5 +$\\{print}(\.{")\}"})$;\5 +$\\{end\_diagnostic}(\\{false})$;\6 +\&{end}\par +\U995.\fi + +\M998. \P$\X998:Trace the current assignment\X\S$\6 +\&{begin} \37\\{begin\_diagnostic};\5 +$\\{print\_nl}(\.{"\{"})$;\6 +\&{if} $\\{info}(\\{lhs})>\\{hash\_end}$ \1\&{then}\5 +$\\{slow\_print}(\\{int\_name}[\\{info}(\\{lhs})-(\\{hash\_end})])$\6 +\4\&{else} $\\{show\_token\_list}(\\{lhs},\39\\{null},\391000,\390)$;\2\6 +$\\{print}(\.{":="})$;\5 +$\\{print\_exp}(\\{null},\390)$;\5 +$\\{print\_char}(\.{"\}"})$;\5 +$\\{end\_diagnostic}(\\{false})$;\6 +\&{end}\par +\U996.\fi + +\M999. \P$\X999:Assign the current expression to an internal variable\X\S$\6 +\&{if} $\\{cur\_type}=\\{known}$ \1\&{then}\5 +$\\{internal}[\\{info}(\\{lhs})-(\\{hash\_end})]\K\\{cur\_exp}$\6 +\4\&{else} \&{begin} \37$\\{exp\_err}(\.{"Internal\ quantity\ \`"})$;\5 +$\\{slow\_print}(\\{int\_name}[\\{info}(\\{lhs})-(\\{hash\_end})])$;\5 +$\\{print}(\.{"\'\ must\ receive\ a\ known\ value"})$;\5 +$\\{help2}(\.{"I\ can\'t\ set\ an\ internal\ quantity\ to\ anything\ but\ a\ +known"})$\6 +$(\.{"numeric\ value,\ so\ I\'ll\ have\ to\ ignore\ this\ assignment."})$;\5 +\\{put\_get\_error};\6 +\&{end}\2\par +\U996.\fi + +\M1000. \P$\X1000:Assign the current expression to the variable \\{lhs}\X\S$\6 +\&{begin} \37$\|p\K\\{find\_variable}(\\{lhs})$;\6 +\&{if} $\|p\I\\{null}$ \1\&{then}\6 +\&{begin} \37$\|q\K\\{stash\_cur\_exp}$;\5 +$\\{cur\_type}\K\\{und\_type}(\|p)$;\5 +$\\{recycle\_value}(\|p)$;\5 +$\\{type}(\|p)\K\\{cur\_type}$;\5 +$\\{value}(\|p)\K\\{null}$;\5 +$\\{make\_exp\_copy}(\|p)$;\5 +$\|p\K\\{stash\_cur\_exp}$;\5 +$\\{unstash\_cur\_exp}(\|q)$;\5 +$\\{make\_eq}(\|p)$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{obliterated}(\\{lhs})$;\5 +\\{put\_get\_error};\6 +\&{end};\2\6 +\&{end}\par +\U996.\fi + +\M1001. And now we get to the nitty-gritty. The \\{make\_eq} procedure is given +a pointer to a capsule that is to be equated to the current expression. + +\Y\P$\4\X1001:Declare the procedure called \\{make\_eq}\X\S$\6 +\4\&{procedure}\1\ \37$\\{make\_eq}(\\{lhs}:\\{pointer})$;\6 +\4\&{label} \37$\\{restart},\39\\{done},\39\\{not\_found}$;\6 +\4\&{var} \37\|t: \37\\{small\_number};\C{type of the left-hand side}\6 +\|v: \37\\{integer};\C{value of the left-hand side}\6 +$\|p,\39\|q$: \37\\{pointer};\C{pointers inside of big nodes}\2\6 +\&{begin} \37\\{restart}: \37$\|t\K\\{type}(\\{lhs})$;\6 +\&{if} $\|t\L\\{pair\_type}$ \1\&{then}\5 +$\|v\K\\{value}(\\{lhs})$;\2\6 +\&{case} $\|t$ \1\&{of}\6 +\hbox{\4}\X1003:For each type \|t, make an equation and \&{goto} \\{done} +unless \\{cur\_type} is incompatible with~\|t\X\2\6 +\&{end};\C{all cases have been listed}\6 +\X1002:Announce that the equation cannot be performed\X;\6 +\4\\{done}: \37\\{check\_arith};\5 +$\\{recycle\_value}(\\{lhs})$;\5 +$\\{free\_node}(\\{lhs},\39\\{value\_node\_size})$;\6 +\&{end};\par +\U995.\fi + +\M1002. \P$\X1002:Announce that the equation cannot be performed\X\S$\6 +$\\{disp\_err}(\\{lhs},\39\.{""})$;\5 +$\\{exp\_err}(\.{"Equation\ cannot\ be\ performed\ ("})$;\6 +\&{if} $\\{type}(\\{lhs})\L\\{pair\_type}$ \1\&{then}\5 +$\\{print\_type}(\\{type}(\\{lhs}))$\ \&{else} $\\{print}(\.{"numeric"})$;\2\6 +$\\{print\_char}(\.{"="})$;\6 +\&{if} $\\{cur\_type}\L\\{pair\_type}$ \1\&{then}\5 +$\\{print\_type}(\\{cur\_type})$\ \&{else} $\\{print}(\.{"numeric"})$;\2\6 +$\\{print\_char}(\.{")"})$;\6 +$\\{help2}(\.{"I\'m\ sorry,\ but\ I\ don\'t\ know\ how\ to\ make\ such\ things\ +equal."})$\6 +$(\.{"(See\ the\ two\ expressions\ just\ above\ the\ error\ message.)"})$;\5 +\\{put\_get\_error}\par +\U1001.\fi + +\M1003. \P$\X1003:For each type \|t, make an equation and \&{goto} \\{done} +unless \\{cur\_type} is incompatible with~\|t\X\S$\6 +\4$\\{boolean\_type},\39\\{string\_type},\39\\{pen\_type},\39\\{path\_type},\39% +\\{picture\_type}$: \37\&{if} $\\{cur\_type}=\|t+\\{unknown\_tag}$ \1\&{then}\6 +\&{begin} \37$\\{nonlinear\_eq}(\|v,\39\\{cur\_exp},\39\\{false})$;\5 +\&{goto} \37\\{done};\6 +\&{end}\6 +\4\&{else} \&{if} $\\{cur\_type}=\|t$ \1\&{then}\5 +\X1004:Report redundant or inconsistent equation and \&{goto} \\{done}\X;\2\2\6 +\4\\{unknown\_types}: \37\&{if} $\\{cur\_type}=\|t-\\{unknown\_tag}$ \1\&{then}% +\6 +\&{begin} \37$\\{nonlinear\_eq}(\\{cur\_exp},\39\\{lhs},\39\\{true})$;\5 +\&{goto} \37\\{done};\6 +\&{end}\6 +\4\&{else} \&{if} $\\{cur\_type}=\|t$ \1\&{then}\6 +\&{begin} \37$\\{ring\_merge}(\\{lhs},\39\\{cur\_exp})$;\5 +\&{goto} \37\\{done};\6 +\&{end}\6 +\4\&{else} \&{if} $\\{cur\_type}=\\{pair\_type}$ \1\&{then}\6 +\&{if} $\|t=\\{unknown\_path}$ \1\&{then}\6 +\&{begin} \37\\{pair\_to\_path};\5 +\&{goto} \37\\{restart};\6 +\&{end};\2\2\2\2\6 +\4$\\{transform\_type},\39\\{pair\_type}$: \37\&{if} $\\{cur\_type}=\|t$ \1% +\&{then}\5 +\X1005:Do multiple equations and \&{goto} \\{done}\X;\2\6 +\4$\\{known},\39\\{dependent},\39\\{proto\_dependent},\39\\{independent}$: \37% +\&{if} $\\{cur\_type}\G\\{known}$ \1\&{then}\6 +\&{begin} \37$\\{try\_eq}(\\{lhs},\39\\{null})$;\5 +\&{goto} \37\\{done};\6 +\&{end};\2\6 +\4\\{vacuous}: \37\\{do\_nothing};\par +\U1001.\fi + +\M1004. \P$\X1004:Report redundant or inconsistent equation and \&{goto} % +\\{done}\X\S$\6 +\&{begin} \37\&{if} $\\{cur\_type}\L\\{string\_type}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{cur\_type}=\\{string\_type}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{str\_vs\_str}(\|v,\39\\{cur\_exp})\I0$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +\&{end}\6 +\4\&{else} \&{if} $\|v\I\\{cur\_exp}$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\2\6 +\X623:Exclaim about a redundant equation\X;\6 +\&{goto} \37\\{done};\6 +\&{end};\2\6 +$\\{print\_err}(\.{"Redundant\ or\ inconsistent\ equation"})$;\5 +$\\{help2}(\.{"An\ equation\ between\ already-known\ quantities\ can\'t\ +help."})$\6 +$(\.{"But\ don\'t\ worry;\ continue\ and\ I\'ll\ just\ ignore\ it."})$;\5 +\\{put\_get\_error};\5 +\&{goto} \37\\{done};\6 +\4\\{not\_found}: \37$\\{print\_err}(\.{"Inconsistent\ equation"})$;\5 +$\\{help2}(\.{"The\ equation\ I\ just\ read\ contradicts\ what\ was\ said\ +before."})$\6 +$(\.{"But\ don\'t\ worry;\ continue\ and\ I\'ll\ just\ ignore\ it."})$;\5 +\\{put\_get\_error};\5 +\&{goto} \37\\{done};\6 +\&{end}\par +\U1003.\fi + +\M1005. \P$\X1005:Do multiple equations and \&{goto} \\{done}\X\S$\6 +\&{begin} \37$\|p\K\|v+\\{big\_node\_size}[\|t]$;\5 +$\|q\K\\{value}(\\{cur\_exp})+\\{big\_node\_size}[\|t]$;\6 +\1\&{repeat} \37$\|p\K\|p-2$;\5 +$\|q\K\|q-2$;\5 +$\\{try\_eq}(\|p,\39\|q)$;\6 +\4\&{until}\5 +$\|p=\|v$;\2\6 +\&{goto} \37\\{done};\6 +\&{end}\par +\U1003.\fi + +\M1006. The first argument to \\{try\_eq} is the location of a value node +in a capsule that will soon be recycled. The second argument is +either a location within a pair or transform node pointed to by +\\{cur\_exp}, or it is \\{null} (which means that \\{cur\_exp} itself +serves as the second argument). The idea is to leave \\{cur\_exp} unchanged, +but to equate the two operands. + +\Y\P$\4\X1006:Declare the procedure called \\{try\_eq}\X\S$\6 +\4\&{procedure}\1\ \37$\\{try\_eq}(\|l,\39\|r:\\{pointer})$;\6 +\4\&{label} \37$\\{done},\39\\{done1}$;\6 +\4\&{var} \37\|p: \37\\{pointer};\C{dependency list for right operand minus +left operand}\6 +\|t: \37$\\{known}\to\\{independent}$;\C{the type of list \|p}\6 +\|q: \37\\{pointer};\C{the constant term of \|p is here}\6 +\\{pp}: \37\\{pointer};\C{dependency list for right operand}\6 +\\{tt}: \37$\\{dependent}\to\\{independent}$;\C{the type of list \\{pp}}\6 +\\{copied}: \37\\{boolean};\C{have we copied a list that ought to be recycled?}% +\2\6 +\&{begin} \37\X1007:Remove the left operand from its container, negate it, and +put it into dependency list~\|p with constant term~\|q\X;\6 +\X1009:Add the right operand to list \|p\X;\6 +\&{if} $\\{info}(\|p)=\\{null}$ \1\&{then}\5 +\X1008:Deal with redundant or inconsistent equation\X\6 +\4\&{else} \&{begin} \37$\\{linear\_eq}(\|p,\39\|t)$;\6 +\&{if} $\|r=\\{null}$ \1\&{then}\6 +\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\6 +\&{if} $\\{type}(\\{cur\_exp})=\\{known}$ \1\&{then}\6 +\&{begin} \37$\\{pp}\K\\{cur\_exp}$;\5 +$\\{cur\_exp}\K\\{value}(\\{cur\_exp})$;\5 +$\\{cur\_type}\K\\{known}$;\5 +$\\{free\_node}(\\{pp},\39\\{value\_node\_size})$;\6 +\&{end};\2\2\2\6 +\&{end};\2\6 +\&{end};\par +\U995.\fi + +\M1007. \P$\X1007:Remove the left operand from its container, negate it, and +put it into dependency list~\|p with constant term~\|q\X\S$\6 +$\|t\K\\{type}(\|l)$;\6 +\&{if} $\|t=\\{known}$ \1\&{then}\6 +\&{begin} \37$\|t\K\\{dependent}$;\5 +$\|p\K\\{const\_dependency}(-\\{value}(\|l))$;\5 +$\|q\K\|p$;\6 +\&{end}\6 +\4\&{else} \&{if} $\|t=\\{independent}$ \1\&{then}\6 +\&{begin} \37$\|t\K\\{dependent}$;\5 +$\|p\K\\{single\_dependency}(\|l)$;\5 +$\\{negate}(\\{value}(\|p))$;\5 +$\|q\K\\{dep\_final}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|p\K\\{dep\_list}(\|l)$;\5 +$\|q\K\|p$;\6 +\~ \1\&{loop}\ \&{begin} \37$\\{negate}(\\{value}(\|q))$;\6 +\&{if} $\\{info}(\|q)=\\{null}$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +$\|q\K\\{link}(\|q)$;\6 +\&{end};\2\6 +\4\\{done}: \37$\\{link}(\\{prev\_dep}(\|l))\K\\{link}(\|q)$;\5 +$\\{prev\_dep}(\\{link}(\|q))\K\\{prev\_dep}(\|l)$;\5 +$\\{type}(\|l)\K\\{known}$;\6 +\&{end}\2\2\par +\U1006.\fi + +\M1008. \P$\X1008:Deal with redundant or inconsistent equation\X\S$\6 +\&{begin} \37\&{if} $\\{abs}(\\{value}(\|p))>64$ \1\&{then}\C{off by .001 or +more}\6 +\&{begin} \37$\\{print\_err}(\.{"Inconsistent\ equation"})$;\6 +$\\{print}(\.{"\ (off\ by\ "})$;\5 +$\\{print\_scaled}(\\{value}(\|p))$;\5 +$\\{print\_char}(\.{")"})$;\5 +$\\{help2}(\.{"The\ equation\ I\ just\ read\ contradicts\ what\ was\ said\ +before."})$\6 +$(\.{"But\ don\'t\ worry;\ continue\ and\ I\'ll\ just\ ignore\ it."})$;\5 +\\{put\_get\_error};\6 +\&{end}\6 +\4\&{else} \&{if} $\|r=\\{null}$ \1\&{then}\5 +\X623:Exclaim about a redundant equation\X;\2\2\6 +$\\{free\_node}(\|p,\39\\{dep\_node\_size})$;\6 +\&{end}\par +\U1006.\fi + +\M1009. \P$\X1009:Add the right operand to list \|p\X\S$\6 +\&{if} $\|r=\\{null}$ \1\&{then}\6 +\&{if} $\\{cur\_type}=\\{known}$ \1\&{then}\6 +\&{begin} \37$\\{value}(\|q)\K\\{value}(\|q)+\\{cur\_exp}$;\5 +\&{goto} \37\\{done1};\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{tt}\K\\{cur\_type}$;\6 +\&{if} $\\{tt}=\\{independent}$ \1\&{then}\5 +$\\{pp}\K\\{single\_dependency}(\\{cur\_exp})$\6 +\4\&{else} $\\{pp}\K\\{dep\_list}(\\{cur\_exp})$;\2\6 +\&{end}\2\6 +\4\&{else} \&{if} $\\{type}(\|r)=\\{known}$ \1\&{then}\6 +\&{begin} \37$\\{value}(\|q)\K\\{value}(\|q)+\\{value}(\|r)$;\5 +\&{goto} \37\\{done1};\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{tt}\K\\{type}(\|r)$;\6 +\&{if} $\\{tt}=\\{independent}$ \1\&{then}\5 +$\\{pp}\K\\{single\_dependency}(\|r)$\6 +\4\&{else} $\\{pp}\K\\{dep\_list}(\|r)$;\2\6 +\&{end};\2\2\6 +\&{if} $\\{tt}\I\\{independent}$ \1\&{then}\5 +$\\{copied}\K\\{false}$\6 +\4\&{else} \&{begin} \37$\\{copied}\K\\{true}$;\5 +$\\{tt}\K\\{dependent}$;\6 +\&{end};\2\6 +\X1010:Add dependency list \\{pp} of type \\{tt} to dependency list~\|p of +type~\|t\X;\6 +\&{if} $\\{copied}$ \1\&{then}\5 +$\\{flush\_node\_list}(\\{pp})$;\2\6 +\4\\{done1}: \37\par +\U1006.\fi + +\M1010. \P$\X1010:Add dependency list \\{pp} of type \\{tt} to dependency list~% +\|p of type~\|t\X\S$\6 +$\\{watch\_coefs}\K\\{false}$;\6 +\&{if} $\|t=\\{tt}$ \1\&{then}\5 +$\|p\K\\{p\_plus\_q}(\|p,\39\\{pp},\39\|t)$\6 +\4\&{else} \&{if} $\|t=\\{proto\_dependent}$ \1\&{then}\5 +$\|p\K\\{p\_plus\_fq}(\|p,\39\\{unity},\39\\{pp},\39\\{proto\_dependent},\39% +\\{dependent})$\6 +\4\&{else} \&{begin} \37$\|q\K\|p$;\6 +\&{while} $\\{info}(\|q)\I\\{null}$ \1\&{do}\6 +\&{begin} \37$\\{value}(\|q)\K\\{round\_fraction}(\\{value}(\|q))$;\5 +$\|q\K\\{link}(\|q)$;\6 +\&{end};\2\6 +$\|t\K\\{proto\_dependent}$;\5 +$\|p\K\\{p\_plus\_q}(\|p,\39\\{pp},\39\|t)$;\6 +\&{end};\2\2\6 +$\\{watch\_coefs}\K\\{true}$;\par +\U1009.\fi + +\M1011. Our next goal is to process type declarations. For this purpose it's +convenient to have a procedure that scans a $\langle\,$declared +variable$\,\rangle$ and returns the corresponding token list. After the +following procedure has acted, the token after the declared variable +will have been scanned, so it will appear in \\{cur\_cmd}, \\{cur\_mod}, +and~\\{cur\_sym}. + +\Y\P$\4\X1011:Declare the function called \\{scan\_declared\_variable}\X\S$\6 +\4\&{function}\1\ \37\\{scan\_declared\_variable}: \37\\{pointer};\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37\|x: \37\\{pointer};\C{hash address of the variable's root}\6 +$\|h,\39\|t$: \37\\{pointer};\C{head and tail of the token list to be returned}% +\6 +\|l: \37\\{pointer};\C{hash address of left bracket}\2\6 +\&{begin} \37\\{get\_symbol};\5 +$\|x\K\\{cur\_sym}$;\6 +\&{if} $\\{cur\_cmd}\I\\{tag\_token}$ \1\&{then}\5 +$\\{clear\_symbol}(\|x,\39\\{false})$;\2\6 +$\|h\K\\{get\_avail}$;\5 +$\\{info}(\|h)\K\|x$;\5 +$\|t\K\|h$;\6 +\~ \1\&{loop}\ \&{begin} \37\\{get\_x\_next};\6 +\&{if} $\\{cur\_sym}=0$ \1\&{then}\5 +\&{goto} \37\\{done};\2\6 +\&{if} $\\{cur\_cmd}\I\\{tag\_token}$ \1\&{then}\6 +\&{if} $\\{cur\_cmd}\I\\{internal\_quantity}$ \1\&{then}\6 +\&{if} $\\{cur\_cmd}=\\{left\_bracket}$ \1\&{then}\5 +\X1012:Descend past a collective subscript\X\6 +\4\&{else} \&{goto} \37\\{done};\2\2\2\6 +$\\{link}(\|t)\K\\{get\_avail}$;\5 +$\|t\K\\{link}(\|t)$;\5 +$\\{info}(\|t)\K\\{cur\_sym}$;\6 +\&{end};\2\6 +\4\\{done}: \37\&{if} $\\{eq\_type}(\|x)\I\\{tag\_token}$ \1\&{then}\5 +$\\{clear\_symbol}(\|x,\39\\{false})$;\2\6 +\&{if} $\\{equiv}(\|x)=\\{null}$ \1\&{then}\5 +$\\{new\_root}(\|x)$;\2\6 +$\\{scan\_declared\_variable}\K\|h$;\6 +\&{end};\par +\U697.\fi + +\M1012. If the subscript isn't collective, we don't accept it as part of the +declared variable. + +\Y\P$\4\X1012:Descend past a collective subscript\X\S$\6 +\&{begin} \37$\|l\K\\{cur\_sym}$;\5 +\\{get\_x\_next};\6 +\&{if} $\\{cur\_cmd}\I\\{right\_bracket}$ \1\&{then}\6 +\&{begin} \37\\{back\_input};\5 +$\\{cur\_sym}\K\|l$;\5 +$\\{cur\_cmd}\K\\{left\_bracket}$;\5 +\&{goto} \37\\{done};\6 +\&{end}\6 +\4\&{else} $\\{cur\_sym}\K\\{collective\_subscript}$;\2\6 +\&{end}\par +\U1011.\fi + +\M1013. Type declarations are introduced by the following primitive operations. + +\Y\P$\4\X192:Put each of \MF's primitives into the hash table\X\mathrel{+}\S$\6 +$\\{primitive}(\.{"numeric"},\39\\{type\_name},\39\\{numeric\_type})$;\6 +$\\{primitive}(\.{"string"},\39\\{type\_name},\39\\{string\_type})$;\6 +$\\{primitive}(\.{"boolean"},\39\\{type\_name},\39\\{boolean\_type})$;\6 +$\\{primitive}(\.{"path"},\39\\{type\_name},\39\\{path\_type})$;\6 +$\\{primitive}(\.{"pen"},\39\\{type\_name},\39\\{pen\_type})$;\6 +$\\{primitive}(\.{"picture"},\39\\{type\_name},\39\\{picture\_type})$;\6 +$\\{primitive}(\.{"transform"},\39\\{type\_name},\39\\{transform\_type})$;\6 +$\\{primitive}(\.{"pair"},\39\\{type\_name},\39\\{pair\_type})$;\par +\fi + +\M1014. \P$\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of +primitives\X\mathrel{+}\S$\6 +\4\\{type\_name}: \37$\\{print\_type}(\|m)$;\par +\fi + +\M1015. Now we are ready to handle type declarations, assuming that a +\\{type\_name} has just been scanned. + +\Y\P$\4\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_type\_declaration};\6 +\4\&{var} \37\|t: \37\\{small\_number};\C{the type being declared}\6 +\|p: \37\\{pointer};\C{token list for a declared variable}\6 +\|q: \37\\{pointer};\C{value node for the variable}\2\6 +\&{begin} \37\&{if} $\\{cur\_mod}\G\\{transform\_type}$ \1\&{then}\5 +$\|t\K\\{cur\_mod}$\ \&{else} $\|t\K\\{cur\_mod}+\\{unknown\_tag}$;\2\6 +\1\&{repeat} \37$\|p\K\\{scan\_declared\_variable}$;\5 +$\\{flush\_variable}(\\{equiv}(\\{info}(\|p)),\39\\{link}(\|p),\39\\{false})$;\6 +$\|q\K\\{find\_variable}(\|p)$;\6 +\&{if} $\|q\I\\{null}$ \1\&{then}\6 +\&{begin} \37$\\{type}(\|q)\K\|t$;\5 +$\\{value}(\|q)\K\\{null}$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Declared\ variable\ conflicts\ with% +\ previous\ vardef"})$;\5 +$\\{help2}(\.{"You\ can\'t\ use,\ e.g.,\ \`numeric\ foo[]\'\ after\ \`vardef\ +foo\'."})$\6 +$(\.{"Proceed,\ and\ I\'ll\ ignore\ the\ illegal\ redeclaration."})$;\5 +\\{put\_get\_error};\6 +\&{end};\2\6 +$\\{flush\_list}(\|p)$;\6 +\&{if} $\\{cur\_cmd}<\\{comma}$ \1\&{then}\5 +\X1016:Flush spurious symbols after the declared variable\X;\2\6 +\4\&{until}\5 +\\{end\_of\_statement};\2\6 +\&{end};\par +\fi + +\M1016. \P$\X1016:Flush spurious symbols after the declared variable\X\S$\6 +\&{begin} \37$\\{print\_err}(\.{"Illegal\ suffix\ of\ declared\ variable\ will\ +be\ flushed"})$;\5 +$\\{help5}(\.{"Variables\ in\ declarations\ must\ consist\ entirely\ of"})$\6 +$(\.{"names\ and\ collective\ subscripts,\ e.g.,\ \`x[]a\'."})$\6 +$(\.{"Are\ you\ trying\ to\ use\ a\ reserved\ word\ in\ a\ variable\ name?"})$\6 +$(\.{"I\'m\ going\ to\ discard\ the\ junk\ I\ found\ here,"})$\6 +$(\.{"up\ to\ the\ next\ comma\ or\ the\ end\ of\ the\ declaration."})$;\6 +\&{if} $\\{cur\_cmd}=\\{numeric\_token}$ \1\&{then}\5 +$\\{help\_line}[2]\K\.{"Explicit\ subscripts\ like\ \`x15a\'\ aren\'t\ +permitted."}$;\2\6 +\\{put\_get\_error};\5 +$\\{scanner\_status}\K\\{flushing}$;\6 +\1\&{repeat} \37\\{get\_next};\5 +\X743:Decrease the string reference count, if the current token is a string\X;\6 +\4\&{until}\5 +$\\{cur\_cmd}\G\\{comma}$;\C{either \\{end\_of\_statement} or $\\{cur\_cmd}=% +\\{comma}$}\2\6 +$\\{scanner\_status}\K\\{normal}$;\6 +\&{end}\par +\U1015.\fi + +\M1017. \MF's \\{main\_control} procedure just calls \\{do\_statement} +repeatedly +until coming to the end of the user's program. +Each execution of \\{do\_statement} concludes with +$\\{cur\_cmd}=\\{semicolon}$, \\{end\_group}, or \\{stop}. + +\Y\P\4\&{procedure}\1\ \37\\{main\_control};\2\6 +\&{begin} \37\1\&{repeat} \37\\{do\_statement};\6 +\&{if} $\\{cur\_cmd}=\\{end\_group}$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"Extra\ \`endgroup\'"})$;\5 +$\\{help2}(\.{"I\'m\ not\ currently\ working\ on\ a\ \`begingroup\',"})$\6 +$(\.{"so\ I\ had\ better\ not\ try\ to\ end\ anything."})$;\5 +$\\{flush\_error}(0)$;\6 +\&{end};\2\6 +\4\&{until}\5 +$\\{cur\_cmd}=\\{stop}$;\2\6 +\&{end};\par +\fi + +\M1018. \P$\X192:Put each of \MF's primitives into the hash table\X\mathrel{+}% +\S$\6 +$\\{primitive}(\.{"end"},\39\\{stop},\390)$;\6 +$\\{primitive}(\.{"dump"},\39\\{stop},\391)$;\par +\fi + +\M1019. \P$\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of +primitives\X\mathrel{+}\S$\6 +\4\\{stop}: \37\&{if} $\|m=0$ \1\&{then}\5 +$\\{print}(\.{"end"})$\ \&{else} $\\{print}(\.{"dump"})$;\2\par +\fi + +\N1020. \[44] Commands. +Let's turn now to statements that are classified as ``commands'' because +of their imperative nature. We'll begin with simple ones, so that it +will be clear how to hook command processing into the \\{do\_statement} +routine; +then we'll tackle the tougher commands. + +Here's one of the simplest: + +\Y\P$\4\X1020:Cases of \\{do\_statement} that invoke particular commands\X\S$\6 +\4\\{random\_seed}: \37\\{do\_random\_seed};\par +\As1023, 1026, 1030, 1033, 1039, 1058, 1069, 1076, 1081, 1100\ETs1175. +\U992.\fi + +\M1021. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_random\_seed};\2\6 +\&{begin} \37\\{get\_x\_next};\6 +\&{if} $\\{cur\_cmd}\I\\{assignment}$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\.{":="})$;\5 +$\\{help1}(\.{"Always\ say\ \`randomseed:=<numeric\ expression>\'."})$;\5 +\\{back\_error};\6 +\&{end};\2\6 +\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\6 +\&{begin} \37$\\{exp\_err}(\.{"Unknown\ value\ will\ be\ ignored"})$;\5 +$\\{help2}(\.{"Your\ expression\ was\ too\ random\ for\ me\ to\ handle,"})$\6 +$(\.{"so\ I\ won\'t\ change\ the\ random\ seed\ just\ now."})$;\6 +$\\{put\_get\_flush\_error}(0)$;\6 +\&{end}\6 +\4\&{else} \X1022:Initialize the random seed to \\{cur\_exp}\X;\2\6 +\&{end};\par +\fi + +\M1022. \P$\X1022:Initialize the random seed to \\{cur\_exp}\X\S$\6 +\&{begin} \37$\\{init\_randoms}(\\{cur\_exp})$;\6 +\&{if} $\\{selector}\G\\{log\_only}$ \1\&{then}\6 +\&{begin} \37$\\{old\_setting}\K\\{selector}$;\5 +$\\{selector}\K\\{log\_only}$;\5 +$\\{print\_nl}(\.{"\{randomseed:="})$;\5 +$\\{print\_scaled}(\\{cur\_exp})$;\5 +$\\{print\_char}(\.{"\}"})$;\5 +$\\{print\_nl}(\.{""})$;\5 +$\\{selector}\K\\{old\_setting}$;\6 +\&{end};\2\6 +\&{end}\par +\U1021.\fi + +\M1023. And here's another simple one (somewhat different in flavor): + +\Y\P$\4\X1020:Cases of \\{do\_statement} that invoke particular commands\X% +\mathrel{+}\S$\6 +\4\\{mode\_command}: \37\&{begin} \37\\{print\_ln};\5 +$\\{interaction}\K\\{cur\_mod}$;\5 +\X70:Initialize the print \\{selector} based on \\{interaction}\X;\6 +\&{if} $\\{log\_opened}$ \1\&{then}\5 +$\\{selector}\K\\{selector}+2$;\2\6 +\\{get\_x\_next};\6 +\&{end};\par +\fi + +\M1024. \P$\X192:Put each of \MF's primitives into the hash table\X\mathrel{+}% +\S$\6 +$\\{primitive}(\.{"batchmode"},\39\\{mode\_command},\39\\{batch\_mode})$;\5 +$\\{primitive}(\.{"nonstopmode"},\39\\{mode\_command},\39\\{nonstop\_mode})$;\5 +$\\{primitive}(\.{"scrollmode"},\39\\{mode\_command},\39\\{scroll\_mode})$;\5 +$\\{primitive}(\.{"errorstopmode"},\39\\{mode\_command},\39\\{error\_stop% +\_mode})$;\par +\fi + +\M1025. \P$\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of +primitives\X\mathrel{+}\S$\6 +\4\\{mode\_command}: \37\&{case} $\|m$ \1\&{of}\6 +\4\\{batch\_mode}: \37$\\{print}(\.{"batchmode"})$;\6 +\4\\{nonstop\_mode}: \37$\\{print}(\.{"nonstopmode"})$;\6 +\4\\{scroll\_mode}: \37$\\{print}(\.{"scrollmode"})$;\6 +\4\&{othercases} \37$\\{print}(\.{"errorstopmode"})$\2\6 +\&{endcases};\par +\fi + +\M1026. The `\&{inner}' and `\&{outer}' commands are only slightly harder. + +\Y\P$\4\X1020:Cases of \\{do\_statement} that invoke particular commands\X% +\mathrel{+}\S$\6 +\4\\{protection\_command}: \37\\{do\_protection};\par +\fi + +\M1027. \P$\X192:Put each of \MF's primitives into the hash table\X\mathrel{+}% +\S$\6 +$\\{primitive}(\.{"inner"},\39\\{protection\_command},\390)$;\6 +$\\{primitive}(\.{"outer"},\39\\{protection\_command},\391)$;\par +\fi + +\M1028. \P$\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of +primitives\X\mathrel{+}\S$\6 +\4\\{protection\_command}: \37\&{if} $\|m=0$ \1\&{then}\5 +$\\{print}(\.{"inner"})$\ \&{else} $\\{print}(\.{"outer"})$;\2\par +\fi + +\M1029. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_protection};\6 +\4\&{var} \37\|m: \37$0\to1$;\C{0 to unprotect, 1 to protect}\6 +\|t: \37\\{halfword};\C{the \\{eq\_type} before we change it}\2\6 +\&{begin} \37$\|m\K\\{cur\_mod}$;\6 +\1\&{repeat} \37\\{get\_symbol};\5 +$\|t\K\\{eq\_type}(\\{cur\_sym})$;\6 +\&{if} $\|m=0$ \1\&{then}\6 +\&{begin} \37\&{if} $\|t\G\\{outer\_tag}$ \1\&{then}\5 +$\\{eq\_type}(\\{cur\_sym})\K\|t-\\{outer\_tag}$;\2\6 +\&{end}\6 +\4\&{else} \&{if} $\|t<\\{outer\_tag}$ \1\&{then}\5 +$\\{eq\_type}(\\{cur\_sym})\K\|t+\\{outer\_tag}$;\2\2\6 +\\{get\_x\_next};\6 +\4\&{until}\5 +$\\{cur\_cmd}\I\\{comma}$;\2\6 +\&{end};\par +\fi + +\M1030. \MF\ never defines the tokens `\.(' and `\.)' to be primitives, but +plain \MF\ begins with the declaration `\&{delimiters} \.{()}'. Such a +declaration assigns the command code \\{left\_delimiter} to `\.{(}' and +\\{right\_delimiter} to `\.{)}'; the \\{equiv} of each delimiter is the +hash address of its mate. + +\Y\P$\4\X1020:Cases of \\{do\_statement} that invoke particular commands\X% +\mathrel{+}\S$\6 +\4\\{delimiters}: \37\\{def\_delims};\par +\fi + +\M1031. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{def\_delims};\6 +\4\&{var} \37$\\{l\_delim},\39\\{r\_delim}$: \37\\{pointer};\C{the new +delimiter pair}\2\6 +\&{begin} \37\\{get\_clear\_symbol};\5 +$\\{l\_delim}\K\\{cur\_sym}$;\6 +\\{get\_clear\_symbol};\5 +$\\{r\_delim}\K\\{cur\_sym}$;\6 +$\\{eq\_type}(\\{l\_delim})\K\\{left\_delimiter}$;\5 +$\\{equiv}(\\{l\_delim})\K\\{r\_delim}$;\6 +$\\{eq\_type}(\\{r\_delim})\K\\{right\_delimiter}$;\5 +$\\{equiv}(\\{r\_delim})\K\\{l\_delim}$;\6 +\\{get\_x\_next};\6 +\&{end};\par +\fi + +\M1032. Here is a procedure that is called when \MF\ has reached a point +where some right delimiter is mandatory. + +\Y\P$\4\X1032:Declare the procedure called \\{check\_delimiter}\X\S$\6 +\4\&{procedure}\1\ \37$\\{check\_delimiter}(\\{l\_delim},\39\\{r\_delim}:% +\\{pointer})$;\6 +\4\&{label} \37\\{exit};\2\6 +\&{begin} \37\&{if} $\\{cur\_cmd}=\\{right\_delimiter}$ \1\&{then}\6 +\&{if} $\\{cur\_mod}=\\{l\_delim}$ \1\&{then}\5 +\&{return};\2\2\6 +\&{if} $\\{cur\_sym}\I\\{r\_delim}$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\\{text}(\\{r\_delim}))$;\6 +$\\{help2}(\.{"I\ found\ no\ right\ delimiter\ to\ match\ a\ left\ one.\ So\ I% +\'ve"})$\6 +$(\.{"put\ one\ in,\ behind\ the\ scenes;\ this\ may\ fix\ the\ problem."})$;\5 +\\{back\_error};\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{print\_err}(\.{"The\ token\ \`"})$;\5 +$\\{slow\_print}(\\{text}(\\{r\_delim}))$;\5 +$\\{print}(\.{"\'\ is\ no\ longer\ a\ right\ delimiter"})$;\5 +$\\{help3}(\.{"Strange:\ This\ token\ has\ lost\ its\ former\ meaning!"})$\6 +$(\.{"I\'ll\ read\ it\ as\ a\ right\ delimiter\ this\ time;"})$\6 +$(\.{"but\ watch\ out,\ I\'ll\ probably\ miss\ it\ later."})$;\5 +\\{error};\6 +\&{end};\2\6 +\4\\{exit}: \37\&{end};\par +\U697.\fi + +\M1033. The next four commands save or change the values associated with +tokens. + +\Y\P$\4\X1020:Cases of \\{do\_statement} that invoke particular commands\X% +\mathrel{+}\S$\6 +\4\\{save\_command}: \37\1\&{repeat} \37\\{get\_symbol};\5 +$\\{save\_variable}(\\{cur\_sym})$;\5 +\\{get\_x\_next};\6 +\4\&{until}\5 +$\\{cur\_cmd}\I\\{comma}$;\2\6 +\4\\{interim\_command}: \37\\{do\_interim};\6 +\4\\{let\_command}: \37\\{do\_let};\6 +\4\\{new\_internal}: \37\\{do\_new\_internal};\par +\fi + +\M1034. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_statement};\5 +\\{forward};\5 +\hbox{\2}\6 +\4\&{procedure}\1\ \37\\{do\_interim};\2\6 +\&{begin} \37\\{get\_x\_next};\6 +\&{if} $\\{cur\_cmd}\I\\{internal\_quantity}$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"The\ token\ \`"})$;\6 +\&{if} $\\{cur\_sym}=0$ \1\&{then}\5 +$\\{print}(\.{"(\%CAPSULE)"})$\6 +\4\&{else} $\\{slow\_print}(\\{text}(\\{cur\_sym}))$;\2\6 +$\\{print}(\.{"\'\ isn\'t\ an\ internal\ quantity"})$;\5 +$\\{help1}(\.{"Something\ like\ \`tracingonline\'\ should\ follow\ \`interim% +\'."})$;\5 +\\{back\_error};\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{save\_internal}(\\{cur\_mod})$;\5 +\\{back\_input};\6 +\&{end};\2\6 +\\{do\_statement};\6 +\&{end};\par +\fi + +\M1035. The following procedure is careful not to undefine the left-hand symbol +too soon, lest commands like `{\tt let x=x}' have a surprising effect. + +\Y\P$\4\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_let};\6 +\4\&{var} \37\|l: \37\\{pointer};\C{hash location of the left-hand symbol}\2\6 +\&{begin} \37\\{get\_symbol};\5 +$\|l\K\\{cur\_sym}$;\5 +\\{get\_x\_next};\6 +\&{if} $\\{cur\_cmd}\I\\{equals}$ \1\&{then}\6 +\&{if} $\\{cur\_cmd}\I\\{assignment}$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\.{"="})$;\5 +$\\{help3}(\.{"You\ should\ have\ said\ \`let\ symbol\ =\ something\'."})$\6 +$(\.{"But\ don\'t\ worry;\ I\'ll\ pretend\ that\ an\ equals\ sign"})$\6 +$(\.{"was\ present.\ The\ next\ token\ I\ read\ will\ be\ \`something\'."})$;\5 +\\{back\_error};\6 +\&{end};\2\2\6 +\\{get\_symbol};\6 +\&{case} $\\{cur\_cmd}$ \1\&{of}\6 +\4$\\{defined\_macro},\39\\{secondary\_primary\_macro},\39\\{tertiary% +\_secondary\_macro},\39\\{expression\_tertiary\_macro}$: \37$\\{add\_mac\_ref}(% +\\{cur\_mod})$;\6 +\4\&{othercases} \37\\{do\_nothing}\2\6 +\&{endcases};\6 +$\\{clear\_symbol}(\|l,\39\\{false})$;\5 +$\\{eq\_type}(\|l)\K\\{cur\_cmd}$;\6 +\&{if} $\\{cur\_cmd}=\\{tag\_token}$ \1\&{then}\5 +$\\{equiv}(\|l)\K\\{null}$\6 +\4\&{else} $\\{equiv}(\|l)\K\\{cur\_mod}$;\2\6 +\\{get\_x\_next};\6 +\&{end};\par +\fi + +\M1036. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_new\_internal};\2\6 +\&{begin} \37\1\&{repeat} \37\&{if} $\\{int\_ptr}=\\{max\_internal}$ \1\&{then}% +\5 +$\\{overflow}(\.{"number\ of\ internals"},\39\\{max\_internal})$;\2\6 +\\{get\_clear\_symbol};\5 +$\\{incr}(\\{int\_ptr})$;\5 +$\\{eq\_type}(\\{cur\_sym})\K\\{internal\_quantity}$;\5 +$\\{equiv}(\\{cur\_sym})\K\\{int\_ptr}$;\5 +$\\{int\_name}[\\{int\_ptr}]\K\\{text}(\\{cur\_sym})$;\5 +$\\{internal}[\\{int\_ptr}]\K0$;\5 +\\{get\_x\_next};\6 +\4\&{until}\5 +$\\{cur\_cmd}\I\\{comma}$;\2\6 +\&{end};\par +\fi + +\M1037. The various `\&{show}' commands are distinguished by modifier fields +in the usual way. + +\Y\P\D \37$\\{show\_token\_code}=0$\C{show the meaning of a single token}\par +\P\D \37$\\{show\_stats\_code}=1$\C{show current memory and string usage}\par +\P\D \37$\\{show\_code}=2$\C{show a list of expressions}\par +\P\D \37$\\{show\_var\_code}=3$\C{show a variable and its descendents}\par +\P\D \37$\\{show\_dependencies\_code}=4$\C{show dependent variables in terms of +independents}\par +\Y\P$\4\X192:Put each of \MF's primitives into the hash table\X\mathrel{+}\S$\6 +$\\{primitive}(\.{"showtoken"},\39\\{show\_command},\39\\{show\_token\_code})$;% +\6 +$\\{primitive}(\.{"showstats"},\39\\{show\_command},\39\\{show\_stats\_code})$;% +\6 +$\\{primitive}(\.{"show"},\39\\{show\_command},\39\\{show\_code})$;\6 +$\\{primitive}(\.{"showvariable"},\39\\{show\_command},\39\\{show\_var% +\_code})$;\6 +$\\{primitive}(\.{"showdependencies"},\39\\{show\_command},\39\\{show% +\_dependencies\_code})$;\par +\fi + +\M1038. \P$\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of +primitives\X\mathrel{+}\S$\6 +\4\\{show\_command}: \37\&{case} $\|m$ \1\&{of}\6 +\4\\{show\_token\_code}: \37$\\{print}(\.{"showtoken"})$;\6 +\4\\{show\_stats\_code}: \37$\\{print}(\.{"showstats"})$;\6 +\4\\{show\_code}: \37$\\{print}(\.{"show"})$;\6 +\4\\{show\_var\_code}: \37$\\{print}(\.{"showvariable"})$;\6 +\4\&{othercases} \37$\\{print}(\.{"showdependencies"})$\2\6 +\&{endcases};\par +\fi + +\M1039. \P$\X1020:Cases of \\{do\_statement} that invoke particular commands\X% +\mathrel{+}\S$\6 +\4\\{show\_command}: \37\\{do\_show\_whatever};\par +\fi + +\M1040. The value of \\{cur\_mod} controls the \\{verbosity} in the \\{print% +\_exp} routine: +If it's \\{show\_code}, complicated structures are abbreviated, otherwise +they aren't. + +\Y\P$\4\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_show};\2\6 +\&{begin} \37\1\&{repeat} \37\\{get\_x\_next};\5 +\\{scan\_expression};\5 +$\\{print\_nl}(\.{">>\ "})$;\5 +$\\{print\_exp}(\\{null},\392)$;\5 +$\\{flush\_cur\_exp}(0)$;\6 +\4\&{until}\5 +$\\{cur\_cmd}\I\\{comma}$;\2\6 +\&{end};\par +\fi + +\M1041. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{disp\_token};\2\6 +\&{begin} \37$\\{print\_nl}(\.{">\ "})$;\6 +\&{if} $\\{cur\_sym}=0$ \1\&{then}\5 +\X1042:Show a numeric or string or capsule token\X\6 +\4\&{else} \&{begin} \37$\\{slow\_print}(\\{text}(\\{cur\_sym}))$;\5 +$\\{print\_char}(\.{"="})$;\6 +\&{if} $\\{eq\_type}(\\{cur\_sym})\G\\{outer\_tag}$ \1\&{then}\5 +$\\{print}(\.{"(outer)\ "})$;\2\6 +$\\{print\_cmd\_mod}(\\{cur\_cmd},\39\\{cur\_mod})$;\6 +\&{if} $\\{cur\_cmd}=\\{defined\_macro}$ \1\&{then}\6 +\&{begin} \37\\{print\_ln};\5 +$\\{show\_macro}(\\{cur\_mod},\39\\{null},\39100000)$;\6 +\&{end};\C{this avoids recursion between \\{show\_macro} and \\{print\_cmd% +\_mod}}\2\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M1042. \P$\X1042:Show a numeric or string or capsule token\X\S$\6 +\&{begin} \37\&{if} $\\{cur\_cmd}=\\{numeric\_token}$ \1\&{then}\5 +$\\{print\_scaled}(\\{cur\_mod})$\6 +\4\&{else} \&{if} $\\{cur\_cmd}=\\{capsule\_token}$ \1\&{then}\6 +\&{begin} \37$\\{g\_pointer}\K\\{cur\_mod}$;\5 +\\{print\_capsule};\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{print\_char}(\.{""}\.{""})$;\5 +$\\{slow\_print}(\\{cur\_mod})$;\5 +$\\{print\_char}(\.{""}\.{""})$;\5 +$\\{delete\_str\_ref}(\\{cur\_mod})$;\6 +\&{end};\2\2\6 +\&{end}\par +\U1041.\fi + +\M1043. The following cases of \\{print\_cmd\_mod} might arise in connection +with \\{disp\_token}, although they don't correspond to any +primitive tokens. + +\Y\P$\4\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of primitives\X% +\mathrel{+}\S$\6 +\4$\\{left\_delimiter},\39\\{right\_delimiter}$: \37\&{begin} \37\&{if} $\|c=% +\\{left\_delimiter}$ \1\&{then}\5 +$\\{print}(\.{"lef"})$\6 +\4\&{else} $\\{print}(\.{"righ"})$;\2\6 +$\\{print}(\.{"t\ delimiter\ that\ matches\ "})$;\5 +$\\{slow\_print}(\\{text}(\|m))$;\6 +\&{end};\6 +\4\\{tag\_token}: \37\&{if} $\|m=\\{null}$ \1\&{then}\5 +$\\{print}(\.{"tag"})$\ \&{else} $\\{print}(\.{"variable"})$;\2\6 +\4\\{defined\_macro}: \37$\\{print}(\.{"macro:"})$;\6 +\4$\\{secondary\_primary\_macro},\39\\{tertiary\_secondary\_macro},\39% +\\{expression\_tertiary\_macro}$: \37\&{begin} \37$\\{print\_cmd\_mod}(\\{macro% +\_def},\39\|c)$;\5 +$\\{print}(\.{"\'d\ macro:"})$;\5 +\\{print\_ln};\5 +$\\{show\_token\_list}(\\{link}(\\{link}(\|m)),\39\\{null},\391000,\390)$;\6 +\&{end};\6 +\4\\{repeat\_loop}: \37$\\{print}(\.{"[repeat\ the\ loop]"})$;\6 +\4\\{internal\_quantity}: \37$\\{slow\_print}(\\{int\_name}[\|m])$;\par +\fi + +\M1044. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_show\_token};\2\6 +\&{begin} \37\1\&{repeat} \37\\{get\_next};\5 +\\{disp\_token};\5 +\\{get\_x\_next};\6 +\4\&{until}\5 +$\\{cur\_cmd}\I\\{comma}$;\2\6 +\&{end};\par +\fi + +\M1045. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_show\_stats};\2\6 +\&{begin} \37$\\{print\_nl}(\.{"Memory\ usage\ "})$;\6 +\&{stat} \37$\\{print\_int}(\\{var\_used})$;\5 +$\\{print\_char}(\.{"\&"})$;\5 +$\\{print\_int}(\\{dyn\_used})$;\6 +\&{if} $\\{false}$ \1\&{then}\ \2\6 +\&{tats}\hbox{}\6 +$\\{print}(\.{"unknown"})$;\5 +$\\{print}(\.{"\ ("})$;\5 +$\\{print\_int}(\\{hi\_mem\_min}-\\{lo\_mem\_max}-1)$;\5 +$\\{print}(\.{"\ still\ untouched)"})$;\5 +\\{print\_ln};\5 +$\\{print\_nl}(\.{"String\ usage\ "})$;\5 +$\\{print\_int}(\\{str\_ptr}-\\{init\_str\_ptr})$;\5 +$\\{print\_char}(\.{"\&"})$;\5 +$\\{print\_int}(\\{pool\_ptr}-\\{init\_pool\_ptr})$;\5 +$\\{print}(\.{"\ ("})$;\5 +$\\{print\_int}(\\{max\_strings}-\\{max\_str\_ptr})$;\5 +$\\{print\_char}(\.{"\&"})$;\5 +$\\{print\_int}(\\{pool\_size}-\\{max\_pool\_ptr})$;\5 +$\\{print}(\.{"\ still\ untouched)"})$;\5 +\\{print\_ln};\5 +\\{get\_x\_next};\6 +\&{end};\par +\fi + +\M1046. Here's a recursive procedure that gives an abbreviated account +of a variable, for use by \\{do\_show\_var}. + +\Y\P$\4\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{disp\_var}(\|p:\\{pointer})$;\6 +\4\&{var} \37\|q: \37\\{pointer};\C{traverses attributes and subscripts}\6 +\|n: \37$0\to\\{max\_print\_line}$;\C{amount of macro text to show}\2\6 +\&{begin} \37\&{if} $\\{type}(\|p)=\\{structured}$ \1\&{then}\5 +\X1047:Descend the structure\X\6 +\4\&{else} \&{if} $\\{type}(\|p)\G\\{unsuffixed\_macro}$ \1\&{then}\5 +\X1048:Display a variable macro\X\6 +\4\&{else} \&{if} $\\{type}(\|p)\I\\{undefined}$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{""})$;\5 +$\\{print\_variable\_name}(\|p)$;\5 +$\\{print\_char}(\.{"="})$;\5 +$\\{print\_exp}(\|p,\390)$;\6 +\&{end};\2\2\2\6 +\&{end};\par +\fi + +\M1047. \P$\X1047:Descend the structure\X\S$\6 +\&{begin} \37$\|q\K\\{attr\_head}(\|p)$;\6 +\1\&{repeat} \37$\\{disp\_var}(\|q)$;\5 +$\|q\K\\{link}(\|q)$;\6 +\4\&{until}\5 +$\|q=\\{end\_attr}$;\2\6 +$\|q\K\\{subscr\_head}(\|p)$;\6 +\&{while} $\\{name\_type}(\|q)=\\{subscr}$ \1\&{do}\6 +\&{begin} \37$\\{disp\_var}(\|q)$;\5 +$\|q\K\\{link}(\|q)$;\6 +\&{end};\2\6 +\&{end}\par +\U1046.\fi + +\M1048. \P$\X1048:Display a variable macro\X\S$\6 +\&{begin} \37$\\{print\_nl}(\.{""})$;\5 +$\\{print\_variable\_name}(\|p)$;\6 +\&{if} $\\{type}(\|p)>\\{unsuffixed\_macro}$ \1\&{then}\5 +$\\{print}(\.{"@\#"})$;\C{\\{suffixed\_macro}}\2\6 +$\\{print}(\.{"=macro:"})$;\6 +\&{if} $\\{file\_offset}\G\\{max\_print\_line}-20$ \1\&{then}\5 +$\|n\K5$\6 +\4\&{else} $\|n\K\\{max\_print\_line}-\\{file\_offset}-15$;\2\6 +$\\{show\_macro}(\\{value}(\|p),\39\\{null},\39\|n)$;\6 +\&{end}\par +\U1046.\fi + +\M1049. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_show\_var};\6 +\4\&{label} \37\\{done};\2\6 +\&{begin} \37\1\&{repeat} \37\\{get\_next};\6 +\&{if} $\\{cur\_sym}>0$ \1\&{then}\6 +\&{if} $\\{cur\_sym}\L\\{hash\_end}$ \1\&{then}\6 +\&{if} $\\{cur\_cmd}=\\{tag\_token}$ \1\&{then}\6 +\&{if} $\\{cur\_mod}\I\\{null}$ \1\&{then}\6 +\&{begin} \37$\\{disp\_var}(\\{cur\_mod})$;\5 +\&{goto} \37\\{done};\6 +\&{end};\2\2\2\2\6 +\\{disp\_token};\6 +\4\\{done}: \37\\{get\_x\_next};\6 +\4\&{until}\5 +$\\{cur\_cmd}\I\\{comma}$;\2\6 +\&{end};\par +\fi + +\M1050. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_show\_dependencies};\6 +\4\&{var} \37\|p: \37\\{pointer};\C{link that runs through all dependencies}\2\6 +\&{begin} \37$\|p\K\\{link}(\\{dep\_head})$;\6 +\&{while} $\|p\I\\{dep\_head}$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{interesting}(\|p)$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{""})$;\5 +$\\{print\_variable\_name}(\|p)$;\6 +\&{if} $\\{type}(\|p)=\\{dependent}$ \1\&{then}\5 +$\\{print\_char}(\.{"="})$\6 +\4\&{else} $\\{print}(\.{"\ =\ "})$;\C{extra spaces imply proto-dependency}\2\6 +$\\{print\_dependency}(\\{dep\_list}(\|p),\39\\{type}(\|p))$;\6 +\&{end};\2\6 +$\|p\K\\{dep\_list}(\|p)$;\6 +\&{while} $\\{info}(\|p)\I\\{null}$ \1\&{do}\5 +$\|p\K\\{link}(\|p)$;\2\6 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +\\{get\_x\_next};\6 +\&{end};\par +\fi + +\M1051. Finally we are ready for the procedure that governs all of the +show commands. + +\Y\P$\4\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_show\_whatever};\2\6 +\&{begin} \37\&{if} $\\{interaction}=\\{error\_stop\_mode}$ \1\&{then}\5 +\\{wake\_up\_terminal};\2\6 +\&{case} $\\{cur\_mod}$ \1\&{of}\6 +\4\\{show\_token\_code}: \37\\{do\_show\_token};\6 +\4\\{show\_stats\_code}: \37\\{do\_show\_stats};\6 +\4\\{show\_code}: \37\\{do\_show};\6 +\4\\{show\_var\_code}: \37\\{do\_show\_var};\6 +\4\\{show\_dependencies\_code}: \37\\{do\_show\_dependencies};\2\6 +\&{end};\C{there are no other cases}\6 +\&{if} $\\{internal}[\\{showstopping}]>0$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"OK"})$;\6 +\&{if} $\\{interaction}<\\{error\_stop\_mode}$ \1\&{then}\6 +\&{begin} \37\\{help0};\5 +$\\{decr}(\\{error\_count})$;\6 +\&{end}\6 +\4\&{else} $\\{help1}(\.{"This\ isn\'t\ an\ error\ message;\ I\'m\ just\ +showing\ something."})$;\2\6 +\&{if} $\\{cur\_cmd}=\\{semicolon}$ \1\&{then}\5 +\\{error}\ \&{else} \\{put\_get\_error};\2\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M1052. The `\&{addto}' command needs the following additional primitives: + +\Y\P\D \37$\\{drop\_code}=0$\C{command modifier for `\&{dropping}'}\par +\P\D \37$\\{keep\_code}=1$\C{command modifier for `\&{keeping}'}\par +\Y\P$\4\X192:Put each of \MF's primitives into the hash table\X\mathrel{+}\S$\6 +$\\{primitive}(\.{"contour"},\39\\{thing\_to\_add},\39\\{contour\_code})$;\6 +$\\{primitive}(\.{"doublepath"},\39\\{thing\_to\_add},\39\\{double\_path% +\_code})$;\6 +$\\{primitive}(\.{"also"},\39\\{thing\_to\_add},\39\\{also\_code})$;\6 +$\\{primitive}(\.{"withpen"},\39\\{with\_option},\39\\{pen\_type})$;\6 +$\\{primitive}(\.{"withweight"},\39\\{with\_option},\39\\{known})$;\6 +$\\{primitive}(\.{"dropping"},\39\\{cull\_op},\39\\{drop\_code})$;\6 +$\\{primitive}(\.{"keeping"},\39\\{cull\_op},\39\\{keep\_code})$;\par +\fi + +\M1053. \P$\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of +primitives\X\mathrel{+}\S$\6 +\4\\{thing\_to\_add}: \37\&{if} $\|m=\\{contour\_code}$ \1\&{then}\5 +$\\{print}(\.{"contour"})$\6 +\4\&{else} \&{if} $\|m=\\{double\_path\_code}$ \1\&{then}\5 +$\\{print}(\.{"doublepath"})$\6 +\4\&{else} $\\{print}(\.{"also"})$;\2\2\6 +\4\\{with\_option}: \37\&{if} $\|m=\\{pen\_type}$ \1\&{then}\5 +$\\{print}(\.{"withpen"})$\6 +\4\&{else} $\\{print}(\.{"withweight"})$;\2\6 +\4\\{cull\_op}: \37\&{if} $\|m=\\{drop\_code}$ \1\&{then}\5 +$\\{print}(\.{"dropping"})$\6 +\4\&{else} $\\{print}(\.{"keeping"})$;\2\par +\fi + +\M1054. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{function}\1\ \37\\{scan\_with}: \37\\{boolean};\6 +\4\&{var} \37\|t: \37\\{small\_number};\C{\\{known} or \\{pen\_type}}\6 +\\{result}: \37\\{boolean};\C{the value to return}\2\6 +\&{begin} \37$\|t\K\\{cur\_mod}$;\5 +$\\{cur\_type}\K\\{vacuous}$;\5 +\\{get\_x\_next};\5 +\\{scan\_expression};\5 +$\\{result}\K\\{false}$;\6 +\&{if} $\\{cur\_type}\I\|t$ \1\&{then}\5 +\X1055:Complain about improper type\X\6 +\4\&{else} \&{if} $\\{cur\_type}=\\{pen\_type}$ \1\&{then}\5 +$\\{result}\K\\{true}$\6 +\4\&{else} \X1056:Check the tentative weight\X;\2\2\6 +$\\{scan\_with}\K\\{result}$;\6 +\&{end};\par +\fi + +\M1055. \P$\X1055:Complain about improper type\X\S$\6 +\&{begin} \37$\\{exp\_err}(\.{"Improper\ type"})$;\5 +$\\{help2}(\.{"Next\ time\ say\ \`withweight\ <known\ numeric\ expression>% +\';"})$\6 +$(\.{"I\'ll\ ignore\ the\ bad\ \`with\'\ clause\ and\ look\ for\ another."})$;\6 +\&{if} $\|t=\\{pen\_type}$ \1\&{then}\5 +$\\{help\_line}[1]\K\.{"Next\ time\ say\ \`withpen\ <known\ pen\ expression>% +\';"}$;\2\6 +$\\{put\_get\_flush\_error}(0)$;\6 +\&{end}\par +\U1054.\fi + +\M1056. \P$\X1056:Check the tentative weight\X\S$\6 +\&{begin} \37$\\{cur\_exp}\K\\{round\_unscaled}(\\{cur\_exp})$;\6 +\&{if} $(\\{abs}(\\{cur\_exp})<4)\W(\\{cur\_exp}\I0)$ \1\&{then}\5 +$\\{result}\K\\{true}$\6 +\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Weight\ must\ be\ -3,\ -2,\ -1,\ ++1,\ +2,\ or\ +3"})$;\5 +$\\{help1}(\.{"I\'ll\ ignore\ the\ bad\ \`with\'\ clause\ and\ look\ for\ +another."})$;\5 +$\\{put\_get\_flush\_error}(0)$;\6 +\&{end};\2\6 +\&{end}\par +\U1054.\fi + +\M1057. One of the things we need to do when we've parsed an \&{addto} or +similar command is set \\{cur\_edges} to the header of a supposed \&{picture} +variable, given a token list for that variable. + +\Y\P$\4\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{find\_edges\_var}(\|t:\\{pointer})$;\6 +\4\&{var} \37\|p: \37\\{pointer};\2\6 +\&{begin} \37$\|p\K\\{find\_variable}(\|t)$;\5 +$\\{cur\_edges}\K\\{null}$;\6 +\&{if} $\|p=\\{null}$ \1\&{then}\6 +\&{begin} \37$\\{obliterated}(\|t)$;\5 +\\{put\_get\_error};\6 +\&{end}\6 +\4\&{else} \&{if} $\\{type}(\|p)\I\\{picture\_type}$ \1\&{then}\6 +\&{begin} \37$\\{print\_err}(\.{"Variable\ "})$;\5 +$\\{show\_token\_list}(\|t,\39\\{null},\391000,\390)$;\5 +$\\{print}(\.{"\ is\ the\ wrong\ type\ ("})$;\5 +$\\{print\_type}(\\{type}(\|p))$;\5 +$\\{print\_char}(\.{")"})$;\5 +$\\{help2}(\.{"I\ was\ looking\ for\ a\ "}\.{"known"}\.{"\ picture\ +variable."})$\6 +$(\.{"So\ I\'ll\ not\ change\ anything\ just\ now."})$;\5 +\\{put\_get\_error};\6 +\&{end}\6 +\4\&{else} $\\{cur\_edges}\K\\{value}(\|p)$;\2\2\6 +$\\{flush\_node\_list}(\|t)$;\6 +\&{end};\par +\fi + +\M1058. \P$\X1020:Cases of \\{do\_statement} that invoke particular commands\X% +\mathrel{+}\S$\6 +\4\\{add\_to\_command}: \37\\{do\_add\_to};\par +\fi + +\M1059. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_add\_to};\6 +\4\&{label} \37$\\{done},\39\\{not\_found}$;\6 +\4\&{var} \37$\\{lhs},\39\\{rhs}$: \37\\{pointer};\C{variable on left, path on +right}\6 +\|w: \37\\{integer};\C{tentative weight}\6 +\|p: \37\\{pointer};\C{list manipulation register}\6 +\|q: \37\\{pointer};\C{beginning of second half of doubled path}\6 +\\{add\_to\_type}: \37$\\{double\_path\_code}\to\\{also\_code}$;\C{modifier of % +\&{addto}}\2\6 +\&{begin} \37\\{get\_x\_next};\5 +$\\{var\_flag}\K\\{thing\_to\_add}$;\5 +\\{scan\_primary};\6 +\&{if} $\\{cur\_type}\I\\{token\_list}$ \1\&{then}\5 +\X1060:Abandon edges command because there's no variable\X\6 +\4\&{else} \&{begin} \37$\\{lhs}\K\\{cur\_exp}$;\5 +$\\{add\_to\_type}\K\\{cur\_mod}$;\6 +$\\{cur\_type}\K\\{vacuous}$;\5 +\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{add\_to\_type}=\\{also\_code}$ \1\&{then}\5 +\X1061:Augment some edges by others\X\6 +\4\&{else} \X1062:Get ready to fill a contour, and fill it\X;\2\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M1060. \P$\X1060:Abandon edges command because there's no variable\X\S$\6 +\&{begin} \37$\\{exp\_err}(\.{"Not\ a\ suitable\ variable"})$;\5 +$\\{help4}(\.{"At\ this\ point\ I\ needed\ to\ see\ the\ name\ of\ a\ picture\ +variable."})$\6 +$(\.{"(Or\ perhaps\ you\ have\ indeed\ presented\ me\ with\ one;\ I\ might"})$\6 +$(\.{"have\ missed\ it,\ if\ it\ wasn\'t\ followed\ by\ the\ proper\ +token.)"})$\6 +$(\.{"So\ I\'ll\ not\ change\ anything\ just\ now."})$;\5 +$\\{put\_get\_flush\_error}(0)$;\6 +\&{end}\par +\Us1059, 1070, 1071\ETs1074.\fi + +\M1061. \P$\X1061:Augment some edges by others\X\S$\6 +\&{begin} \37$\\{find\_edges\_var}(\\{lhs})$;\6 +\&{if} $\\{cur\_edges}=\\{null}$ \1\&{then}\5 +$\\{flush\_cur\_exp}(0)$\6 +\4\&{else} \&{if} $\\{cur\_type}\I\\{picture\_type}$ \1\&{then}\6 +\&{begin} \37$\\{exp\_err}(\.{"Improper\ \`addto\'"})$;\5 +$\\{help2}(\.{"This\ expression\ should\ have\ specified\ a\ known\ +picture."})$\6 +$(\.{"So\ I\'ll\ not\ change\ anything\ just\ now."})$;\5 +$\\{put\_get\_flush\_error}(0)$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{merge\_edges}(\\{cur\_exp})$;\5 +$\\{flush\_cur\_exp}(0)$;\6 +\&{end};\2\2\6 +\&{end}\par +\U1059.\fi + +\M1062. \P$\X1062:Get ready to fill a contour, and fill it\X\S$\6 +\&{begin} \37\&{if} $\\{cur\_type}=\\{pair\_type}$ \1\&{then}\5 +\\{pair\_to\_path};\2\6 +\&{if} $\\{cur\_type}\I\\{path\_type}$ \1\&{then}\6 +\&{begin} \37$\\{exp\_err}(\.{"Improper\ \`addto\'"})$;\5 +$\\{help2}(\.{"This\ expression\ should\ have\ been\ a\ known\ path."})$\6 +$(\.{"So\ I\'ll\ not\ change\ anything\ just\ now."})$;\5 +$\\{put\_get\_flush\_error}(0)$;\5 +$\\{flush\_token\_list}(\\{lhs})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{rhs}\K\\{cur\_exp}$;\5 +$\|w\K1$;\5 +$\\{cur\_pen}\K\\{null\_pen}$;\6 +\&{while} $\\{cur\_cmd}=\\{with\_option}$ \1\&{do}\6 +\&{if} $\\{scan\_with}$ \1\&{then}\6 +\&{if} $\\{cur\_type}=\\{known}$ \1\&{then}\5 +$\|w\K\\{cur\_exp}$\6 +\4\&{else} \X1063:Change the tentative pen\X;\2\2\2\6 +\X1064:Complete the contour filling operation\X;\6 +$\\{delete\_pen\_ref}(\\{cur\_pen})$;\6 +\&{end};\2\6 +\&{end}\par +\U1059.\fi + +\M1063. We could say `$\\{add\_pen\_ref}(\\{cur\_pen})$; $\\{flush\_cur% +\_exp}(0)$' after changing +\\{cur\_pen} here. But that would have no effect, because the current +expression +will not be flushed. Thus we save a bit of code (at the risk of being too +tricky). + +\Y\P$\4\X1063:Change the tentative pen\X\S$\6 +\&{begin} \37$\\{delete\_pen\_ref}(\\{cur\_pen})$;\5 +$\\{cur\_pen}\K\\{cur\_exp}$;\6 +\&{end}\par +\U1062.\fi + +\M1064. \P$\X1064:Complete the contour filling operation\X\S$\6 +$\\{find\_edges\_var}(\\{lhs})$;\6 +\&{if} $\\{cur\_edges}=\\{null}$ \1\&{then}\5 +$\\{toss\_knot\_list}(\\{rhs})$\6 +\4\&{else} \&{begin} \37$\\{lhs}\K\\{null}$;\5 +$\\{cur\_path\_type}\K\\{add\_to\_type}$;\6 +\&{if} $\\{left\_type}(\\{rhs})=\\{endpoint}$ \1\&{then}\6 +\&{if} $\\{cur\_path\_type}=\\{double\_path\_code}$ \1\&{then}\5 +\X1065:Double the path\X\6 +\4\&{else} \X1067:Complain about non-cycle and \&{goto} \\{not\_found}\X\2\6 +\4\&{else} \&{if} $\\{cur\_path\_type}=\\{double\_path\_code}$ \1\&{then}\5 +$\\{lhs}\K\\{htap\_ypoc}(\\{rhs})$;\2\2\6 +$\\{cur\_wt}\K\|w$;\5 +$\\{rhs}\K\\{make\_spec}(\\{rhs},\39\\{max\_offset}(\\{cur\_pen}),\39% +\\{internal}[\\{tracing\_specs}])$;\5 +\X1068:Check the turning number\X;\6 +\&{if} $\\{max\_offset}(\\{cur\_pen})=0$ \1\&{then}\5 +$\\{fill\_spec}(\\{rhs})$\6 +\4\&{else} $\\{fill\_envelope}(\\{rhs})$;\2\6 +\&{if} $\\{lhs}\I\\{null}$ \1\&{then}\6 +\&{begin} \37$\\{rev\_turns}\K\\{true}$;\5 +$\\{lhs}\K\\{make\_spec}(\\{lhs},\39\\{max\_offset}(\\{cur\_pen}),\39% +\\{internal}[\\{tracing\_specs}])$;\5 +$\\{rev\_turns}\K\\{false}$;\6 +\&{if} $\\{max\_offset}(\\{cur\_pen})=0$ \1\&{then}\5 +$\\{fill\_spec}(\\{lhs})$\6 +\4\&{else} $\\{fill\_envelope}(\\{lhs})$;\2\6 +\&{end};\2\6 +\4\\{not\_found}: \37\&{end}\2\par +\U1062.\fi + +\M1065. \P$\X1065:Double the path\X\S$\6 +\&{if} $\\{link}(\\{rhs})=\\{rhs}$ \1\&{then}\5 +\X1066:Make a trivial one-point path cycle\X\6 +\4\&{else} \&{begin} \37$\|p\K\\{htap\_ypoc}(\\{rhs})$;\5 +$\|q\K\\{link}(\|p)$;\6 +$\\{right\_x}(\\{path\_tail})\K\\{right\_x}(\|q)$;\5 +$\\{right\_y}(\\{path\_tail})\K\\{right\_y}(\|q)$;\5 +$\\{right\_type}(\\{path\_tail})\K\\{right\_type}(\|q)$;\5 +$\\{link}(\\{path\_tail})\K\\{link}(\|q)$;\5 +$\\{free\_node}(\|q,\39\\{knot\_node\_size})$;\6 +$\\{right\_x}(\|p)\K\\{right\_x}(\\{rhs})$;\5 +$\\{right\_y}(\|p)\K\\{right\_y}(\\{rhs})$;\5 +$\\{right\_type}(\|p)\K\\{right\_type}(\\{rhs})$;\5 +$\\{link}(\|p)\K\\{link}(\\{rhs})$;\5 +$\\{free\_node}(\\{rhs},\39\\{knot\_node\_size})$;\6 +$\\{rhs}\K\|p$;\6 +\&{end}\2\par +\U1064.\fi + +\M1066. \P$\X1066:Make a trivial one-point path cycle\X\S$\6 +\&{begin} \37$\\{right\_x}(\\{rhs})\K\\{x\_coord}(\\{rhs})$;\5 +$\\{right\_y}(\\{rhs})\K\\{y\_coord}(\\{rhs})$;\5 +$\\{left\_x}(\\{rhs})\K\\{x\_coord}(\\{rhs})$;\5 +$\\{left\_y}(\\{rhs})\K\\{y\_coord}(\\{rhs})$;\5 +$\\{left\_type}(\\{rhs})\K\\{explicit}$;\5 +$\\{right\_type}(\\{rhs})\K\\{explicit}$;\6 +\&{end}\par +\U1065.\fi + +\M1067. \P$\X1067:Complain about non-cycle and \&{goto} \\{not\_found}\X\S$\6 +\&{begin} \37$\\{print\_err}(\.{"Not\ a\ cycle"})$;\5 +$\\{help2}(\.{"That\ contour\ should\ have\ ended\ with\ \`..cycle\'\ or\ \`% +\&cycle\'."})$\6 +$(\.{"So\ I\'ll\ not\ change\ anything\ just\ now."})$;\5 +\\{put\_get\_error};\5 +$\\{toss\_knot\_list}(\\{rhs})$;\5 +\&{goto} \37\\{not\_found};\6 +\&{end}\par +\U1064.\fi + +\M1068. \P$\X1068:Check the turning number\X\S$\6 +\&{if} $\\{turning\_number}\L0$ \1\&{then}\6 +\&{if} $\\{cur\_path\_type}\I\\{double\_path\_code}$ \1\&{then}\6 +\&{if} $\\{internal}[\\{turning\_check}]>0$ \1\&{then}\6 +\&{if} $(\\{turning\_number}<0)\W(\\{link}(\\{cur\_pen})=\\{null})$ \1\&{then}\5 +$\\{negate}(\\{cur\_wt})$\6 +\4\&{else} \&{begin} \37\&{if} $\\{turning\_number}=0$ \1\&{then}\6 +\&{if} $(\\{internal}[\\{turning\_check}]\L\\{unity})\W(\\{link}(\\{cur\_pen})=% +\\{null})$ \1\&{then}\5 +\&{goto} \37\\{done}\6 +\4\&{else} $\\{print\_strange}(\.{"Strange\ path\ (turning\ number\ is\ +zero)"})$\2\6 +\4\&{else} $\\{print\_strange}(\.{"Backwards\ path\ (turning\ number\ is\ +negative)"})$;\2\6 +$\\{help3}(\.{"The\ path\ doesn\'t\ have\ a\ counterclockwise\ orientation,"})$% +\6 +$(\.{"so\ I\'ll\ probably\ have\ trouble\ drawing\ it."})$\6 +$(\.{"(See\ Chapter\ 27\ of\ The\ METAFONTbook\ for\ more\ help.)"})$;\5 +\\{put\_get\_error};\6 +\&{end};\2\2\2\2\6 +\4\\{done}: \37\par +\U1064.\fi + +\M1069. \P$\X1020:Cases of \\{do\_statement} that invoke particular commands\X% +\mathrel{+}\S$\6 +\4\\{ship\_out\_command}: \37\\{do\_ship\_out};\6 +\4\\{display\_command}: \37\\{do\_display};\6 +\4\\{open\_window}: \37\\{do\_open\_window};\6 +\4\\{cull\_command}: \37\\{do\_cull};\par +\fi + +\M1070. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\hbox{\4}\X1098:Declare the function called \\{tfm\_check}\X\6 +\4\&{procedure}\1\ \37\\{do\_ship\_out};\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37\|c: \37\\{integer};\C{the character code}\2\6 +\&{begin} \37\\{get\_x\_next};\5 +$\\{var\_flag}\K\\{semicolon}$;\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_type}\I\\{token\_list}$ \1\&{then}\6 +\&{if} $\\{cur\_type}=\\{picture\_type}$ \1\&{then}\5 +$\\{cur\_edges}\K\\{cur\_exp}$\6 +\4\&{else} \&{begin} \37\X1060:Abandon edges command because there's no +variable\X;\6 +\&{return};\6 +\&{end}\2\6 +\4\&{else} \&{begin} \37$\\{find\_edges\_var}(\\{cur\_exp})$;\5 +$\\{cur\_type}\K\\{vacuous}$;\6 +\&{end};\2\6 +\&{if} $\\{cur\_edges}\I\\{null}$ \1\&{then}\6 +\&{begin} \37$\|c\K\\{round\_unscaled}(\\{internal}[\\{char\_code}])\mathbin{% +\&{mod}}256$;\6 +\&{if} $\|c<0$ \1\&{then}\5 +$\|c\K\|c+256$;\2\6 +\X1099:Store the width information for character code~\|c\X;\6 +\&{if} $\\{internal}[\\{proofing}]\G0$ \1\&{then}\5 +$\\{ship\_out}(\|c)$;\2\6 +\&{end};\2\6 +$\\{flush\_cur\_exp}(0)$;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M1071. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_display};\6 +\4\&{label} \37$\\{not\_found},\39\\{common\_ending},\39\\{exit}$;\6 +\4\&{var} \37\|e: \37\\{pointer};\C{token list for a picture variable}\2\6 +\&{begin} \37\\{get\_x\_next};\5 +$\\{var\_flag}\K\\{in\_window}$;\5 +\\{scan\_primary};\6 +\&{if} $\\{cur\_type}\I\\{token\_list}$ \1\&{then}\5 +\X1060:Abandon edges command because there's no variable\X\6 +\4\&{else} \&{begin} \37$\|e\K\\{cur\_exp}$;\5 +$\\{cur\_type}\K\\{vacuous}$;\5 +\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\5 +\&{goto} \37\\{common\_ending};\2\6 +$\\{cur\_exp}\K\\{round\_unscaled}(\\{cur\_exp})$;\6 +\&{if} $\\{cur\_exp}<0$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +\&{if} $\\{cur\_exp}>15$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +\&{if} $\R\\{window\_open}[\\{cur\_exp}]$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +$\\{find\_edges\_var}(\|e)$;\6 +\&{if} $\\{cur\_edges}\I\\{null}$ \1\&{then}\5 +$\\{disp\_edges}(\\{cur\_exp})$;\2\6 +\&{return};\6 +\4\\{not\_found}: \37$\\{cur\_exp}\K\\{cur\_exp}\ast\\{unity}$;\6 +\4\\{common\_ending}: \37$\\{exp\_err}(\.{"Bad\ window\ number"})$;\5 +$\\{help1}(\.{"It\ should\ be\ the\ number\ of\ an\ open\ window."})$;\5 +$\\{put\_get\_flush\_error}(0)$;\5 +$\\{flush\_token\_list}(\|e)$;\6 +\&{end};\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M1072. The only thing difficult about `\&{openwindow}' is that the syntax +allows the user to go astray in many ways. The following subroutine +helps keep the necessary program reasonably short and sweet. + +\Y\P$\4\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{function}\1\ \37$\\{get\_pair}(\|c:\\{command\_code})$: \37\\{boolean};\6 +\4\&{var} \37\|p: \37\\{pointer};\C{a pair of values that are known (we hope)}\6 +\|b: \37\\{boolean};\C{did we find such a pair?}\2\6 +\&{begin} \37\&{if} $\\{cur\_cmd}\I\|c$ \1\&{then}\5 +$\\{get\_pair}\K\\{false}$\6 +\4\&{else} \&{begin} \37\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{nice\_pair}(\\{cur\_exp},\39\\{cur\_type})$ \1\&{then}\6 +\&{begin} \37$\|p\K\\{value}(\\{cur\_exp})$;\5 +$\\{cur\_x}\K\\{value}(\\{x\_part\_loc}(\|p))$;\5 +$\\{cur\_y}\K\\{value}(\\{y\_part\_loc}(\|p))$;\5 +$\|b\K\\{true}$;\6 +\&{end}\6 +\4\&{else} $\|b\K\\{false}$;\2\6 +$\\{flush\_cur\_exp}(0)$;\5 +$\\{get\_pair}\K\|b$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M1073. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_open\_window};\6 +\4\&{label} \37$\\{not\_found},\39\\{exit}$;\6 +\4\&{var} \37\|k: \37\\{integer};\C{the window number in question}\6 +$\\{r0},\39\\{c0},\39\\{r1},\39\\{c1}$: \37\\{scaled};\C{window coordinates}\2\6 +\&{begin} \37\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +$\|k\K\\{round\_unscaled}(\\{cur\_exp})$;\6 +\&{if} $\|k<0$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +\&{if} $\|k>15$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +\&{if} $\R\\{get\_pair}(\\{from\_token})$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +$\\{r0}\K\\{cur\_x}$;\5 +$\\{c0}\K\\{cur\_y}$;\6 +\&{if} $\R\\{get\_pair}(\\{to\_token})$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +$\\{r1}\K\\{cur\_x}$;\5 +$\\{c1}\K\\{cur\_y}$;\6 +\&{if} $\R\\{get\_pair}(\\{at\_token})$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +$\\{open\_a\_window}(\|k,\39\\{r0},\39\\{c0},\39\\{r1},\39\\{c1},\39\\{cur\_x},% +\39\\{cur\_y})$;\5 +\&{return};\6 +\4\\{not\_found}: \37$\\{print\_err}(\.{"Improper\ \`openwindow\'"})$;\5 +$\\{help2}(\.{"Say\ \`openwindow\ k\ from\ (r0,c0)\ to\ (r1,c1)\ at\ (x,y)% +\',"})$\6 +$(\.{"where\ all\ quantities\ are\ known\ and\ k\ is\ between\ 0\ and\ 15."})$;% +\5 +\\{put\_get\_error};\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M1074. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_cull};\6 +\4\&{label} \37$\\{not\_found},\39\\{exit}$;\6 +\4\&{var} \37\|e: \37\\{pointer};\C{token list for a picture variable}\6 +\\{keeping}: \37$\\{drop\_code}\to\\{keep\_code}$;\C{modifier of \\{cull\_op}}\6 +$\|w,\39\\{w\_in},\39\\{w\_out}$: \37\\{integer};\C{culling weights}\2\6 +\&{begin} \37$\|w\K1$;\5 +\\{get\_x\_next};\5 +$\\{var\_flag}\K\\{cull\_op}$;\5 +\\{scan\_primary};\6 +\&{if} $\\{cur\_type}\I\\{token\_list}$ \1\&{then}\5 +\X1060:Abandon edges command because there's no variable\X\6 +\4\&{else} \&{begin} \37$\|e\K\\{cur\_exp}$;\5 +$\\{cur\_type}\K\\{vacuous}$;\5 +$\\{keeping}\K\\{cur\_mod}$;\6 +\&{if} $\R\\{get\_pair}(\\{cull\_op})$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +\&{while} $(\\{cur\_cmd}=\\{with\_option})\W(\\{cur\_mod}=\\{known})$ \1\&{do}\6 +\&{if} $\\{scan\_with}$ \1\&{then}\5 +$\|w\K\\{cur\_exp}$;\2\2\6 +\X1075:Set up the culling weights, or \&{goto} \\{not\_found} if the thresholds +are bad\X;\6 +$\\{find\_edges\_var}(\|e)$;\6 +\&{if} $\\{cur\_edges}\I\\{null}$ \1\&{then}\5 +$\\{cull\_edges}(\\{floor\_unscaled}(\\{cur\_x}+\\{unity}-1),\39\\{floor% +\_unscaled}(\\{cur\_y}),\39\\{w\_out},\39\\{w\_in})$;\2\6 +\&{return};\6 +\4\\{not\_found}: \37$\\{print\_err}(\.{"Bad\ culling\ amounts"})$;\5 +$\\{help1}(\.{"Always\ cull\ by\ known\ amounts\ that\ exclude\ 0."})$;\5 +\\{put\_get\_error};\5 +$\\{flush\_token\_list}(\|e)$;\6 +\&{end};\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M1075. \P$\X1075:Set up the culling weights, or \&{goto} \\{not\_found} if the +thresholds are bad\X\S$\6 +\&{if} $\\{cur\_x}>\\{cur\_y}$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +\&{if} $\\{keeping}=\\{drop\_code}$ \1\&{then}\6 +\&{begin} \37\&{if} $(\\{cur\_x}>0)\V(\\{cur\_y}<0)$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +$\\{w\_out}\K\|w$;\5 +$\\{w\_in}\K0$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37\&{if} $(\\{cur\_x}\L0)\W(\\{cur\_y}\G0)$ \1\&{then}\5 +\&{goto} \37\\{not\_found};\2\6 +$\\{w\_out}\K0$;\5 +$\\{w\_in}\K\|w$;\6 +\&{end}\2\par +\U1074.\fi + +\M1076. The \&{everyjob} command simply assigns a nonzero value to the global +variable +\\{start\_sym}. + +\Y\P$\4\X1020:Cases of \\{do\_statement} that invoke particular commands\X% +\mathrel{+}\S$\6 +\4\\{every\_job\_command}: \37\&{begin} \37\\{get\_symbol};\5 +$\\{start\_sym}\K\\{cur\_sym}$;\5 +\\{get\_x\_next};\6 +\&{end};\par +\fi + +\M1077. \P$\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{start\_sym}: \37\\{halfword};\C{a symbolic token to insert at beginning of +job}\par +\fi + +\M1078. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{start\_sym}\K0$;\par +\fi + +\M1079. Finally, we have only the ``message'' commands remaining. + +\Y\P\D \37$\\{message\_code}=0$\par +\P\D \37$\\{err\_message\_code}=1$\par +\P\D \37$\\{err\_help\_code}=2$\par +\Y\P$\4\X192:Put each of \MF's primitives into the hash table\X\mathrel{+}\S$\6 +$\\{primitive}(\.{"message"},\39\\{message\_command},\39\\{message\_code})$;\6 +$\\{primitive}(\.{"errmessage"},\39\\{message\_command},\39\\{err\_message% +\_code})$;\6 +$\\{primitive}(\.{"errhelp"},\39\\{message\_command},\39\\{err\_help\_code})$;% +\par +\fi + +\M1080. \P$\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of +primitives\X\mathrel{+}\S$\6 +\4\\{message\_command}: \37\&{if} $\|m<\\{err\_message\_code}$ \1\&{then}\5 +$\\{print}(\.{"message"})$\6 +\4\&{else} \&{if} $\|m=\\{err\_message\_code}$ \1\&{then}\5 +$\\{print}(\.{"errmessage"})$\6 +\4\&{else} $\\{print}(\.{"errhelp"})$;\2\2\par +\fi + +\M1081. \P$\X1020:Cases of \\{do\_statement} that invoke particular commands\X% +\mathrel{+}\S$\6 +\4\\{message\_command}: \37\\{do\_message};\par +\fi + +\M1082. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_message};\6 +\4\&{var} \37\|m: \37$\\{message\_code}\to\\{err\_help\_code}$;\C{the type of +message}\2\6 +\&{begin} \37$\|m\K\\{cur\_mod}$;\5 +\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_type}\I\\{string\_type}$ \1\&{then}\6 +\&{begin} \37$\\{exp\_err}(\.{"Not\ a\ string"})$;\5 +$\\{help1}(\.{"A\ message\ should\ be\ a\ known\ string\ expression."})$;\5 +\\{put\_get\_error};\6 +\&{end}\6 +\4\&{else} \&{case} $\|m$ \1\&{of}\6 +\4\\{message\_code}: \37\&{begin} \37$\\{print\_nl}(\.{""})$;\5 +$\\{slow\_print}(\\{cur\_exp})$;\6 +\&{end};\6 +\4\\{err\_message\_code}: \37\X1086:Print string \\{cur\_exp} as an error +message\X;\6 +\4\\{err\_help\_code}: \37\X1083:Save string \\{cur\_exp} as the \\{err\_help}% +\X;\2\6 +\&{end};\C{there are no other cases}\2\6 +$\\{flush\_cur\_exp}(0)$;\6 +\&{end};\par +\fi + +\M1083. The global variable \\{err\_help} is zero when the user has most +recently +given an empty help string, or if none has ever been given. + +\Y\P$\4\X1083:Save string \\{cur\_exp} as the \\{err\_help}\X\S$\6 +\&{begin} \37\&{if} $\\{err\_help}\I0$ \1\&{then}\5 +$\\{delete\_str\_ref}(\\{err\_help})$;\2\6 +\&{if} $\\{length}(\\{cur\_exp})=0$ \1\&{then}\5 +$\\{err\_help}\K0$\6 +\4\&{else} \&{begin} \37$\\{err\_help}\K\\{cur\_exp}$;\5 +$\\{add\_str\_ref}(\\{err\_help})$;\6 +\&{end};\2\6 +\&{end}\par +\U1082.\fi + +\M1084. If \&{errmessage} occurs often in \\{scroll\_mode}, without +user-defined +\&{errhelp}, we don't want to give a long help message each time. So we +give a verbose explanation only once. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{long\_help\_seen}: \37\\{boolean};\C{has the long \&{errmessage} help been +used?}\par +\fi + +\M1085. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{long\_help\_seen}\K\\{false}$;\par +\fi + +\M1086. \P$\X1086:Print string \\{cur\_exp} as an error message\X\S$\6 +\&{begin} \37$\\{print\_err}(\.{""})$;\5 +$\\{slow\_print}(\\{cur\_exp})$;\6 +\&{if} $\\{err\_help}\I0$ \1\&{then}\5 +$\\{use\_err\_help}\K\\{true}$\6 +\4\&{else} \&{if} $\\{long\_help\_seen}$ \1\&{then}\5 +$\\{help1}(\.{"(That\ was\ another\ \`errmessage\'.)"})$\6 +\4\&{else} \&{begin} \37\&{if} $\\{interaction}<\\{error\_stop\_mode}$ \1% +\&{then}\5 +$\\{long\_help\_seen}\K\\{true}$;\2\6 +$\\{help4}(\.{"This\ error\ message\ was\ generated\ by\ an\ \`errmessage\'"})$% +\6 +$(\.{"command,\ so\ I\ can\'t\ give\ any\ explicit\ help."})$\6 +$(\.{"Pretend\ that\ you\'re\ Miss\ Marple:\ Examine\ all\ clues,"})$\6 +$(\.{"and\ deduce\ the\ truth\ by\ inspired\ guesses."})$;\6 +\&{end};\2\2\6 +\\{put\_get\_error};\5 +$\\{use\_err\_help}\K\\{false}$;\6 +\&{end}\par +\U1082.\fi + +\N1087. \[45] 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. One of \MF's duties is to +write \.{TFM} files so that the user's fonts can readily be +applied to typesetting. + +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 \MF\ uses the +byte interpretation. The format of \.{TFM} files was designed by +Lyle Ramshaw in 1980. The intent is to convey a lot of different kinds +of information in a compact but useful form. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{tfm\_file}: \37\\{byte\_file};\C{the font metric output goes here}\6 +\4\\{metric\_file\_name}: \37\\{str\_number};\C{full name of the font metric +file}\par +\fi + +\M1088. The first 24 bytes (6 words) of a \.{TFM} file contain twelve 16-bit +integers that give the lengths of the various subsequent portions +of the file. These twelve integers are, in order: +$$\vbox{\halign{\hfil#&$\null=\null$#\hfil\cr +\\{lf}&length of the entire file, in words;\cr +\\{lh}&length of the header data, in words;\cr +\\{bc}&smallest character code in the font;\cr +\\{ec}&largest character code in the font;\cr +\\{nw}&number of words in the width table;\cr +\\{nh}&number of words in the height table;\cr +\\{nd}&number of words in the depth table;\cr +\\{ni}&number of words in the italic correction table;\cr +\\{nl}&number of words in the lig/kern table;\cr +\\{nk}&number of words in the kern table;\cr +\\{ne}&number of words in the extensible character table;\cr +\\{np}&number of font parameter words.\cr}}$$ +They are all nonnegative and less than $2^{15}$. We must have $\\{bc}-1\L\\{ec}% +\L255$, +$\\{ne}\L256$, 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. + +\fi + +\M1089. 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} +\tabskip\centering +\halign to\displaywidth{\hfil\\{#}\tabskip=0pt&$\,:\,$\arr#\hfil +\tabskip\centering\cr +header&$[0\to\\{lh}-1]\hbox{\\{stuff}}$\cr +char\_info&$[\\{bc}\to\\{ec}]\\{char\_info\_word}$\cr +width&$[0\to\\{nw}-1]\\{fix\_word}$\cr +height&$[0\to\\{nh}-1]\\{fix\_word}$\cr +depth&$[0\to\\{nd}-1]\\{fix\_word}$\cr +italic&$[0\to\\{ni}-1]\\{fix\_word}$\cr +lig\_kern&$[0\to\\{nl}-1]\\{lig\_kern\_command}$\cr +kern&$[0\to\\{nk}-1]\\{fix\_word}$\cr +exten&$[0\to\\{ne}-1]\\{extensible\_recipe}$\cr +param&$[1\to\\{np}]\\{fix\_word}$\cr}$$ +The most important data type used here is a \\{fix\_word}, which is +a 32-bit representation of a binary fraction. A \\{fix\_word} is a signed +quantity, with the two's complement of the entire word used to represent +negation. Of the 32 bits in a \\{fix\_word}, exactly 12 are to the left of the +binary point; thus, the largest \\{fix\_word} value is $2048-2^{-20}$, and +the smallest is $-2048$. We will see below, however, that all but two of +the \\{fix\_word} values must lie between $-16$ and $+16$. + +\fi + +\M1090. 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, and \MF\ will generate it if the \.{headerbyte} command occurs. +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 MATHSY}'), the next five +give the font family name (e.g., `\.{HELVETICA}' or `\.{CMSY}'), and the +last gives the ``face byte.'' + +\yskip\hang$\\{header}[0]$ is a 32-bit check sum that \MF\ will copy into +the \.{GF} output file. This helps ensure consistency between files, +since \TeX\ records the check sums from the \.{TFM}'s it reads, and these +should match the check sums on actual fonts that are used. The actual +relation between this check sum and the rest of the \.{TFM} file is not +important; the check sum is simply an identification number with the +property that incompatible fonts almost always have distinct check sums. + +\yskip\hang$\\{header}[1]$ is a \\{fix\_word} containing the design size of the +font, in units of \TeX\ points. This number must be at least 1.0; it is +fairly arbitrary, but usually the design size is 10.0 for a ``10 point'' +font, i.e., a font that was designed to look best at a 10-point size, +whatever that really means. When a \TeX\ user asks for a font `\.{at} +$\delta$ \.{pt}', the effect is to override the design size and replace it +by $\delta$, and to multiply the $x$ and~$y$ coordinates of the points in +the font image by a factor of $\delta$ divided by the design size. {\sl +All other dimensions in the\/ \.{TFM} file are \\{fix\_word}\kern-1pt\ +numbers in design-size units.} Thus, for example, the value of $\\{param}[6]$, +which defines the \.{em} unit, is often the \\{fix\_word} value $2^{20}=1.0$, +since many fonts have a design size equal to one em. The other dimensions +must be less than 16 design-size units in absolute value; thus, +$\\{header}[1]$ and $\\{param}[1]$ are the only \\{fix\_word} entries in the +whole +\.{TFM} file whose first byte might be something besides 0 or 255. + +\fi + +\M1091. Next comes the \\{char\_info} array, which contains one \\{char\_info% +\_word} +per character. Each word in this part of the file contains six fields +packed into four bytes as follows. + +\yskip\hang first byte: \\{width\_index} (8 bits)\par +\hang second byte: \\{height\_index} (4 bits) times 16, plus \\{depth\_index} +(4~bits)\par +\hang third byte: \\{italic\_index} (6 bits) times 4, plus \\{tag} +(2~bits)\par +\hang fourth byte: \\{remainder} (8 bits)\par +\yskip\noindent +The actual width of a character is \\{width}$[\\{width\_index}]$, in +design-size +units; this is a device for compressing information, since many characters +have the same width. Since it is quite common for many characters +to have the same height, depth, or italic correction, the \.{TFM} format +imposes a limit of 16 different heights, 16 different depths, and +64 different italic corrections. + +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 + +\M1092. The \\{tag} field in a \\{char\_info\_word} has four values that +explain how to +interpret the \\{remainder} field. + +\def\hangg#1 {\hang\hbox{#1 }} +\yskip\hangg$\\{tag}=0$ (\\{no\_tag}) means that \\{remainder} is unused.\par +\hangg$\\{tag}=1$ (\\{lig\_tag}) means that this character has a +ligature/kerning +program starting at location \\{remainder} in the \\{lig\_kern} array.\par +\hangg$\\{tag}=2$ (\\{list\_tag}) means that this character is part of a chain +of +characters of ascending sizes, and not the largest in the chain. The +\\{remainder} field gives the character code of the next larger character.\par +\hangg$\\{tag}=3$ (\\{ext\_tag}) means that this character code represents an +extensible character, i.e., a character that is built up of smaller pieces +so that it can be made arbitrarily large. The pieces are specified in +$\\{exten}[\\{remainder}]$.\par +\yskip\noindent +Characters with $\\{tag}=2$ and $\\{tag}=3$ are treated as characters with $% +\\{tag}=0$ +unless they are used in special circumstances in math formulas. For example, +\TeX's \.{\\sum} operation looks for a \\{list\_tag}, and the \.{\\left} +operation looks for both \\{list\_tag} and \\{ext\_tag}. + +\Y\P\D \37$\\{no\_tag}=0$\C{vanilla character}\par +\P\D \37$\\{lig\_tag}=1$\C{character has a ligature/kerning program}\par +\P\D \37$\\{list\_tag}=2$\C{character has a successor in a charlist}\par +\P\D \37$\\{ext\_tag}=3$\C{character is extensible}\par +\fi + +\M1093. The \\{lig\_kern} array contains instructions in a simple programming +language +that explains what to do for special letter pairs. Each word in this array is a +\\{lig\_kern\_command} of four bytes. + +\yskip\hang first byte: \\{skip\_byte}, indicates that this is the final +program +step if the byte is 128 or more, otherwise the next step is obtained by +skipping this number of intervening steps.\par +\hang second byte: \\{next\_char}, ``if \\{next\_char} follows the current +character, +then perform the operation and stop, otherwise continue.''\par +\hang third byte: \\{op\_byte}, indicates a ligature step if less than~128, +a kern step otherwise.\par +\hang fourth byte: \\{remainder}.\par +\yskip\noindent +In a kern step, an +additional space equal to $\\{kern}[256\ast(\\{op\_byte}-128)+\\{remainder}]$ +is inserted +between the current character and \\{next\_char}. This amount is +often negative, so that the characters are brought closer together +by kerning; but it might be positive. + +There are eight kinds of ligature steps, having \\{op\_byte} codes $4a+2b+c$ +where +$0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is +\\{remainder} is inserted between the current character and \\{next\_char}; +then the current character is deleted if $b=0$, and \\{next\_char} is +deleted if $c=0$; then we pass over $a$~characters to reach the next +current character (which may have a ligature/kerning program of its own). + +If the very first instruction of the \\{lig\_kern} array has $\\{skip% +\_byte}=255$, +the \\{next\_char} byte is the so-called right boundary character of this font; +the value of \\{next\_char} need not lie between \\{bc} and~\\{ec}. +If the very last instruction of the \\{lig\_kern} array has $\\{skip% +\_byte}=255$, +there is a special ligature/kerning program for a left boundary character, +beginning at location $256\ast\\{op\_byte}+\\{remainder}$. +The interpretation is that \TeX\ puts implicit boundary characters +before and after each consecutive string of characters from the same font. +These implicit characters do not appear in the output, but they can affect +ligatures and kerning. + +If the very first instruction of a character's \\{lig\_kern} program has +$\\{skip\_byte}>128$, the program actually begins in location +$256\ast\\{op\_byte}+\\{remainder}$. This feature allows access to large \\{lig% +\_kern} +arrays, because the first instruction must otherwise +appear in a location $\L255$. + +Any instruction with $\\{skip\_byte}>128$ in the \\{lig\_kern} array must +satisfy +the condition +$$\hbox{$256\ast\\{op\_byte}+\\{remainder}<\\{nl}$.}$$ +If such an instruction is encountered during +normal program execution, it denotes an unconditional halt; no ligature +command is performed. + +\Y\P\D \37$\\{stop\_flag}=128+\\{min\_quarterword}$\C{value indicating `% +\.{STOP}' in a lig/kern program}\par +\P\D \37$\\{kern\_flag}=128+\\{min\_quarterword}$\C{op code for a kern step}\par +\P\D \37$\\{skip\_byte}(\#)\S\\{lig\_kern}[\#].\\{b0}$\par +\P\D \37$\\{next\_char}(\#)\S\\{lig\_kern}[\#].\\{b1}$\par +\P\D \37$\\{op\_byte}(\#)\S\\{lig\_kern}[\#].\\{b2}$\par +\P\D \37$\\{rem\_byte}(\#)\S\\{lig\_kern}[\#].\\{b3}$\par +\fi + +\M1094. Extensible characters are specified by an \\{extensible\_recipe}, which +consists of four bytes called \\{top}, \\{mid}, \\{bot}, and \\{rep} (in this +order). These bytes are the character codes of individual pieces used to +build up a large symbol. If \\{top}, \\{mid}, or \\{bot} are zero, they are +not +present in the built-up result. For example, an extensible vertical line is +like an extensible bracket, except that the top and bottom pieces are missing. + +Let $T$, $M$, $B$, and $R$ denote the respective pieces, or an empty box +if the piece isn't present. Then the extensible characters have the form +$TR^kMR^kB$ from top to bottom, for some $\|k\G0$, unless $M$ is absent; +in the latter case we can have $TR^kB$ for both even and odd values of~\|k. +The width of the extensible character is the width of $R$; and the +height-plus-depth is the sum of the individual height-plus-depths of the +components used, since the pieces are butted together in a vertical list. + +\Y\P\D \37$\\{ext\_top}(\#)\S\\{exten}[\#].\\{b0}$\C{\\{top} piece in a recipe}% +\par +\P\D \37$\\{ext\_mid}(\#)\S\\{exten}[\#].\\{b1}$\C{\\{mid} piece in a recipe}% +\par +\P\D \37$\\{ext\_bot}(\#)\S\\{exten}[\#].\\{b2}$\C{\\{bot} piece in a recipe}% +\par +\P\D \37$\\{ext\_rep}(\#)\S\\{exten}[\#].\\{b3}$\C{\\{rep} piece in a recipe}% +\par +\fi + +\M1095. 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 is 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 \O{40} 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. + +\Y\P\D \37$\\{slant\_code}=1$\par +\P\D \37$\\{space\_code}=2$\par +\P\D \37$\\{space\_stretch\_code}=3$\par +\P\D \37$\\{space\_shrink\_code}=4$\par +\P\D \37$\\{x\_height\_code}=5$\par +\P\D \37$\\{quad\_code}=6$\par +\P\D \37$\\{extra\_space\_code}=7$\par +\fi + +\M1096. So that is what \.{TFM} files hold. One of \MF's duties is to output +such +information, and it does this all at once at the end of a job. +In order to prepare for such frenetic activity, it squirrels away the +necessary facts in various arrays as information becomes available. + +Character dimensions (\&{charwd}, \&{charht}, \&{chardp}, and \&{charic}) +are stored respectively in \\{tfm\_width}, \\{tfm\_height}, \\{tfm\_depth}, and +\\{tfm\_ital\_corr}. Other information about a character (e.g., about +its ligatures or successors) is accessible via the \\{char\_tag} and +\\{char\_remainder} arrays. Other information about the font as a whole +is kept in additional arrays called \\{header\_byte}, \\{lig\_kern}, +\\{kern}, \\{exten}, and \\{param}. + +\Y\P\D \37$\\{undefined\_label}\S\\{lig\_table\_size}$\C{an undefined local +label}\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4$\\{bc},\39\\{ec}$: \37\\{eight\_bits};\C{smallest and largest character +codes shipped out}\6 +\4\\{tfm\_width}: \37\&{array} $[\\{eight\_bits}]$ \1\&{of}\5 +\\{scaled};\C{\&{charwd} values}\2\6 +\4\\{tfm\_height}: \37\&{array} $[\\{eight\_bits}]$ \1\&{of}\5 +\\{scaled};\C{\&{charht} values}\2\6 +\4\\{tfm\_depth}: \37\&{array} $[\\{eight\_bits}]$ \1\&{of}\5 +\\{scaled};\C{\&{chardp} values}\2\6 +\4\\{tfm\_ital\_corr}: \37\&{array} $[\\{eight\_bits}]$ \1\&{of}\5 +\\{scaled};\C{\&{charic} values}\2\6 +\4\\{char\_exists}: \37\&{array} $[\\{eight\_bits}]$ \1\&{of}\5 +\\{boolean};\C{has this code been shipped out?}\2\6 +\4\\{char\_tag}: \37\&{array} $[\\{eight\_bits}]$ \1\&{of}\5 +$\\{no\_tag}\to\\{ext\_tag}$;\C{\\{remainder} category}\2\6 +\4\\{char\_remainder}: \37\&{array} $[\\{eight\_bits}]$ \1\&{of}\5 +$0\to\\{lig\_table\_size}$;\C{the \\{remainder} byte}\2\6 +\4\\{header\_byte}: \37\&{array} $[1\to\\{header\_size}]$ \1\&{of}\5 +$-1\to255$;\C{bytes of the \.{TFM} header, or $-1$ if unset}\2\6 +\4\\{lig\_kern}: \37\&{array} $[0\to\\{lig\_table\_size}]$ \1\&{of}\5 +\\{four\_quarters};\C{the ligature/kern table}\2\6 +\4\\{nl}: \37$0\to32767-256$;\C{the number of ligature/kern steps so far}\6 +\4\\{kern}: \37\&{array} $[0\to\\{max\_kerns}]$ \1\&{of}\5 +\\{scaled};\C{distinct kerning amounts}\2\6 +\4\\{nk}: \37$0\to\\{max\_kerns}$;\C{the number of distinct kerns so far}\6 +\4\\{exten}: \37\&{array} $[\\{eight\_bits}]$ \1\&{of}\5 +\\{four\_quarters};\C{extensible character recipes}\2\6 +\4\\{ne}: \37$0\to256$;\C{the number of extensible characters so far}\6 +\4\\{param}: \37\&{array} $[1\to\\{max\_font\_dimen}]$ \1\&{of}\5 +\\{scaled};\C{\&{fontinfo} parameters}\2\6 +\4\\{np}: \37$0\to\\{max\_font\_dimen}$;\C{the largest \&{fontinfo} parameter +specified so far}\6 +\4$\\{nw},\39\\{nh},\39\\{nd},\39\\{ni}$: \37$0\to256$;\C{sizes of \.{TFM} +subtables}\6 +\4\\{skip\_table}: \37\&{array} $[\\{eight\_bits}]$ \1\&{of}\5 +$0\to\\{lig\_table\_size}$;\C{local label status}\2\6 +\4\\{lk\_started}: \37\\{boolean};\C{has there been a lig/kern step in this +command yet?}\6 +\4\\{bchar}: \37\\{integer};\C{right boundary character}\6 +\4\\{bch\_label}: \37$0\to\\{lig\_table\_size}$;\C{left boundary starting +location}\6 +\4$\\{ll},\39\\{lll}$: \37$0\to\\{lig\_table\_size}$;\C{registers used for +lig/kern processing}\6 +\4\\{label\_loc}: \37\&{array} $[0\to256]$ \1\&{of}\5 +$-1\to\\{lig\_table\_size}$;\C{lig/kern starting addresses}\2\6 +\4\\{label\_char}: \37\&{array} $[1\to256]$ \1\&{of}\5 +\\{eight\_bits};\C{characters for \\{label\_loc}}\2\6 +\4\\{label\_ptr}: \37$0\to256$;\C{highest position occupied in \\{label\_loc}}% +\par +\fi + +\M1097. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +\&{for} $\|k\K0\mathrel{\&{to}}255$ \1\&{do}\6 +\&{begin} \37$\\{tfm\_width}[\|k]\K0$;\5 +$\\{tfm\_height}[\|k]\K0$;\5 +$\\{tfm\_depth}[\|k]\K0$;\5 +$\\{tfm\_ital\_corr}[\|k]\K0$;\5 +$\\{char\_exists}[\|k]\K\\{false}$;\5 +$\\{char\_tag}[\|k]\K\\{no\_tag}$;\5 +$\\{char\_remainder}[\|k]\K0$;\5 +$\\{skip\_table}[\|k]\K\\{undefined\_label}$;\6 +\&{end};\2\6 +\&{for} $\|k\K1\mathrel{\&{to}}\\{header\_size}$ \1\&{do}\5 +$\\{header\_byte}[\|k]\K-1$;\2\6 +$\\{bc}\K255$;\5 +$\\{ec}\K0$;\5 +$\\{nl}\K0$;\5 +$\\{nk}\K0$;\5 +$\\{ne}\K0$;\5 +$\\{np}\K0$;\6 +$\\{internal}[\\{boundary\_char}]\K-\\{unity}$;\5 +$\\{bch\_label}\K\\{undefined\_label}$;\6 +$\\{label\_loc}[0]\K-1$;\5 +$\\{label\_ptr}\K0$;\par +\fi + +\M1098. \P$\X1098:Declare the function called \\{tfm\_check}\X\S$\6 +\4\&{function}\1\ \37$\\{tfm\_check}(\|m:\\{small\_number})$: \37\\{scaled};\2% +\6 +\&{begin} \37\&{if} $\\{abs}(\\{internal}[\|m])\G\\{fraction\_half}$ \1\&{then}% +\6 +\&{begin} \37$\\{print\_err}(\.{"Enormous\ "})$;\5 +$\\{print}(\\{int\_name}[\|m])$;\5 +$\\{print}(\.{"\ has\ been\ reduced"})$;\5 +$\\{help1}(\.{"Font\ metric\ dimensions\ must\ be\ less\ than\ 2048pt."})$;\5 +\\{put\_get\_error};\6 +\&{if} $\\{internal}[\|m]>0$ \1\&{then}\5 +$\\{tfm\_check}\K\\{fraction\_half}-1$\6 +\4\&{else} $\\{tfm\_check}\K1-\\{fraction\_half}$;\2\6 +\&{end}\6 +\4\&{else} $\\{tfm\_check}\K\\{internal}[\|m]$;\2\6 +\&{end};\par +\U1070.\fi + +\M1099. \P$\X1099:Store the width information for character code~\|c\X\S$\6 +\&{if} $\|c<\\{bc}$ \1\&{then}\5 +$\\{bc}\K\|c$;\2\6 +\&{if} $\|c>\\{ec}$ \1\&{then}\5 +$\\{ec}\K\|c$;\2\6 +$\\{char\_exists}[\|c]\K\\{true}$;\5 +$\\{gf\_dx}[\|c]\K\\{internal}[\\{char\_dx}]$;\5 +$\\{gf\_dy}[\|c]\K\\{internal}[\\{char\_dy}]$;\5 +$\\{tfm\_width}[\|c]\K\\{tfm\_check}(\\{char\_wd})$;\5 +$\\{tfm\_height}[\|c]\K\\{tfm\_check}(\\{char\_ht})$;\5 +$\\{tfm\_depth}[\|c]\K\\{tfm\_check}(\\{char\_dp})$;\5 +$\\{tfm\_ital\_corr}[\|c]\K\\{tfm\_check}(\\{char\_ic})$\par +\U1070.\fi + +\M1100. Now let's consider \MF's special \.{TFM}-oriented commands. + +\Y\P$\4\X1020:Cases of \\{do\_statement} that invoke particular commands\X% +\mathrel{+}\S$\6 +\4\\{tfm\_command}: \37\\{do\_tfm\_command};\par +\fi + +\M1101. \P\D \37$\\{char\_list\_code}=0$\par +\P\D \37$\\{lig\_table\_code}=1$\par +\P\D \37$\\{extensible\_code}=2$\par +\P\D \37$\\{header\_byte\_code}=3$\par +\P\D \37$\\{font\_dimen\_code}=4$\par +\Y\P$\4\X192:Put each of \MF's primitives into the hash table\X\mathrel{+}\S$\6 +$\\{primitive}(\.{"charlist"},\39\\{tfm\_command},\39\\{char\_list\_code})$;\6 +$\\{primitive}(\.{"ligtable"},\39\\{tfm\_command},\39\\{lig\_table\_code})$;\6 +$\\{primitive}(\.{"extensible"},\39\\{tfm\_command},\39\\{extensible\_code})$;\6 +$\\{primitive}(\.{"headerbyte"},\39\\{tfm\_command},\39\\{header\_byte% +\_code})$;\6 +$\\{primitive}(\.{"fontdimen"},\39\\{tfm\_command},\39\\{font\_dimen\_code})$;% +\par +\fi + +\M1102. \P$\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of +primitives\X\mathrel{+}\S$\6 +\4\\{tfm\_command}: \37\&{case} $\|m$ \1\&{of}\6 +\4\\{char\_list\_code}: \37$\\{print}(\.{"charlist"})$;\6 +\4\\{lig\_table\_code}: \37$\\{print}(\.{"ligtable"})$;\6 +\4\\{extensible\_code}: \37$\\{print}(\.{"extensible"})$;\6 +\4\\{header\_byte\_code}: \37$\\{print}(\.{"headerbyte"})$;\6 +\4\&{othercases} \37$\\{print}(\.{"fontdimen"})$\2\6 +\&{endcases};\par +\fi + +\M1103. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{function}\1\ \37\\{get\_code}: \37\\{eight\_bits};\C{scans a character +code value}\6 +\4\&{label} \37\\{found};\6 +\4\&{var} \37\|c: \37\\{integer};\C{the code value found}\2\6 +\&{begin} \37\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_type}=\\{known}$ \1\&{then}\6 +\&{begin} \37$\|c\K\\{round\_unscaled}(\\{cur\_exp})$;\6 +\&{if} $\|c\G0$ \1\&{then}\6 +\&{if} $\|c<256$ \1\&{then}\5 +\&{goto} \37\\{found};\2\2\6 +\&{end}\6 +\4\&{else} \&{if} $\\{cur\_type}=\\{string\_type}$ \1\&{then}\6 +\&{if} $\\{length}(\\{cur\_exp})=1$ \1\&{then}\6 +\&{begin} \37$\|c\K\\{so}(\\{str\_pool}[\\{str\_start}[\\{cur\_exp}]])$;\5 +\&{goto} \37\\{found};\6 +\&{end};\2\2\2\6 +$\\{exp\_err}(\.{"Invalid\ code\ has\ been\ replaced\ by\ 0"})$;\5 +$\\{help2}(\.{"I\ was\ looking\ for\ a\ number\ between\ 0\ and\ 255,\ or\ for\ +a"})$\6 +$(\.{"string\ of\ length\ 1.\ Didn\'t\ find\ it;\ will\ use\ 0\ instead."})$;\5 +$\\{put\_get\_flush\_error}(0)$;\5 +$\|c\K0$;\6 +\4\\{found}: \37$\\{get\_code}\K\|c$;\6 +\&{end};\par +\fi + +\M1104. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{set\_tag}(\|c:\\{halfword};\,\35\|t:\\{small% +\_number};\,\35\|r:\\{halfword})$;\2\6 +\&{begin} \37\&{if} $\\{char\_tag}[\|c]=\\{no\_tag}$ \1\&{then}\6 +\&{begin} \37$\\{char\_tag}[\|c]\K\|t$;\5 +$\\{char\_remainder}[\|c]\K\|r$;\6 +\&{if} $\|t=\\{lig\_tag}$ \1\&{then}\6 +\&{begin} \37$\\{incr}(\\{label\_ptr})$;\5 +$\\{label\_loc}[\\{label\_ptr}]\K\|r$;\5 +$\\{label\_char}[\\{label\_ptr}]\K\|c$;\6 +\&{end};\2\6 +\&{end}\6 +\4\&{else} \X1105:Complain about a character tag conflict\X;\2\6 +\&{end};\par +\fi + +\M1105. \P$\X1105:Complain about a character tag conflict\X\S$\6 +\&{begin} \37$\\{print\_err}(\.{"Character\ "})$;\6 +\&{if} $(\|c>\.{"\ "})\W(\|c<127)$ \1\&{then}\5 +$\\{print}(\|c)$\6 +\4\&{else} \&{if} $\|c=256$ \1\&{then}\5 +$\\{print}(\.{"||"})$\6 +\4\&{else} \&{begin} \37$\\{print}(\.{"code\ "})$;\5 +$\\{print\_int}(\|c)$;\6 +\&{end};\2\2\6 +$\\{print}(\.{"\ is\ already\ "})$;\6 +\&{case} $\\{char\_tag}[\|c]$ \1\&{of}\6 +\4\\{lig\_tag}: \37$\\{print}(\.{"in\ a\ ligtable"})$;\6 +\4\\{list\_tag}: \37$\\{print}(\.{"in\ a\ charlist"})$;\6 +\4\\{ext\_tag}: \37$\\{print}(\.{"extensible"})$;\2\6 +\&{end};\C{there are no other cases}\6 +$\\{help2}(\.{"It\'s\ not\ legal\ to\ label\ a\ character\ more\ than\ +once."})$\6 +$(\.{"So\ I\'ll\ not\ change\ anything\ just\ now."})$;\5 +\\{put\_get\_error};\6 +\&{end}\par +\U1104.\fi + +\M1106. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_tfm\_command};\6 +\4\&{label} \37$\\{continue},\39\\{done}$;\6 +\4\&{var} \37$\|c,\39\\{cc}$: \37$0\to256$;\C{character codes}\6 +\|k: \37$0\to\\{max\_kerns}$;\C{index into the \\{kern} array}\6 +\|j: \37\\{integer};\C{index into \\{header\_byte} or \\{param}}\2\6 +\&{begin} \37\&{case} $\\{cur\_mod}$ \1\&{of}\6 +\4\\{char\_list\_code}: \37\&{begin} \37$\|c\K\\{get\_code}$;\C{we will store a +list of character successors}\6 +\&{while} $\\{cur\_cmd}=\\{colon}$ \1\&{do}\6 +\&{begin} \37$\\{cc}\K\\{get\_code}$;\5 +$\\{set\_tag}(\|c,\39\\{list\_tag},\39\\{cc})$;\5 +$\|c\K\\{cc}$;\6 +\&{end};\2\6 +\&{end};\6 +\4\\{lig\_table\_code}: \37\X1107:Store a list of ligature/kern steps\X;\6 +\4\\{extensible\_code}: \37\X1113:Define an extensible recipe\X;\6 +\4$\\{header\_byte\_code},\39\\{font\_dimen\_code}$: \37\&{begin} \37$\|c\K% +\\{cur\_mod}$;\5 +\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $(\\{cur\_type}\I\\{known})\V(\\{cur\_exp}<\\{half\_unit})$ \1\&{then}\6 +\&{begin} \37$\\{exp\_err}(\.{"Improper\ location"})$;\5 +$\\{help2}(\.{"I\ was\ looking\ for\ a\ known,\ positive\ number."})$\6 +$(\.{"For\ safety\'s\ sake\ I\'ll\ ignore\ the\ present\ command."})$;\5 +\\{put\_get\_error};\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\|j\K\\{round\_unscaled}(\\{cur\_exp})$;\6 +\&{if} $\\{cur\_cmd}\I\\{colon}$ \1\&{then}\6 +\&{begin} \37$\\{missing\_err}(\.{":"})$;\5 +$\\{help1}(\.{"A\ colon\ should\ follow\ a\ headerbyte\ or\ fontinfo\ +location."})$;\5 +\\{back\_error};\6 +\&{end};\2\6 +\&{if} $\|c=\\{header\_byte\_code}$ \1\&{then}\5 +\X1114:Store a list of header bytes\X\6 +\4\&{else} \X1115:Store a list of font dimensions\X;\2\6 +\&{end};\2\6 +\&{end};\2\6 +\&{end};\C{there are no other cases}\6 +\&{end};\par +\fi + +\M1107. \P$\X1107:Store a list of ligature/kern steps\X\S$\6 +\&{begin} \37$\\{lk\_started}\K\\{false}$;\6 +\4\\{continue}: \37\\{get\_x\_next};\6 +\&{if} $(\\{cur\_cmd}=\\{skip\_to})\W\\{lk\_started}$ \1\&{then}\5 +\X1110:Process a \\{skip\_to} command and \&{goto} \\{done}\X;\2\6 +\&{if} $\\{cur\_cmd}=\\{bchar\_label}$ \1\&{then}\6 +\&{begin} \37$\|c\K256$;\5 +$\\{cur\_cmd}\K\\{colon}$;\ \&{end}\6 +\4\&{else} \&{begin} \37\\{back\_input};\5 +$\|c\K\\{get\_code}$;\ \&{end};\2\6 +\&{if} $(\\{cur\_cmd}=\\{colon})\V(\\{cur\_cmd}=\\{double\_colon})$ \1\&{then}\5 +\X1111:Record a label in a lig/kern subprogram and \&{goto} \\{continue}\X;\2\6 +\&{if} $\\{cur\_cmd}=\\{lig\_kern\_token}$ \1\&{then}\5 +\X1112:Compile a ligature/kern command\X\6 +\4\&{else} \&{begin} \37$\\{print\_err}(\.{"Illegal\ ligtable\ step"})$;\5 +$\\{help1}(\.{"I\ was\ looking\ for\ \`=:\'\ or\ \`kern\'\ here."})$;\5 +\\{back\_error};\5 +$\\{next\_char}(\\{nl})\K\\{qi}(0)$;\5 +$\\{op\_byte}(\\{nl})\K\\{qi}(0)$;\5 +$\\{rem\_byte}(\\{nl})\K\\{qi}(0)$;\6 +$\\{skip\_byte}(\\{nl})\K\\{stop\_flag}+1$;\C{this specifies an unconditional +stop}\6 +\&{end};\2\6 +\&{if} $\\{nl}=\\{lig\_table\_size}$ \1\&{then}\5 +$\\{overflow}(\.{"ligtable\ size"},\39\\{lig\_table\_size})$;\2\6 +$\\{incr}(\\{nl})$;\6 +\&{if} $\\{cur\_cmd}=\\{comma}$ \1\&{then}\5 +\&{goto} \37\\{continue};\2\6 +\&{if} $\\{skip\_byte}(\\{nl}-1)<\\{stop\_flag}$ \1\&{then}\5 +$\\{skip\_byte}(\\{nl}-1)\K\\{stop\_flag}$;\2\6 +\4\\{done}: \37\&{end}\par +\U1106.\fi + +\M1108. \P$\X192:Put each of \MF's primitives into the hash table\X\mathrel{+}% +\S$\6 +$\\{primitive}(\.{"=:"},\39\\{lig\_kern\_token},\390)$;\5 +$\\{primitive}(\.{"=:|"},\39\\{lig\_kern\_token},\391)$;\5 +$\\{primitive}(\.{"=:|>"},\39\\{lig\_kern\_token},\395)$;\5 +$\\{primitive}(\.{"|=:"},\39\\{lig\_kern\_token},\392)$;\5 +$\\{primitive}(\.{"|=:>"},\39\\{lig\_kern\_token},\396)$;\5 +$\\{primitive}(\.{"|=:|"},\39\\{lig\_kern\_token},\393)$;\5 +$\\{primitive}(\.{"|=:|>"},\39\\{lig\_kern\_token},\397)$;\5 +$\\{primitive}(\.{"|=:|>>"},\39\\{lig\_kern\_token},\3911)$;\5 +$\\{primitive}(\.{"kern"},\39\\{lig\_kern\_token},\39128)$;\par +\fi + +\M1109. \P$\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of +primitives\X\mathrel{+}\S$\6 +\4\\{lig\_kern\_token}: \37\&{case} $\|m$ \1\&{of}\6 +\40: \37$\\{print}(\.{"=:"})$;\6 +\41: \37$\\{print}(\.{"=:|"})$;\6 +\42: \37$\\{print}(\.{"|=:"})$;\6 +\43: \37$\\{print}(\.{"|=:|"})$;\6 +\45: \37$\\{print}(\.{"=:|>"})$;\6 +\46: \37$\\{print}(\.{"|=:>"})$;\6 +\47: \37$\\{print}(\.{"|=:|>"})$;\6 +\411: \37$\\{print}(\.{"|=:|>>"})$;\6 +\4\&{othercases} \37$\\{print}(\.{"kern"})$\2\6 +\&{endcases};\par +\fi + +\M1110. Local labels are implemented by maintaining the \\{skip\_table} array, +where $\\{skip\_table}[\|c]$ is either \\{undefined\_label} or the address of +the +most recent lig/kern instruction that skips to local label~\|c. In the +latter case, the \\{skip\_byte} in that instruction will (temporarily) +be zero if there were no prior skips to this label, or it will be the +distance to the prior skip. + +We may need to cancel skips that span more than 127 lig/kern steps. + +\Y\P\D \37$\\{cancel\_skips}(\#)\S\\{ll}\K\#$;\6 +\1\&{repeat} \37$\\{lll}\K\\{qo}(\\{skip\_byte}(\\{ll}))$;\5 +$\\{skip\_byte}(\\{ll})\K\\{stop\_flag}$;\5 +$\\{ll}\K\\{ll}-\\{lll}$;\6 +\4\&{until}\5 +$\\{lll}=0$\2\par +\P\D \37$\\{skip\_error}(\#)\S$\1\6 +\&{begin} \37$\\{print\_err}(\.{"Too\ far\ to\ skip"})$;\5 +$\\{help1}(\.{"At\ most\ 127\ lig/kern\ steps\ can\ separate\ skipto1\ from\ +1::."})$;\5 +\\{error};\5 +$\\{cancel\_skips}(\#)$;\6 +\&{end}\2\par +\Y\P$\4\X1110:Process a \\{skip\_to} command and \&{goto} \\{done}\X\S$\6 +\&{begin} \37$\|c\K\\{get\_code}$;\6 +\&{if} $\\{nl}-\\{skip\_table}[\|c]>128$ \1\&{then}\C{$\\{skip\_table}[\|c]<<% +\\{nl}\L\\{undefined\_label}$}\6 +\&{begin} \37$\\{skip\_error}(\\{skip\_table}[\|c])$;\5 +$\\{skip\_table}[\|c]\K\\{undefined\_label}$;\6 +\&{end};\2\6 +\&{if} $\\{skip\_table}[\|c]=\\{undefined\_label}$ \1\&{then}\5 +$\\{skip\_byte}(\\{nl}-1)\K\\{qi}(0)$\6 +\4\&{else} $\\{skip\_byte}(\\{nl}-1)\K\\{qi}(\\{nl}-\\{skip\_table}[\|c]-1)$;\2% +\6 +$\\{skip\_table}[\|c]\K\\{nl}-1$;\5 +\&{goto} \37\\{done};\6 +\&{end}\par +\U1107.\fi + +\M1111. \P$\X1111:Record a label in a lig/kern subprogram and \&{goto} % +\\{continue}\X\S$\6 +\&{begin} \37\&{if} $\\{cur\_cmd}=\\{colon}$ \1\&{then}\6 +\&{if} $\|c=256$ \1\&{then}\5 +$\\{bch\_label}\K\\{nl}$\6 +\4\&{else} $\\{set\_tag}(\|c,\39\\{lig\_tag},\39\\{nl})$\2\6 +\4\&{else} \&{if} $\\{skip\_table}[\|c]<\\{undefined\_label}$ \1\&{then}\6 +\&{begin} \37$\\{ll}\K\\{skip\_table}[\|c]$;\5 +$\\{skip\_table}[\|c]\K\\{undefined\_label}$;\6 +\1\&{repeat} \37$\\{lll}\K\\{qo}(\\{skip\_byte}(\\{ll}))$;\6 +\&{if} $\\{nl}-\\{ll}>128$ \1\&{then}\6 +\&{begin} \37$\\{skip\_error}(\\{ll})$;\5 +\&{goto} \37\\{continue};\6 +\&{end};\2\6 +$\\{skip\_byte}(\\{ll})\K\\{qi}(\\{nl}-\\{ll}-1)$;\5 +$\\{ll}\K\\{ll}-\\{lll}$;\6 +\4\&{until}\5 +$\\{lll}=0$;\2\6 +\&{end};\2\2\6 +\&{goto} \37\\{continue};\6 +\&{end}\par +\U1107.\fi + +\M1112. \P$\X1112:Compile a ligature/kern command\X\S$\6 +\&{begin} \37$\\{next\_char}(\\{nl})\K\\{qi}(\|c)$;\5 +$\\{skip\_byte}(\\{nl})\K\\{qi}(0)$;\6 +\&{if} $\\{cur\_mod}<128$ \1\&{then}\C{ligature op}\6 +\&{begin} \37$\\{op\_byte}(\\{nl})\K\\{qi}(\\{cur\_mod})$;\5 +$\\{rem\_byte}(\\{nl})\K\\{qi}(\\{get\_code})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\6 +\&{begin} \37$\\{exp\_err}(\.{"Improper\ kern"})$;\5 +$\\{help2}(\.{"The\ amount\ of\ kern\ should\ be\ a\ known\ numeric\ value."})$% +\6 +$(\.{"I\'m\ zeroing\ this\ one.\ Proceed,\ with\ fingers\ crossed."})$;\5 +$\\{put\_get\_flush\_error}(0)$;\6 +\&{end};\2\6 +$\\{kern}[\\{nk}]\K\\{cur\_exp}$;\5 +$\|k\K0$;\ \&{while} $\\{kern}[\|k]\I\\{cur\_exp}$ \1\&{do}\5 +$\\{incr}(\|k)$;\2\6 +\&{if} $\|k=\\{nk}$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{nk}=\\{max\_kerns}$ \1\&{then}\5 +$\\{overflow}(\.{"kern"},\39\\{max\_kerns})$;\2\6 +$\\{incr}(\\{nk})$;\6 +\&{end};\2\6 +$\\{op\_byte}(\\{nl})\K\\{kern\_flag}+(\|k\mathbin{\&{div}}256)$;\5 +$\\{rem\_byte}(\\{nl})\K\\{qi}((\|k\mathbin{\&{mod}}256))$;\6 +\&{end};\2\6 +$\\{lk\_started}\K\\{true}$;\6 +\&{end}\par +\U1107.\fi + +\M1113. \P\D \37$\\{missing\_extensible\_punctuation}(\#)\S$\1\6 +\&{begin} \37$\\{missing\_err}(\#)$;\5 +$\\{help1}(\.{"I\'m\ processing\ \`extensible\ c:\ t,m,b,r\'."})$;\5 +\\{back\_error};\6 +\&{end}\2\par +\Y\P$\4\X1113:Define an extensible recipe\X\S$\6 +\&{begin} \37\&{if} $\\{ne}=256$ \1\&{then}\5 +$\\{overflow}(\.{"extensible"},\39256)$;\2\6 +$\|c\K\\{get\_code}$;\5 +$\\{set\_tag}(\|c,\39\\{ext\_tag},\39\\{ne})$;\6 +\&{if} $\\{cur\_cmd}\I\\{colon}$ \1\&{then}\5 +$\\{missing\_extensible\_punctuation}(\.{":"})$;\2\6 +$\\{ext\_top}(\\{ne})\K\\{qi}(\\{get\_code})$;\6 +\&{if} $\\{cur\_cmd}\I\\{comma}$ \1\&{then}\5 +$\\{missing\_extensible\_punctuation}(\.{","})$;\2\6 +$\\{ext\_mid}(\\{ne})\K\\{qi}(\\{get\_code})$;\6 +\&{if} $\\{cur\_cmd}\I\\{comma}$ \1\&{then}\5 +$\\{missing\_extensible\_punctuation}(\.{","})$;\2\6 +$\\{ext\_bot}(\\{ne})\K\\{qi}(\\{get\_code})$;\6 +\&{if} $\\{cur\_cmd}\I\\{comma}$ \1\&{then}\5 +$\\{missing\_extensible\_punctuation}(\.{","})$;\2\6 +$\\{ext\_rep}(\\{ne})\K\\{qi}(\\{get\_code})$;\5 +$\\{incr}(\\{ne})$;\6 +\&{end}\par +\U1106.\fi + +\M1114. \P$\X1114:Store a list of header bytes\X\S$\6 +\1\&{repeat} \37\&{if} $\|j>\\{header\_size}$ \1\&{then}\5 +$\\{overflow}(\.{"headerbyte"},\39\\{header\_size})$;\2\6 +$\\{header\_byte}[\|j]\K\\{get\_code}$;\5 +$\\{incr}(\|j)$;\6 +\4\&{until}\5 +$\\{cur\_cmd}\I\\{comma}$\2\par +\U1106.\fi + +\M1115. \P$\X1115:Store a list of font dimensions\X\S$\6 +\1\&{repeat} \37\&{if} $\|j>\\{max\_font\_dimen}$ \1\&{then}\5 +$\\{overflow}(\.{"fontdimen"},\39\\{max\_font\_dimen})$;\2\6 +\&{while} $\|j>\\{np}$ \1\&{do}\6 +\&{begin} \37$\\{incr}(\\{np})$;\5 +$\\{param}[\\{np}]\K0$;\6 +\&{end};\2\6 +\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{cur\_type}\I\\{known}$ \1\&{then}\6 +\&{begin} \37$\\{exp\_err}(\.{"Improper\ font\ parameter"})$;\5 +$\\{help1}(\.{"I\'m\ zeroing\ this\ one.\ Proceed,\ with\ fingers\ +crossed."})$;\5 +$\\{put\_get\_flush\_error}(0)$;\6 +\&{end};\2\6 +$\\{param}[\|j]\K\\{cur\_exp}$;\5 +$\\{incr}(\|j)$;\6 +\4\&{until}\5 +$\\{cur\_cmd}\I\\{comma}$\2\par +\U1106.\fi + +\M1116. OK: We've stored all the data that is needed for the \.{TFM} file. +All that remains is to output it in the correct format. + +An interesting problem needs to be solved in this connection, because +the \.{TFM} format allows at most 256~widths, 16~heights, 16~depths, +and 64~italic corrections. If the data has more distinct values than +this, we want to meet the necessary restrictions by perturbing the +given values as little as possible. + +\MF\ solves this problem in two steps. First the values of a given +kind (widths, heights, depths, or italic corrections) are sorted; +then the list of sorted values is perturbed, if necessary. + +The sorting operation is facilitated by having a special node of +essentially infinite \\{value} at the end of the current list. + +\Y\P$\4\X176:Initialize table entries (done by \.{INIMF} only)\X\mathrel{+}\S$\6 +$\\{value}(\\{inf\_val})\K\\{fraction\_four}$;\par +\fi + +\M1117. Straight linear insertion is good enough for sorting, since the lists +are usually not terribly long. As we work on the data, the current list +will start at $\\{link}(\\{temp\_head})$ and end at \\{inf\_val}; the nodes in +this +list will be in increasing order of their \\{value} fields. + +Given such a list, the \\{sort\_in} function takes a value and returns a +pointer +to where that value can be found in the list. The value is inserted in +the proper place, if necessary. + +At the time we need to do these operations, most of \MF's work has been +completed, so we will have plenty of memory to play with. The value nodes +that are allocated for sorting will never be returned to free storage. + +\Y\P\D \37$\\{clear\_the\_list}\S\\{link}(\\{temp\_head})\K\\{inf\_val}$\par +\Y\P\4\&{function}\1\ \37$\\{sort\_in}(\|v:\\{scaled})$: \37\\{pointer};\6 +\4\&{label} \37\\{found};\6 +\4\&{var} \37$\|p,\39\|q,\39\|r$: \37\\{pointer};\C{list manipulation +registers}\2\6 +\&{begin} \37$\|p\K\\{temp\_head}$;\6 +\~ \1\&{loop}\ \&{begin} \37$\|q\K\\{link}(\|p)$;\6 +\&{if} $\|v\L\\{value}(\|q)$ \1\&{then}\5 +\&{goto} \37\\{found};\2\6 +$\|p\K\|q$;\6 +\&{end};\2\6 +\4\\{found}: \37\&{if} $\|v<\\{value}(\|q)$ \1\&{then}\6 +\&{begin} \37$\|r\K\\{get\_node}(\\{value\_node\_size})$;\5 +$\\{value}(\|r)\K\|v$;\5 +$\\{link}(\|r)\K\|q$;\5 +$\\{link}(\|p)\K\|r$;\6 +\&{end};\2\6 +$\\{sort\_in}\K\\{link}(\|p)$;\6 +\&{end};\par +\fi + +\M1118. Now we come to the interesting part, where we reduce the list if +necessary +until it has the required size. The \\{min\_cover} routine is basic to this +process; it computes the minimum number~\|m such that the values of the +current sorted list can be covered by \|m~intervals of width~\|d. It +also sets the global value \\{perturbation} to the smallest value $d'>d$ +such that the covering found by this algorithm would be different. + +In particular, $\\{min\_cover}(0)$ returns the number of distinct values in the +current list and sets \\{perturbation} to the minimum distance between +adjacent values. + +\Y\P\4\&{function}\1\ \37$\\{min\_cover}(\|d:\\{scaled})$: \37\\{integer};\6 +\4\&{var} \37\|p: \37\\{pointer};\C{runs through the current list}\6 +\|l: \37\\{scaled};\C{the least element covered by the current interval}\6 +\|m: \37\\{integer};\C{lower bound on the size of the minimum cover}\2\6 +\&{begin} \37$\|m\K0$;\5 +$\|p\K\\{link}(\\{temp\_head})$;\5 +$\\{perturbation}\K\\{el\_gordo}$;\6 +\&{while} $\|p\I\\{inf\_val}$ \1\&{do}\6 +\&{begin} \37$\\{incr}(\|m)$;\5 +$\|l\K\\{value}(\|p)$;\6 +\1\&{repeat} \37$\|p\K\\{link}(\|p)$;\6 +\4\&{until}\5 +$\\{value}(\|p)>\|l+\|d$;\2\6 +\&{if} $\\{value}(\|p)-\|l<\\{perturbation}$ \1\&{then}\5 +$\\{perturbation}\K\\{value}(\|p)-\|l$;\2\6 +\&{end};\2\6 +$\\{min\_cover}\K\|m$;\6 +\&{end};\par +\fi + +\M1119. \P$\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{perturbation}: \37\\{scaled};\C{quantity related to \.{TFM} rounding}\6 +\4\\{excess}: \37\\{integer};\C{the list is this much too long}\par +\fi + +\M1120. The smallest \|d such that a given list can be covered with \|m +intervals +is determined by the \\{threshold} routine, which is sort of an inverse +to \\{min\_cover}. The idea is to increase the interval size rapidly until +finding the range, then to go sequentially until the exact borderline has +been discovered. + +\Y\P\4\&{function}\1\ \37$\\{threshold}(\|m:\\{integer})$: \37\\{scaled};\6 +\4\&{var} \37\|d: \37\\{scaled};\C{lower bound on the smallest interval size}\2% +\6 +\&{begin} \37$\\{excess}\K\\{min\_cover}(0)-\|m$;\6 +\&{if} $\\{excess}\L0$ \1\&{then}\5 +$\\{threshold}\K0$\6 +\4\&{else} \&{begin} \37\1\&{repeat} \37$\|d\K\\{perturbation}$;\6 +\4\&{until}\5 +$\\{min\_cover}(\|d+\|d)\L\|m$;\2\6 +\&{while} $\\{min\_cover}(\|d)>\|m$ \1\&{do}\5 +$\|d\K\\{perturbation}$;\2\6 +$\\{threshold}\K\|d$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M1121. The \\{skimp} procedure reduces the current list to at most \|m +entries, +by changing values if necessary. It also sets $\\{info}(\|p)\K\|k$ if $% +\\{value}(\|p)$ +is the \|kth distinct value on the resulting list, and it sets +\\{perturbation} to the maximum amount by which a \\{value} field has +been changed. The size of the resulting list is returned as the +value of \\{skimp}. + +\Y\P\4\&{function}\1\ \37$\\{skimp}(\|m:\\{integer})$: \37\\{integer};\6 +\4\&{var} \37\|d: \37\\{scaled};\C{the size of intervals being coalesced}\6 +$\|p,\39\|q,\39\|r$: \37\\{pointer};\C{list manipulation registers}\6 +\|l: \37\\{scaled};\C{the least value in the current interval}\6 +\|v: \37\\{scaled};\C{a compromise value}\2\6 +\&{begin} \37$\|d\K\\{threshold}(\|m)$;\5 +$\\{perturbation}\K0$;\5 +$\|q\K\\{temp\_head}$;\5 +$\|m\K0$;\5 +$\|p\K\\{link}(\\{temp\_head})$;\6 +\&{while} $\|p\I\\{inf\_val}$ \1\&{do}\6 +\&{begin} \37$\\{incr}(\|m)$;\5 +$\|l\K\\{value}(\|p)$;\5 +$\\{info}(\|p)\K\|m$;\6 +\&{if} $\\{value}(\\{link}(\|p))\L\|l+\|d$ \1\&{then}\5 +\X1122:Replace an interval of values by its midpoint\X;\2\6 +$\|q\K\|p$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +$\\{skimp}\K\|m$;\6 +\&{end};\par +\fi + +\M1122. \P$\X1122:Replace an interval of values by its midpoint\X\S$\6 +\&{begin} \37\1\&{repeat} \37$\|p\K\\{link}(\|p)$;\5 +$\\{info}(\|p)\K\|m$;\5 +$\\{decr}(\\{excess})$;\ \&{if} $\\{excess}=0$ \1\&{then}\5 +$\|d\K0$;\2\6 +\4\&{until}\5 +$\\{value}(\\{link}(\|p))>\|l+\|d$;\2\6 +$\|v\K\|l+\\{half}(\\{value}(\|p)-\|l)$;\6 +\&{if} $\\{value}(\|p)-\|v>\\{perturbation}$ \1\&{then}\5 +$\\{perturbation}\K\\{value}(\|p)-\|v$;\2\6 +$\|r\K\|q$;\6 +\1\&{repeat} \37$\|r\K\\{link}(\|r)$;\5 +$\\{value}(\|r)\K\|v$;\6 +\4\&{until}\5 +$\|r=\|p$;\2\6 +$\\{link}(\|q)\K\|p$;\C{remove duplicate values from the current list}\6 +\&{end}\par +\U1121.\fi + +\M1123. A warning message is issued whenever something is perturbed by +more than 1/16\thinspace pt. + +\Y\P\4\&{procedure}\1\ \37$\\{tfm\_warning}(\|m:\\{small\_number})$;\2\6 +\&{begin} \37$\\{print\_nl}(\.{"(some\ "})$;\5 +$\\{print}(\\{int\_name}[\|m])$;\5 +$\\{print}(\.{"\ values\ had\ to\ be\ adjusted\ by\ as\ much\ as\ "})$;\5 +$\\{print\_scaled}(\\{perturbation})$;\5 +$\\{print}(\.{"pt)"})$;\6 +\&{end};\par +\fi + +\M1124. Here's an example of how we use these routines. +The width data needs to be perturbed only if there are 256 distinct +widths, but \MF\ must check for this case even though it is +highly unusual. + +An integer variable \|k will be defined when we use this code. +The \\{dimen\_head} array will contain pointers to the sorted +lists of dimensions. + +\Y\P$\4\X1124:Massage the \.{TFM} widths\X\S$\6 +\\{clear\_the\_list};\6 +\&{for} $\|k\K\\{bc}\mathrel{\&{to}}\\{ec}$ \1\&{do}\6 +\&{if} $\\{char\_exists}[\|k]$ \1\&{then}\5 +$\\{tfm\_width}[\|k]\K\\{sort\_in}(\\{tfm\_width}[\|k])$;\2\2\6 +$\\{nw}\K\\{skimp}(255)+1$;\5 +$\\{dimen\_head}[1]\K\\{link}(\\{temp\_head})$;\6 +\&{if} $\\{perturbation}\G\O{10000}$ \1\&{then}\5 +$\\{tfm\_warning}(\\{char\_wd})$\2\par +\U1206.\fi + +\M1125. \P$\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{dimen\_head}: \37\&{array} $[1\to4]$ \1\&{of}\5 +\\{pointer};\C{lists of \.{TFM} dimensions}\2\par +\fi + +\M1126. Heights, depths, and italic corrections are different from widths +not only because their list length is more severely restricted, but +also because zero values do not need to be put into the lists. + +\Y\P$\4\X1126:Massage the \.{TFM} heights, depths, and italic corrections\X\S$\6 +\\{clear\_the\_list};\6 +\&{for} $\|k\K\\{bc}\mathrel{\&{to}}\\{ec}$ \1\&{do}\6 +\&{if} $\\{char\_exists}[\|k]$ \1\&{then}\6 +\&{if} $\\{tfm\_height}[\|k]=0$ \1\&{then}\5 +$\\{tfm\_height}[\|k]\K\\{zero\_val}$\6 +\4\&{else} $\\{tfm\_height}[\|k]\K\\{sort\_in}(\\{tfm\_height}[\|k])$;\2\2\2\6 +$\\{nh}\K\\{skimp}(15)+1$;\5 +$\\{dimen\_head}[2]\K\\{link}(\\{temp\_head})$;\6 +\&{if} $\\{perturbation}\G\O{10000}$ \1\&{then}\5 +$\\{tfm\_warning}(\\{char\_ht})$;\2\6 +\\{clear\_the\_list};\6 +\&{for} $\|k\K\\{bc}\mathrel{\&{to}}\\{ec}$ \1\&{do}\6 +\&{if} $\\{char\_exists}[\|k]$ \1\&{then}\6 +\&{if} $\\{tfm\_depth}[\|k]=0$ \1\&{then}\5 +$\\{tfm\_depth}[\|k]\K\\{zero\_val}$\6 +\4\&{else} $\\{tfm\_depth}[\|k]\K\\{sort\_in}(\\{tfm\_depth}[\|k])$;\2\2\2\6 +$\\{nd}\K\\{skimp}(15)+1$;\5 +$\\{dimen\_head}[3]\K\\{link}(\\{temp\_head})$;\6 +\&{if} $\\{perturbation}\G\O{10000}$ \1\&{then}\5 +$\\{tfm\_warning}(\\{char\_dp})$;\2\6 +\\{clear\_the\_list};\6 +\&{for} $\|k\K\\{bc}\mathrel{\&{to}}\\{ec}$ \1\&{do}\6 +\&{if} $\\{char\_exists}[\|k]$ \1\&{then}\6 +\&{if} $\\{tfm\_ital\_corr}[\|k]=0$ \1\&{then}\5 +$\\{tfm\_ital\_corr}[\|k]\K\\{zero\_val}$\6 +\4\&{else} $\\{tfm\_ital\_corr}[\|k]\K\\{sort\_in}(\\{tfm\_ital\_corr}[\|k])$;% +\2\2\2\6 +$\\{ni}\K\\{skimp}(63)+1$;\5 +$\\{dimen\_head}[4]\K\\{link}(\\{temp\_head})$;\6 +\&{if} $\\{perturbation}\G\O{10000}$ \1\&{then}\5 +$\\{tfm\_warning}(\\{char\_ic})$\2\par +\U1206.\fi + +\M1127. \P$\X176:Initialize table entries (done by \.{INIMF} only)\X\mathrel{+}% +\S$\6 +$\\{value}(\\{zero\_val})\K0$;\5 +$\\{info}(\\{zero\_val})\K0$;\par +\fi + +\M1128. Bytes 5--8 of the header are set to the design size, unless the user +has +some crazy reason for specifying them differently. + +Error messages are not allowed at the time this procedure is called, +so a warning is printed instead. + +The value of \\{max\_tfm\_dimen} is calculated so that +$$\hbox{$\\{make\_scaled}(16\ast\\{max\_tfm\_dimen},\\{internal}[\\{design% +\_size}])$} +< \\{three\_bytes}.$$ + +\Y\P\D \37$\\{three\_bytes}\S\O{100000000}$\C{$2^{24}$}\par +\Y\P\4\&{procedure}\1\ \37\\{fix\_design\_size};\6 +\4\&{var} \37\|d: \37\\{scaled};\C{the design size}\2\6 +\&{begin} \37$\|d\K\\{internal}[\\{design\_size}]$;\6 +\&{if} $(\|d<\\{unity})\V(\|d\G\\{fraction\_half})$ \1\&{then}\6 +\&{begin} \37\&{if} $\|d\I0$ \1\&{then}\5 +$\\{print\_nl}(\.{"(illegal\ design\ size\ has\ been\ changed\ to\ 128pt)"})$;% +\2\6 +$\|d\K\O{40000000}$;\5 +$\\{internal}[\\{design\_size}]\K\|d$;\6 +\&{end};\2\6 +\&{if} $\\{header\_byte}[5]<0$ \1\&{then}\6 +\&{if} $\\{header\_byte}[6]<0$ \1\&{then}\6 +\&{if} $\\{header\_byte}[7]<0$ \1\&{then}\6 +\&{if} $\\{header\_byte}[8]<0$ \1\&{then}\6 +\&{begin} \37$\\{header\_byte}[5]\K\|d\mathbin{\&{div}}\O{4000000}$;\5 +$\\{header\_byte}[6]\K(\|d\mathbin{\&{div}}4096)\mathbin{\&{mod}}256$;\5 +$\\{header\_byte}[7]\K(\|d\mathbin{\&{div}}16)\mathbin{\&{mod}}256$;\5 +$\\{header\_byte}[8]\K(\|d\mathbin{\&{mod}}16)\ast16$;\6 +\&{end};\2\2\2\2\6 +$\\{max\_tfm\_dimen}\K16\ast\\{internal}[\\{design\_size}]-\\{internal}[% +\\{design\_size}]\mathbin{\&{div}}\O{10000000}$;\6 +\&{if} $\\{max\_tfm\_dimen}\G\\{fraction\_half}$ \1\&{then}\5 +$\\{max\_tfm\_dimen}\K\\{fraction\_half}-1$;\2\6 +\&{end};\par +\fi + +\M1129. The \\{dimen\_out} procedure computes a \\{fix\_word} relative to the +design size. If the data was out of range, it is corrected and the +global variable \\{tfm\_changed} is increased by~one. + +\Y\P\4\&{function}\1\ \37$\\{dimen\_out}(\|x:\\{scaled})$: \37\\{integer};\2\6 +\&{begin} \37\&{if} $\\{abs}(\|x)>\\{max\_tfm\_dimen}$ \1\&{then}\6 +\&{begin} \37$\\{incr}(\\{tfm\_changed})$;\6 +\&{if} $\|x>0$ \1\&{then}\5 +$\|x\K\\{three\_bytes}-1$\ \&{else} $\|x\K1-\\{three\_bytes}$;\2\6 +\&{end}\6 +\4\&{else} $\|x\K\\{make\_scaled}(\|x\ast16,\39\\{internal}[\\{design% +\_size}])$;\2\6 +$\\{dimen\_out}\K\|x$;\6 +\&{end};\par +\fi + +\M1130. \P$\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{max\_tfm\_dimen}: \37\\{scaled};\C{bound on widths, heights, kerns, etc.}\6 +\4\\{tfm\_changed}: \37\\{integer};\C{the number of data entries that were out +of bounds}\par +\fi + +\M1131. If the user has not specified any of the first four header bytes, +the \\{fix\_check\_sum} procedure replaces them by a ``check sum'' computed +from the \\{tfm\_width} data relative to the design size. + +\Y\P\4\&{procedure}\1\ \37\\{fix\_check\_sum};\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37\|k: \37\\{eight\_bits};\C{runs through character codes}\6 +$\\{b1},\39\\{b2},\39\\{b3},\39\\{b4}$: \37\\{eight\_bits};\C{bytes of the +check sum}\6 +\|x: \37\\{integer};\C{hash value used in check sum computation}\2\6 +\&{begin} \37\&{if} $\\{header\_byte}[1]<0$ \1\&{then}\6 +\&{if} $\\{header\_byte}[2]<0$ \1\&{then}\6 +\&{if} $\\{header\_byte}[3]<0$ \1\&{then}\6 +\&{if} $\\{header\_byte}[4]<0$ \1\&{then}\6 +\&{begin} \37\X1132:Compute a check sum in $(\\{b1},\\{b2},\\{b3},\\{b4})$\X;\6 +$\\{header\_byte}[1]\K\\{b1}$;\5 +$\\{header\_byte}[2]\K\\{b2}$;\5 +$\\{header\_byte}[3]\K\\{b3}$;\5 +$\\{header\_byte}[4]\K\\{b4}$;\5 +\&{return};\6 +\&{end};\2\2\2\2\6 +\&{for} $\|k\K1\mathrel{\&{to}}4$ \1\&{do}\6 +\&{if} $\\{header\_byte}[\|k]<0$ \1\&{then}\5 +$\\{header\_byte}[\|k]\K0$;\2\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M1132. \P$\X1132:Compute a check sum in $(\\{b1},\\{b2},\\{b3},\\{b4})$\X\S$\6 +$\\{b1}\K\\{bc}$;\5 +$\\{b2}\K\\{ec}$;\5 +$\\{b3}\K\\{bc}$;\5 +$\\{b4}\K\\{ec}$;\5 +$\\{tfm\_changed}\K0$;\6 +\&{for} $\|k\K\\{bc}\mathrel{\&{to}}\\{ec}$ \1\&{do}\6 +\&{if} $\\{char\_exists}[\|k]$ \1\&{then}\6 +\&{begin} \37$\|x\K\\{dimen\_out}(\\{value}(\\{tfm\_width}[\|k]))+(\|k+4)\ast% +\O{20000000}$;\C{this is positive}\6 +$\\{b1}\K(\\{b1}+\\{b1}+\|x)\mathbin{\&{mod}}255$;\5 +$\\{b2}\K(\\{b2}+\\{b2}+\|x)\mathbin{\&{mod}}253$;\5 +$\\{b3}\K(\\{b3}+\\{b3}+\|x)\mathbin{\&{mod}}251$;\5 +$\\{b4}\K(\\{b4}+\\{b4}+\|x)\mathbin{\&{mod}}247$;\6 +\&{end}\2\2\par +\U1131.\fi + +\M1133. Finally we're ready to actually write the \.{TFM} information. +Here are some utility routines for this purpose. + +\Y\P\D \37$\\{tfm\_out}(\#)\S\\{write}(\\{tfm\_file},\39\#)$\C{output one byte +to \\{tfm\_file}}\par +\Y\P\4\&{procedure}\1\ \37$\\{tfm\_two}(\|x:\\{integer})$;\C{output two bytes +to \\{tfm\_file}}\2\6 +\&{begin} \37$\\{tfm\_out}(\|x\mathbin{\&{div}}256)$;\5 +$\\{tfm\_out}(\|x\mathbin{\&{mod}}256)$;\6 +\&{end};\7 +\4\&{procedure}\1\ \37$\\{tfm\_four}(\|x:\\{integer})$;\C{output four bytes to +\\{tfm\_file}}\2\6 +\&{begin} \37\&{if} $\|x\G0$ \1\&{then}\5 +$\\{tfm\_out}(\|x\mathbin{\&{div}}\\{three\_bytes})$\6 +\4\&{else} \&{begin} \37$\|x\K\|x+\O{10000000000}$;\C{use two's complement for +negative values}\6 +$\|x\K\|x+\O{10000000000}$;\5 +$\\{tfm\_out}((\|x\mathbin{\&{div}}\\{three\_bytes})+128)$;\6 +\&{end};\2\6 +$\|x\K\|x\mathbin{\&{mod}}\\{three\_bytes}$;\5 +$\\{tfm\_out}(\|x\mathbin{\&{div}}\\{unity})$;\5 +$\|x\K\|x\mathbin{\&{mod}}\\{unity}$;\5 +$\\{tfm\_out}(\|x\mathbin{\&{div}}\O{400})$;\5 +$\\{tfm\_out}(\|x\mathbin{\&{mod}}\O{400})$;\6 +\&{end};\7 +\4\&{procedure}\1\ \37$\\{tfm\_qqqq}(\|x:\\{four\_quarters})$;\C{output four +quarterwords to \\{tfm\_file}}\2\6 +\&{begin} \37$\\{tfm\_out}(\\{qo}(\|x.\\{b0}))$;\5 +$\\{tfm\_out}(\\{qo}(\|x.\\{b1}))$;\5 +$\\{tfm\_out}(\\{qo}(\|x.\\{b2}))$;\5 +$\\{tfm\_out}(\\{qo}(\|x.\\{b3}))$;\6 +\&{end};\par +\fi + +\M1134. \P$\X1134:Finish the \.{TFM} file\X\S$\6 +\&{if} $\\{job\_name}=0$ \1\&{then}\5 +\\{open\_log\_file};\2\6 +$\\{pack\_job\_name}(\.{".tfm"})$;\6 +\&{while} $\R\\{b\_open\_out}(\\{tfm\_file})$ \1\&{do}\5 +$\\{prompt\_file\_name}(\.{"file\ name\ for\ font\ metrics"},\39\.{".tfm"})$;\2% +\6 +$\\{metric\_file\_name}\K\\{b\_make\_name\_string}(\\{tfm\_file})$;\5 +\X1135:Output the subfile sizes and header bytes\X;\6 +\X1136:Output the character information bytes, then output the dimensions +themselves\X;\6 +\X1139:Output the ligature/kern program\X;\6 +\X1140:Output the extensible character recipes and the font metric parameters% +\X;\6 +\&{stat} \37\&{if} $\\{internal}[\\{tracing\_stats}]>0$ \1\&{then}\5 +\X1141:Log the subfile sizes of the \.{TFM} file\X;\2\ \&{tats}\6 +$\\{print\_nl}(\.{"Font\ metrics\ written\ on\ "})$;\5 +$\\{slow\_print}(\\{metric\_file\_name})$;\5 +$\\{print\_char}(\.{"."})$;\5 +$\\{b\_close}(\\{tfm\_file})$\par +\U1206.\fi + +\M1135. Integer variables \\{lh}, \|k, and \\{lk\_offset} will be defined when +we use +this code. + +\Y\P$\4\X1135:Output the subfile sizes and header bytes\X\S$\6 +$\|k\K\\{header\_size}$;\6 +\&{while} $\\{header\_byte}[\|k]<0$ \1\&{do}\5 +$\\{decr}(\|k)$;\2\6 +$\\{lh}\K(\|k+3)\mathbin{\&{div}}4$;\C{this is the number of header words}\6 +\&{if} $\\{bc}>\\{ec}$ \1\&{then}\5 +$\\{bc}\K1$;\C{if there are no characters, $\\{ec}=0$ and $\\{bc}=1$}\2\6 +\X1137:Compute the ligature/kern program offset and implant the left boundary +label\X;\6 +$\\{tfm\_two}(6+\\{lh}+(\\{ec}-\\{bc}+1)+\\{nw}+\\{nh}+\\{nd}+\\{ni}+\\{nl}+% +\\{lk\_offset}+\\{nk}+\\{ne}+\\{np})$;\C{this is the total number of file words +that will be output}\6 +$\\{tfm\_two}(\\{lh})$;\5 +$\\{tfm\_two}(\\{bc})$;\5 +$\\{tfm\_two}(\\{ec})$;\5 +$\\{tfm\_two}(\\{nw})$;\5 +$\\{tfm\_two}(\\{nh})$;\5 +$\\{tfm\_two}(\\{nd})$;\5 +$\\{tfm\_two}(\\{ni})$;\5 +$\\{tfm\_two}(\\{nl}+\\{lk\_offset})$;\5 +$\\{tfm\_two}(\\{nk})$;\5 +$\\{tfm\_two}(\\{ne})$;\5 +$\\{tfm\_two}(\\{np})$;\6 +\&{for} $\|k\K1\mathrel{\&{to}}4\ast\\{lh}$ \1\&{do}\6 +\&{begin} \37\&{if} $\\{header\_byte}[\|k]<0$ \1\&{then}\5 +$\\{header\_byte}[\|k]\K0$;\2\6 +$\\{tfm\_out}(\\{header\_byte}[\|k])$;\6 +\&{end}\2\par +\U1134.\fi + +\M1136. \P$\X1136:Output the character information bytes, then output the +dimensions themselves\X\S$\6 +\&{for} $\|k\K\\{bc}\mathrel{\&{to}}\\{ec}$ \1\&{do}\6 +\&{if} $\R\\{char\_exists}[\|k]$ \1\&{then}\5 +$\\{tfm\_four}(0)$\6 +\4\&{else} \&{begin} \37$\\{tfm\_out}(\\{info}(\\{tfm\_width}[\|k]))$;\C{the +width index}\6 +$\\{tfm\_out}((\\{info}(\\{tfm\_height}[\|k]))\ast16+\\{info}(\\{tfm\_depth}[% +\|k]))$;\5 +$\\{tfm\_out}((\\{info}(\\{tfm\_ital\_corr}[\|k]))\ast4+\\{char\_tag}[\|k])$;\5 +$\\{tfm\_out}(\\{char\_remainder}[\|k])$;\6 +\&{end};\2\2\6 +$\\{tfm\_changed}\K0$;\6 +\&{for} $\|k\K1\mathrel{\&{to}}4$ \1\&{do}\6 +\&{begin} \37$\\{tfm\_four}(0)$;\5 +$\|p\K\\{dimen\_head}[\|k]$;\6 +\&{while} $\|p\I\\{inf\_val}$ \1\&{do}\6 +\&{begin} \37$\\{tfm\_four}(\\{dimen\_out}(\\{value}(\|p)))$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +\&{end}\2\par +\U1134.\fi + +\M1137. We need to output special instructions at the beginning of the +\\{lig\_kern} array in order to specify the right boundary character +and/or to handle starting addresses that exceed 255. The \\{label\_loc} +and \\{label\_char} arrays have been set up to record all the +starting addresses; we have $-1=\\{label\_loc}[0]<\\{label\_loc}[1]\le\cdots +\le\\{label\_loc}[\\{label\_ptr} ] $. + +\Y\P$\4\X1137:Compute the ligature/kern program offset and implant the left +boundary label\X\S$\6 +$\\{bchar}\K\\{round\_unscaled}(\\{internal}[\\{boundary\_char}])$;\6 +\&{if} $(\\{bchar}<0)\V(\\{bchar}>255)$ \1\&{then}\6 +\&{begin} \37$\\{bchar}\K-1$;\5 +$\\{lk\_started}\K\\{false}$;\5 +$\\{lk\_offset}\K0$;\ \&{end}\6 +\4\&{else} \&{begin} \37$\\{lk\_started}\K\\{true}$;\5 +$\\{lk\_offset}\K1$;\ \&{end};\2\6 +\X1138:Find the minimum \\{lk\_offset} and adjust all remainders\X;\6 +\&{if} $\\{bch\_label}<\\{undefined\_label}$ \1\&{then}\6 +\&{begin} \37$\\{skip\_byte}(\\{nl})\K\\{qi}(255)$;\5 +$\\{next\_char}(\\{nl})\K\\{qi}(0)$;\5 +$\\{op\_byte}(\\{nl})\K\\{qi}(((\\{bch\_label}+\\{lk\_offset})\mathbin{% +\&{div}}256))$;\5 +$\\{rem\_byte}(\\{nl})\K\\{qi}(((\\{bch\_label}+\\{lk\_offset})\mathbin{% +\&{mod}}256))$;\5 +$\\{incr}(\\{nl})$;\C{possibly $\\{nl}=\\{lig\_table\_size}+1$}\6 +\&{end}\2\par +\U1135.\fi + +\M1138. \P$\X1138:Find the minimum \\{lk\_offset} and adjust all remainders\X% +\S$\6 +$\|k\K\\{label\_ptr}$;\C{pointer to the largest unallocated label}\6 +\&{if} $\\{label\_loc}[\|k]+\\{lk\_offset}>255$ \1\&{then}\6 +\&{begin} \37$\\{lk\_offset}\K0$;\5 +$\\{lk\_started}\K\\{false}$;\C{location 0 can do double duty}\6 +\1\&{repeat} \37$\\{char\_remainder}[\\{label\_char}[\|k]]\K\\{lk\_offset}$;\6 +\&{while} $\\{label\_loc}[\|k-1]=\\{label\_loc}[\|k]$ \1\&{do}\6 +\&{begin} \37$\\{decr}(\|k)$;\5 +$\\{char\_remainder}[\\{label\_char}[\|k]]\K\\{lk\_offset}$;\6 +\&{end};\2\6 +$\\{incr}(\\{lk\_offset})$;\5 +$\\{decr}(\|k)$;\6 +\4\&{until}\5 +$\\{lk\_offset}+\\{label\_loc}[\|k]<256$;\C{N.B.: $\\{lk\_offset}=256$ +satisfies this when $\|k=0$}\2\6 +\&{end};\2\6 +\&{if} $\\{lk\_offset}>0$ \1\&{then}\6 +\&{while} $\|k>0$ \1\&{do}\6 +\&{begin} \37$\\{char\_remainder}[\\{label\_char}[\|k]]\K\\{char\_remainder}[% +\\{label\_char}[\|k]]+\\{lk\_offset}$;\5 +$\\{decr}(\|k)$;\6 +\&{end}\2\2\par +\U1137.\fi + +\M1139. \P$\X1139:Output the ligature/kern program\X\S$\6 +\&{for} $\|k\K0\mathrel{\&{to}}255$ \1\&{do}\6 +\&{if} $\\{skip\_table}[\|k]<\\{undefined\_label}$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"(local\ label\ "})$;\5 +$\\{print\_int}(\|k)$;\5 +$\\{print}(\.{"::\ was\ missing)"})$;\5 +$\\{cancel\_skips}(\\{skip\_table}[\|k])$;\6 +\&{end};\2\2\6 +\&{if} $\\{lk\_started}$ \1\&{then}\C{$\\{lk\_offset}=1$ for the special % +\\{bchar}}\6 +\&{begin} \37$\\{tfm\_out}(255)$;\5 +$\\{tfm\_out}(\\{bchar})$;\5 +$\\{tfm\_two}(0)$;\6 +\&{end}\6 +\4\&{else} \&{for} $\|k\K1\mathrel{\&{to}}\\{lk\_offset}$ \1\&{do}\C{output the +redirection specs}\6 +\&{begin} \37$\\{ll}\K\\{label\_loc}[\\{label\_ptr}]$;\6 +\&{if} $\\{bchar}<0$ \1\&{then}\6 +\&{begin} \37$\\{tfm\_out}(254)$;\5 +$\\{tfm\_out}(0)$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{tfm\_out}(255)$;\5 +$\\{tfm\_out}(\\{bchar})$;\6 +\&{end};\2\6 +$\\{tfm\_two}(\\{ll}+\\{lk\_offset})$;\6 +\1\&{repeat} \37$\\{decr}(\\{label\_ptr})$;\6 +\4\&{until}\5 +$\\{label\_loc}[\\{label\_ptr}]<\\{ll}$;\2\6 +\&{end};\2\2\6 +\&{for} $\|k\K0\mathrel{\&{to}}\\{nl}-1$ \1\&{do}\5 +$\\{tfm\_qqqq}(\\{lig\_kern}[\|k])$;\2\6 +\&{for} $\|k\K0\mathrel{\&{to}}\\{nk}-1$ \1\&{do}\5 +$\\{tfm\_four}(\\{dimen\_out}(\\{kern}[\|k]))$\2\par +\U1134.\fi + +\M1140. \P$\X1140:Output the extensible character recipes and the font metric +parameters\X\S$\6 +\&{for} $\|k\K0\mathrel{\&{to}}\\{ne}-1$ \1\&{do}\5 +$\\{tfm\_qqqq}(\\{exten}[\|k])$;\2\6 +\&{for} $\|k\K1\mathrel{\&{to}}\\{np}$ \1\&{do}\6 +\&{if} $\|k=1$ \1\&{then}\6 +\&{if} $\\{abs}(\\{param}[1])<\\{fraction\_half}$ \1\&{then}\5 +$\\{tfm\_four}(\\{param}[1]\ast16)$\6 +\4\&{else} \&{begin} \37$\\{incr}(\\{tfm\_changed})$;\6 +\&{if} $\\{param}[1]>0$ \1\&{then}\5 +$\\{tfm\_four}(\\{el\_gordo})$\6 +\4\&{else} $\\{tfm\_four}(-\\{el\_gordo})$;\2\6 +\&{end}\2\6 +\4\&{else} $\\{tfm\_four}(\\{dimen\_out}(\\{param}[\|k]))$;\2\2\6 +\&{if} $\\{tfm\_changed}>0$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{tfm\_changed}=1$ \1\&{then}\5 +$\\{print\_nl}(\.{"(a\ font\ metric\ dimension"})$\6 +\4\&{else} \&{begin} \37$\\{print\_nl}(\.{"("})$;\5 +$\\{print\_int}(\\{tfm\_changed})$;\5 +$\\{print}(\.{"\ font\ metric\ dimensions"})$;\6 +\&{end};\2\6 +$\\{print}(\.{"\ had\ to\ be\ decreased)"})$;\6 +\&{end}\2\par +\U1134.\fi + +\M1141. \P$\X1141:Log the subfile sizes of the \.{TFM} file\X\S$\6 +\&{begin} \37$\\{wlog\_ln}(\.{\'\ \'})$;\6 +\&{if} $\\{bch\_label}<\\{undefined\_label}$ \1\&{then}\5 +$\\{decr}(\\{nl})$;\2\6 +$\\{wlog\_ln}(\.{\'(You\ used\ \'},\39\\{nw}:1,\39\.{\'w,\'},\39\30\\{nh}:1,\39% +\.{\'h,\'},\39\30\\{nd}:1,\39\.{\'d,\'},\39\30\\{ni}:1,\39\.{\'i,\'},\39\30% +\\{nl}:1,\39\.{\'l,\'},\39\30\\{nk}:1,\39\.{\'k,\'},\39\30\\{ne}:1,\39\.{\'e,% +\'},\39\30\\{np}:1,\39\.{\'p\ metric\ file\ positions\'})$;\5 +$\\{wlog\_ln}(\.{\'\ \ out\ of\ \'},\39\30\.{\'256w,16h,16d,64i,\'},\39\30% +\\{lig\_table\_size}:1,\39\.{\'l,\'},\39\\{max\_kerns}:1,\39\.{\'k,256e,\'},\39% +\30\\{max\_font\_dimen}:1,\39\.{\'p)\'})$;\6 +\&{end}\par +\U1134.\fi + +\N1142. \[46] Generic font file format. +The most important output produced by a typical run of \MF\ is the +``generic font'' (\.{GF}) file that specifies the bit patterns of the +characters that have been drawn. The term {\sl generic\/} indicates that +this file format doesn't match the conventions of any name-brand manufacturer; +but it is easy to convert \.{GF} files to the special format required by +almost all digital phototypesetting equipment. There's a strong analogy +between the \.{DVI} files written by \TeX\ and the \.{GF} files written +by \MF; and, in fact, the file formats have a lot in common. + +A \.{GF} file is a stream of 8-bit bytes that 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 +`\\{boc}' (beginning of character) command has six parameters, each of +which is four bytes long. Parameters are usually regarded as nonnegative +integers; but four-byte-long parameters can be either positive or +negative, hence they range in value from $-2^{31}$ to $2^{31}-1$. +As in \.{TFM} files, numbers that occupy +more than one byte position appear in BigEndian order, +and negative numbers appear in two's complement notation. + +A \.{GF} file consists of a ``preamble,'' followed by a sequence of one or +more ``characters,'' followed by a ``postamble.'' The preamble is simply a +\\{pre} command, with its parameters that introduce the file; this must come +first. Each ``character'' consists of a \\{boc} command, followed by any +number of other commands that specify ``black'' pixels, +followed by an \\{eoc} command. The characters appear in the order that \MF\ +generated them. If we ignore no-op commands (which are allowed between any +two commands in the file), each \\{eoc} command is immediately followed by a +\\{boc} command, or by a \\{post} command; in the latter case, there are no +more characters in the file, and the remaining bytes form the postamble. +Further details about the postamble will be explained later. + +Some parameters in \.{GF} commands are ``pointers.'' These are four-byte +quantities that give the location number of some other byte in the file; +the first file byte is number~0, then comes number~1, and so on. + +\fi + +\M1143. The \.{GF} format is intended to be both compact and easily interpreted +by a machine. Compactness is achieved by making most of the information +relative instead of absolute. When a \.{GF}-reading program reads the +commands for a character, it keeps track of two quantities: (a)~the current +column number,~\|m; and (b)~the current row number,~\|n. These are 32-bit +signed integers, although most actual font formats produced from \.{GF} +files will need to curtail this vast range because of practical +limitations. (\MF\ output will never allow $\vert m\vert$ or $\vert +n\vert$ to get extremely large, but the \.{GF} format tries to be more +general.) + +How do \.{GF}'s row and column numbers correspond to the conventions +of \TeX\ and \MF? Well, the ``reference point'' of a character, in \TeX's +view, is considered to be at the lower left corner of the pixel in row~0 +and column~0. This point is the intersection of the baseline with the left +edge of the type; it corresponds to location $(0,0)$ in \MF\ programs. +Thus the pixel in \.{GF} row~0 and column~0 is \MF's unit square, comprising +the +region of the plane whose coordinates both lie between 0 and~1. The +pixel in \.{GF} row~\|n and column~\|m consists of the points whose \MF\ +coordinates $(\|x,\|y)$ satisfy $\|m\L\|x\L\|m+1$ and $\|n\L\|y\L\|n+1$. +Negative values of +\|m and~\|x correspond to columns of pixels {\sl left\/} of the reference +point; negative values of \|n and~\|y correspond to rows of pixels {\sl +below\/} the baseline. + +Besides \|m and \|n, there's also a third aspect of the current +state, namely the \\{paint\_switch}, which is always either \\{black} or +\\{white}. Each \\{paint} command advances \|m by a specified amount~\|d, +and blackens the intervening pixels if $\\{paint\_switch}=\\{black}$; then +the \\{paint\_switch} changes to the opposite state. \.{GF}'s commands are +designed so that \|m will never decrease within a row, and \|n will never +increase within a character; hence there is no way to whiten a pixel that +has been blackened. + +\fi + +\M1144. Here is a list of all the commands that may appear in a \.{GF} file. +Each +command is specified by its symbolic name (e.g., \\{boc}), its opcode byte +(e.g., 67), and its parameters (if any). The parameters are followed +by a bracketed number telling how many bytes they occupy; for example, +`$\|d[2]$' means that parameter \|d is two bytes long. + +\yskip\hang\\{paint\_0} 0. This is a \\{paint} command with $\|d=0$; it does +nothing but change the \\{paint\_switch} from \\{black} to \\{white} or +vice~versa. + +\yskip\hang\\{paint\_1} through \\{paint\_63} (opcodes 1 to 63). +These are \\{paint} commands with $\|d=1$ to~63, defined as follows: If +$\\{paint\_switch}=\\{black}$, blacken \|d~pixels of the current row~\|n, +in columns \|m through $\|m+\|d-1$ inclusive. Then, in any case, +complement the \\{paint\_switch} and advance \|m by~\|d. + +\yskip\hang\\{paint1} 64 $\|d[1]$. This is a \\{paint} command with a specified +value of~\|d; \MF\ uses it to paint when $64\L\|d<256$. + +\yskip\hang\\{paint2} 65 $\|d[2]$. Same as \\{paint1}, but \|d~can be as high +as~65535. + +\yskip\hang\\{paint3} 66 $\|d[3]$. Same as \\{paint1}, but \|d~can be as high +as $2^{24}-1$. \MF\ never needs this command, and it is hard to imagine +anybody making practical use of it; surely a more compact encoding will be +desirable when characters can be this large. But the command is there, +anyway, just in case. + +\yskip\hang\\{boc} 67 $\|c[4]$ $\|p[4]$ $\\{min\_m}[4]$ $\\{max\_m}[4]$ $\\{min% +\_n}[4]$ +$\\{max\_n}[4]$. Beginning of a character: Here \|c is the character code, and +\|p points to the previous character beginning (if any) for characters having +this code number modulo 256. (The pointer \|p is $-1$ if there was no +prior character with an equivalent code.) The values of registers \|m and \|n +defined by the instructions that follow for this character must +satisfy $\\{min\_m}\L\|m\L\\{max\_m}$ and $\\{min\_n}\L\|n\L\\{max\_n}$. (The +values of \\{max\_m} and +\\{min\_n} need not be the tightest bounds possible.) When a \.{GF}-reading +program sees a \\{boc}, it can use \\{min\_m}, \\{max\_m}, \\{min\_n}, and % +\\{max\_n} to +initialize the bounds of an array. Then it sets $\|m\K\\{min\_m}$, $\|n\K\\{max% +\_n}$, and +$\\{paint\_switch}\K\\{white}$. + +\yskip\hang\\{boc1} 68 $\|c[1]$ $\\{del\_m}[1]$ $\\{max\_m}[1]$ $\\{del\_n}[1]$ +$\\{max\_n}[1]$. +Same as \\{boc}, but \|p is assumed to be~$-1$; also $\\{del\_m}=\\{max\_m}-% +\\{min\_m}$ +and $\\{del\_n}=\\{max\_n}-\\{min\_n}$ are given instead of \\{min\_m} and % +\\{min\_n}. +The one-byte parameters must be between 0 and 255, inclusive. +\ (This abbreviated \\{boc} saves 19~bytes per character, in common cases.) + +\yskip\hang\\{eoc} 69. End of character: All pixels blackened so far +constitute the pattern for this character. In particular, a completely +blank character might have \\{eoc} immediately following \\{boc}. + +\yskip\hang\\{skip0} 70. Decrease \|n by 1 and set $\|m\K\\{min\_m}$, +$\\{paint\_switch}\K\\{white}$. \ (This finishes one row and begins another, +ready to whiten the leftmost pixel in the new row.) + +\yskip\hang\\{skip1} 71 $\|d[1]$. Decrease \|n by $\|d+1$, set $\|m\K\\{min% +\_m}$, and set +$\\{paint\_switch}\K\\{white}$. This is a way to produce \|d all-white rows. + +\yskip\hang\\{skip2} 72 $\|d[2]$. Same as \\{skip1}, but \|d can be as large +as 65535. + +\yskip\hang\\{skip3} 73 $\|d[3]$. Same as \\{skip1}, but \|d can be as large +as $2^{24}-1$. \MF\ obviously never needs this command. + +\yskip\hang\\{new\_row\_0} 74. Decrease \|n by 1 and set $\|m\K\\{min\_m}$, +$\\{paint\_switch}\K\\{black}$. \ (This finishes one row and begins another, +ready to {\sl blacken\/} the leftmost pixel in the new row.) + +\yskip\hang\\{new\_row\_1} through \\{new\_row\_164} (opcodes 75 to 238). Same +as +\\{new\_row\_0}, but with $\|m\K\\{min\_m}+1$ through $\\{min\_m}+164$, +respectively. + +\yskip\hang\\{xxx1} 239 $\|k[1]$ $\|x[\|k]$. This command is undefined in +general; it functions as a $(k+2)$-byte \\{no\_op} unless special % +\.{GF}-reading +programs are being used. \MF\ generates \\{xxx} commands when encountering +a \&{special} string; this occurs in the \.{GF} file only between +characters, after the preamble, and before the postamble. However, +\\{xxx} commands might appear within characters, +in \.{GF} files generated by other +processors. It is recommended that \|x be a string having the form of a +keyword followed by possible parameters relevant to that keyword. + +\yskip\hang\\{xxx2} 240 $\|k[2]$ $\|x[\|k]$. Like \\{xxx1}, but $0\L\|k<65536$. + +\yskip\hang\\{xxx3} 241 $\|k[3]$ $\|x[\|k]$. Like \\{xxx1}, but $0\L\|k<% +\hbox{$2^{24}$}$. +\MF\ uses this when sending a \&{special} string whose length exceeds~255. + +\yskip\hang\\{xxx4} 242 $\|k[4]$ $\|x[\|k]$. Like \\{xxx1}, but \|k can be +ridiculously large; \|k mustn't be negative. + +\yskip\hang\\{yyy} 243 $\|y[4]$. This command is undefined in general; +it functions as a 5-byte \\{no\_op} unless special \.{GF}-reading programs +are being used. \MF\ puts \\{scaled} numbers into \\{yyy}'s, as a +result of \&{numspecial} commands; the intent is to provide numeric +parameters to \\{xxx} commands that immediately precede. + +\yskip\hang\\{no\_op} 244. No operation, do nothing. Any number of \\{no\_op}'s +may occur between \.{GF} commands, but a \\{no\_op} cannot be inserted between +a command and its parameters or between two parameters. + +\yskip\hang\\{char\_loc} 245 $\|c[1]$ $\\{dx}[4]$ $\\{dy}[4]$ $\|w[4]$ $% +\|p[4]$. +This command will appear only in the postamble, which will be explained +shortly. + +\yskip\hang\\{char\_loc0} 246 $\|c[1]$ $\\{dm}[1]$ $\|w[4]$ $\|p[4]$. +Same as \\{char\_loc}, except that \\{dy} is assumed to be zero, and the value +of~\\{dx} is taken to be $65536\ast\\{dm}$, where $0\L\\{dm}<256$. + +\yskip\hang\\{pre} 247 $\|i[1]$ $\|k[1]$ $\|x[\|k]$. +Beginning of the preamble; this must come at the very beginning of the +file. Parameter \|i is an identifying number for \.{GF} format, currently +131. The other information is merely commentary; it is not given +special interpretation like \\{xxx} commands are. (Note that \\{xxx} +commands may immediately follow the preamble, before the first \\{boc}.) + +\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. + +\Y\P\D \37$\\{gf\_id\_byte}=131$\C{identifies the kind of \.{GF} files +described here}\par +\fi + +\M1145. \MF\ refers to the following opcodes explicitly. + +\Y\P\D \37$\\{paint\_0}=0$\C{beginning of the \\{paint} commands}\par +\P\D \37$\\{paint1}=64$\C{move right a given number of columns, then black${}% +\swap{}$white}\par +\P\D \37$\\{boc}=67$\C{beginning of a character}\par +\P\D \37$\\{boc1}=68$\C{short form of \\{boc}}\par +\P\D \37$\\{eoc}=69$\C{end of a character}\par +\P\D \37$\\{skip0}=70$\C{skip no blank rows}\par +\P\D \37$\\{skip1}=71$\C{skip over blank rows}\par +\P\D \37$\\{new\_row\_0}=74$\C{move down one row and then right}\par +\P\D \37$\\{max\_new\_row}=164$\C{the largest \\{new\_row} command is \\{new% +\_row\_164}}\par +\P\D \37$\\{xxx1}=239$\C{for \&{special} strings}\par +\P\D \37$\\{xxx3}=241$\C{for long \&{special} strings}\par +\P\D \37$\\{yyy}=243$\C{for \&{numspecial} numbers}\par +\P\D \37$\\{char\_loc}=245$\C{character locators in the postamble}\par +\P\D \37$\\{pre}=247$\C{preamble}\par +\P\D \37$\\{post}=248$\C{postamble beginning}\par +\P\D \37$\\{post\_post}=249$\C{postamble ending}\par +\fi + +\M1146. The last character in a \.{GF} file is followed by `\\{post}'; this +command +introduces the postamble, which summarizes important facts that \MF\ has +accumulated. The postamble has the form +$$\vbox{\halign{\hbox{#\hfil}\cr +\\{post} $\|p[4]$ $\\{ds}[4]$ $\\{cs}[4]$ $\\{hppp}[4]$ $\\{vppp}[4]$ +$\\{min\_m}[4]$ $\\{max\_m}[4]$ $\\{min\_n}[4]$ $\\{max\_n}[4]$\cr +$\langle\,$character locators$\,\rangle$\cr +\\{post\_post} $\|q[4]$ $\|i[1]$ 223's$[{\G}4]$\cr}}$$ +Here \|p is a pointer to the byte following the final \\{eoc} in the file +(or to the byte following the preamble, if there are no characters); +it can be used to locate the beginning of \\{xxx} commands +that might have preceded the postamble. The \\{ds} and \\{cs} parameters +give the design size and check sum, respectively, which are exactly the +values put into the header of the \.{TFM} file that \MF\ produces (or +would produce) on this run. Parameters \\{hppp} and \\{vppp} are the ratios of +pixels per point, horizontally and vertically, expressed as \\{scaled} integers +(i.e., multiplied by $2^{16}$); they can be used to correlate the font +with specific device resolutions, magnifications, and ``at sizes.'' Then +come \\{min\_m}, \\{max\_m}, \\{min\_n}, and \\{max\_n}, which bound the values +that +registers \|m and~\|n assume in all characters in this \.{GF} file. +(These bounds need not be the best possible; \\{max\_m} and \\{min\_n} may, on +the +other hand, be tighter than the similar bounds in \\{boc} commands. For +example, some character may have $\\{min\_n}=-100$ in its \\{boc}, but it might +turn out that \|n never gets lower than $-50$ in any character; then +\\{min\_n} can have any value $\L-50$. If there are no characters in the file, +it's possible to have $\\{min\_m}>\\{max\_m}$ and/or $\\{min\_n}>\\{max\_n}$.) + +\fi + +\M1147. Character locators are introduced by \\{char\_loc} commands, +which specify a character residue~\|c, character escapements ($\\{dx},\\{dy}$), +a character width~\|w, and a pointer~\|p +to the beginning of that character. (If two or more characters have the +same code~\|c modulo 256, only the last will be indicated; the others can be +located by following backpointers. Characters whose codes differ by a +multiple of 256 are assumed to share the same font metric information, +hence the \.{TFM} file contains only residues of character codes modulo~256. +This convention is intended for oriental languages, when there are many +character shapes but few distinct widths.) + +The character escapements ($\\{dx},\\{dy}$) are the values of \MF's \&{chardx} +and \&{chardy} parameters; they are in units of \\{scaled} pixels; +i.e., \\{dx} is in horizontal pixel units times $2^{16}$, and \\{dy} is in +vertical pixel units times $2^{16}$. This is the intended amount of +displacement after typesetting the character; for \.{DVI} files, \\{dy} +should be zero, but other document file formats allow nonzero vertical +escapement. + +The character width~\|w duplicates the information in the \.{TFM} file; it +is a \\{fix\_word} value relative to the design size, and it should be +independent of magnification. + +The backpointer \|p points to the character's \\{boc}, or to the first of +a sequence of consecutive \\{xxx} or \\{yyy} or \\{no\_op} commands that +immediately precede the \\{boc}, if such commands exist; such ``special'' +commands essentially belong to the characters, while the special commands +after the final character belong to the postamble (i.e., to the font +as a whole). This convention about \|p applies also to the backpointers +in \\{boc} commands, even though it wasn't explained in the description +of~\\{boc}. + +Pointer \|p might be $-1$ if the character exists in the \.{TFM} file +but not in the \.{GF} file. This unusual situation can arise in \MF\ output +if the user had $\\{proofing}<0$ when the character was being shipped out, +but then made $\\{proofing}\G0$ in order to get a \.{GF} file. + +\fi + +\M1148. The last part of the postamble, following the \\{post\_post} byte that +signifies the end of the character locators, contains \|q, a pointer to the +\\{post} command that started the postamble. An identification byte, \|i, +comes next; this currently equals~131, 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., \O{337} in octal). \MF\ 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 \.{GF} file makes it feasible for +\.{GF}-reading programs to find the postamble first, on most computers, +even though \MF\ wants to write the postamble last. Most operating +systems permit random access to individual words or bytes of a file, so +the \.{GF} 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 +\.{GF} reader can discover all the information needed for individual +characters. + +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 \.{GF} +format has been designed to work most efficiently with modern operating +systems. +But if \.{GF} files have to be processed under the restrictions of standard +\PASCAL, one can simply read them from front to back. This will +be adequate for most applications. However, the postamble-first approach +would facilitate a program that merges two \.{GF} files, replacing data +from one that is overridden by corresponding data in the other. + +\fi + +\N1149. \[47] Shipping characters out. +The \\{ship\_out} procedure, to be described below, is given a pointer to +an edge structure. Its mission is to describe the the positive pixels +in \.{GF} form, outputting a ``character'' to \\{gf\_file}. + +Several global variables hold information about the font file as a whole:\ +\\{gf\_min\_m}, \\{gf\_max\_m}, \\{gf\_min\_n}, and \\{gf\_max\_n} are the +minimum and +maximum \.{GF} coordinates output so far; \\{gf\_prev\_ptr} is the byte number +following the preamble or the last \\{eoc} command in the output; +\\{total\_chars} is the total number of characters (i.e., $\\{boc}\to\\{eoc}$ +segments) +shipped out. There's also an array, \\{char\_ptr}, containing the starting +positions of each character in the file, as required for the postamble. If +character code~\|c has not yet been output, $\\{char\_ptr}[\|c]=-1$. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4$\\{gf\_min\_m},\39\\{gf\_max\_m},\39\\{gf\_min\_n},\39\\{gf\_max\_n}$: \37% +\\{integer};\C{bounding rectangle}\6 +\4\\{gf\_prev\_ptr}: \37\\{integer};\C{where the present/next character +started/starts}\6 +\4\\{total\_chars}: \37\\{integer};\C{the number of characters output so far}\6 +\4\\{char\_ptr}: \37\&{array} $[\\{eight\_bits}]$ \1\&{of}\5 +\\{integer};\C{where individual characters started}\2\6 +\4$\\{gf\_dx},\39\\{gf\_dy}$: \37\&{array} $[\\{eight\_bits}]$ \1\&{of}\5 +\\{integer};\C{device escapements}\2\par +\fi + +\M1150. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{gf\_prev\_ptr}\K0$;\5 +$\\{total\_chars}\K0$;\par +\fi + +\M1151. The \.{GF} bytes are output to a buffer instead of being sent +byte-by-byte to \\{gf\_file}, because this tends to save a lot of +subroutine-call overhead. \MF\ uses the same conventions for \\{gf\_file} +as \TeX\ uses for its \\{dvi\_file}; hence if system-dependent +changes are needed, they should probably be the same for both programs. + +The output buffer is divided into two parts of equal size; the bytes found +in $\\{gf\_buf}[0\to\\{half\_buf}-1]$ constitute the first half, and those in +$\\{gf\_buf}[\\{half\_buf}\to\\{gf\_buf\_size}-1]$ constitute the second. The +global +variable \\{gf\_ptr} points to the position that will receive the next +output byte. When \\{gf\_ptr} reaches \\{gf\_limit}, which is always equal +to one of the two values \\{half\_buf} or \\{gf\_buf\_size}, the half buffer +that +is about to be invaded next is sent to the output and \\{gf\_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 \.{GF} file are numbered sequentially starting with 0; +the next byte to be generated will be number $\\{gf\_offset}+\\{gf\_ptr}$. + +\Y\P$\4\X18:Types in the outer block\X\mathrel{+}\S$\6 +$\\{gf\_index}=0\to\\{gf\_buf\_size}$;\C{an index into the output buffer}\par +\fi + +\M1152. Some systems may find it more efficient to make \\{gf\_buf} a % +\&{packed} +array, since output of four bytes at once may be facilitated. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{gf\_buf}: \37\&{array} $[\\{gf\_index}]$ \1\&{of}\5 +\\{eight\_bits};\C{buffer for \.{GF} output}\2\6 +\4\\{half\_buf}: \37\\{gf\_index};\C{half of \\{gf\_buf\_size}}\6 +\4\\{gf\_limit}: \37\\{gf\_index};\C{end of the current half buffer}\6 +\4\\{gf\_ptr}: \37\\{gf\_index};\C{the next available buffer address}\6 +\4\\{gf\_offset}: \37\\{integer};\C{\\{gf\_buf\_size} times the number of times +the output buffer has been fully emptied}\par +\fi + +\M1153. Initially the buffer is all in one piece; we will output half of it +only +after it first fills up. + +\Y\P$\4\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{half\_buf}\K\\{gf\_buf\_size}\mathbin{\&{div}}2$;\5 +$\\{gf\_limit}\K\\{gf\_buf\_size}$;\5 +$\\{gf\_ptr}\K0$;\5 +$\\{gf\_offset}\K0$;\par +\fi + +\M1154. The actual output of $\\{gf\_buf}[\|a\to\|b]$ to \\{gf\_file} is +performed by calling +$\\{write\_gf}(\|a,\|b)$. It is safe to assume that \|a and $\|b+1$ will both +be +multiples of 4 when $\\{write\_gf}(\|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\P$\4\X1154:Declare generic font output procedures\X\S$\6 +\4\&{procedure}\1\ \37$\\{write\_gf}(\|a,\39\|b:\\{gf\_index})$;\6 +\4\&{var} \37\|k: \37\\{gf\_index};\2\6 +\&{begin} \37\&{for} $\|k\K\|a\mathrel{\&{to}}\|b$ \1\&{do}\5 +$\\{write}(\\{gf\_file},\39\\{gf\_buf}[\|k])$;\2\6 +\&{end};\par +\As1155, 1157, 1158, 1159, 1160, 1161, 1163\ETs1165. +\U989.\fi + +\M1155. To put a byte in the buffer without paying the cost of invoking a +procedure +each time, we use the macro \\{gf\_out}. + +\Y\P\D \37$\\{gf\_out}(\#)\S$\ \&{begin} \37$\\{gf\_buf}[\\{gf\_ptr}]\K\#$;\5 +$\\{incr}(\\{gf\_ptr})$;\6 +\&{if} $\\{gf\_ptr}=\\{gf\_limit}$ \1\&{then}\5 +\\{gf\_swap};\2\6 +\&{end}\par +\Y\P$\4\X1154:Declare generic font output procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{gf\_swap};\C{outputs half of the buffer}\2\6 +\&{begin} \37\&{if} $\\{gf\_limit}=\\{gf\_buf\_size}$ \1\&{then}\6 +\&{begin} \37$\\{write\_gf}(0,\39\\{half\_buf}-1)$;\5 +$\\{gf\_limit}\K\\{half\_buf}$;\5 +$\\{gf\_offset}\K\\{gf\_offset}+\\{gf\_buf\_size}$;\5 +$\\{gf\_ptr}\K0$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{write\_gf}(\\{half\_buf},\39\\{gf\_buf\_size}-1)$;\5 +$\\{gf\_limit}\K\\{gf\_buf\_size}$;\6 +\&{end};\2\6 +\&{end};\par +\fi + +\M1156. Here is how we clean out the buffer when \MF\ is all through; \\{gf% +\_ptr} +will be a multiple of~4. + +\Y\P$\4\X1156:Empty the last bytes out of \\{gf\_buf}\X\S$\6 +\&{if} $\\{gf\_limit}=\\{half\_buf}$ \1\&{then}\5 +$\\{write\_gf}(\\{half\_buf},\39\\{gf\_buf\_size}-1)$;\2\6 +\&{if} $\\{gf\_ptr}>0$ \1\&{then}\5 +$\\{write\_gf}(0,\39\\{gf\_ptr}-1)$\2\par +\U1182.\fi + +\M1157. The \\{gf\_four} procedure outputs four bytes in two's complement +notation, +without risking arithmetic overflow. + +\Y\P$\4\X1154:Declare generic font output procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{gf\_four}(\|x:\\{integer})$;\2\6 +\&{begin} \37\&{if} $\|x\G0$ \1\&{then}\5 +$\\{gf\_out}(\|x\mathbin{\&{div}}\\{three\_bytes})$\6 +\4\&{else} \&{begin} \37$\|x\K\|x+\O{10000000000}$;\5 +$\|x\K\|x+\O{10000000000}$;\5 +$\\{gf\_out}((\|x\mathbin{\&{div}}\\{three\_bytes})+128)$;\6 +\&{end};\2\6 +$\|x\K\|x\mathbin{\&{mod}}\\{three\_bytes}$;\5 +$\\{gf\_out}(\|x\mathbin{\&{div}}\\{unity})$;\5 +$\|x\K\|x\mathbin{\&{mod}}\\{unity}$;\5 +$\\{gf\_out}(\|x\mathbin{\&{div}}\O{400})$;\5 +$\\{gf\_out}(\|x\mathbin{\&{mod}}\O{400})$;\6 +\&{end};\par +\fi + +\M1158. Of course, it's even easier to output just two or three bytes. + +\Y\P$\4\X1154:Declare generic font output procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{gf\_two}(\|x:\\{integer})$;\2\6 +\&{begin} \37$\\{gf\_out}(\|x\mathbin{\&{div}}\O{400})$;\5 +$\\{gf\_out}(\|x\mathbin{\&{mod}}\O{400})$;\6 +\&{end};\7 +\4\&{procedure}\1\ \37$\\{gf\_three}(\|x:\\{integer})$;\2\6 +\&{begin} \37$\\{gf\_out}(\|x\mathbin{\&{div}}\\{unity})$;\5 +$\\{gf\_out}((\|x\mathbin{\&{mod}}\\{unity})\mathbin{\&{div}}\O{400})$;\5 +$\\{gf\_out}(\|x\mathbin{\&{mod}}\O{400})$;\6 +\&{end};\par +\fi + +\M1159. We need a simple routine to generate a \\{paint} +command of the appropriate type. + +\Y\P$\4\X1154:Declare generic font output procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{gf\_paint}(\|d:\\{integer})$;\C{here $0\L\|d<65536$}% +\2\6 +\&{begin} \37\&{if} $\|d<64$ \1\&{then}\5 +$\\{gf\_out}(\\{paint\_0}+\|d)$\6 +\4\&{else} \&{if} $\|d<256$ \1\&{then}\6 +\&{begin} \37$\\{gf\_out}(\\{paint1})$;\5 +$\\{gf\_out}(\|d)$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{gf\_out}(\\{paint1}+1)$;\5 +$\\{gf\_two}(\|d)$;\6 +\&{end};\2\2\6 +\&{end};\par +\fi + +\M1160. And \\{gf\_string} outputs one or two strings. If the first string +number +is nonzero, an \\{xxx} command is generated. + +\Y\P$\4\X1154:Declare generic font output procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{gf\_string}(\|s,\39\|t:\\{str\_number})$;\6 +\4\&{var} \37\|k: \37\\{pool\_pointer};\5 +\|l: \37\\{integer};\C{length of the strings to output}\2\6 +\&{begin} \37\&{if} $\|s\I0$ \1\&{then}\6 +\&{begin} \37$\|l\K\\{length}(\|s)$;\6 +\&{if} $\|t\I0$ \1\&{then}\5 +$\|l\K\|l+\\{length}(\|t)$;\2\6 +\&{if} $\|l\L255$ \1\&{then}\6 +\&{begin} \37$\\{gf\_out}(\\{xxx1})$;\5 +$\\{gf\_out}(\|l)$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{gf\_out}(\\{xxx3})$;\5 +$\\{gf\_three}(\|l)$;\6 +\&{end};\2\6 +\&{for} $\|k\K\\{str\_start}[\|s]\mathrel{\&{to}}\\{str\_start}[\|s+1]-1$ \1% +\&{do}\5 +$\\{gf\_out}(\\{so}(\\{str\_pool}[\|k]))$;\2\6 +\&{end};\2\6 +\&{if} $\|t\I0$ \1\&{then}\6 +\&{for} $\|k\K\\{str\_start}[\|t]\mathrel{\&{to}}\\{str\_start}[\|t+1]-1$ \1% +\&{do}\5 +$\\{gf\_out}(\\{so}(\\{str\_pool}[\|k]))$;\2\2\6 +\&{end};\par +\fi + +\M1161. The choice between \\{boc} commands is handled by \\{gf\_boc}. + +\Y\P\D $\\{one\_byte}(\#)\S\#\G0$ \&{then} \6 +\&{if} $\#<256$\par +\Y\P$\4\X1154:Declare generic font output procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{gf\_boc}(\\{min\_m},\39\\{max\_m},\39\\{min\_n},\39% +\\{max\_n}:\\{integer})$;\6 +\4\&{label} \37\\{exit};\2\6 +\&{begin} \37\&{if} $\\{min\_m}<\\{gf\_min\_m}$ \1\&{then}\5 +$\\{gf\_min\_m}\K\\{min\_m}$;\2\6 +\&{if} $\\{max\_n}>\\{gf\_max\_n}$ \1\&{then}\5 +$\\{gf\_max\_n}\K\\{max\_n}$;\2\6 +\&{if} $\\{boc\_p}=-1$ \1\&{then}\6 +\&{if} $\\{one\_byte}(\\{boc\_c})$ \1\&{then}\6 +\&{if} $\\{one\_byte}(\\{max\_m}-\\{min\_m})$ \1\&{then}\6 +\&{if} $\\{one\_byte}(\\{max\_m})$ \1\&{then}\6 +\&{if} $\\{one\_byte}(\\{max\_n}-\\{min\_n})$ \1\&{then}\6 +\&{if} $\\{one\_byte}(\\{max\_n})$ \1\&{then}\6 +\&{begin} \37$\\{gf\_out}(\\{boc1})$;\5 +$\\{gf\_out}(\\{boc\_c})$;\6 +$\\{gf\_out}(\\{max\_m}-\\{min\_m})$;\5 +$\\{gf\_out}(\\{max\_m})$;\5 +$\\{gf\_out}(\\{max\_n}-\\{min\_n})$;\5 +$\\{gf\_out}(\\{max\_n})$;\5 +\&{return};\6 +\&{end};\2\2\2\2\2\2\6 +$\\{gf\_out}(\\{boc})$;\5 +$\\{gf\_four}(\\{boc\_c})$;\5 +$\\{gf\_four}(\\{boc\_p})$;\6 +$\\{gf\_four}(\\{min\_m})$;\5 +$\\{gf\_four}(\\{max\_m})$;\5 +$\\{gf\_four}(\\{min\_n})$;\5 +$\\{gf\_four}(\\{max\_n})$;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M1162. Two of the parameters to \\{gf\_boc} are global. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4$\\{boc\_c},\39\\{boc\_p}$: \37\\{integer};\C{parameters of the next \\{boc} +command}\par +\fi + +\M1163. Here is a routine that gets a \.{GF} file off to a good start. + +\Y\P\D \37$\\{check\_gf}\S\hbox{}$\ \&{if} $\\{output\_file\_name}=0$ \1% +\&{then}\5 +\\{init\_gf}\2\par +\Y\P$\4\X1154:Declare generic font output procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{init\_gf};\6 +\4\&{var} \37\|k: \37\\{eight\_bits};\C{runs through all possible character +codes}\6 +\|t: \37\\{integer};\C{the time of this run}\2\6 +\&{begin} \37$\\{gf\_min\_m}\K4096$;\5 +$\\{gf\_max\_m}\K-4096$;\5 +$\\{gf\_min\_n}\K4096$;\5 +$\\{gf\_max\_n}\K-4096$;\6 +\&{for} $\|k\K0\mathrel{\&{to}}255$ \1\&{do}\5 +$\\{char\_ptr}[\|k]\K-1$;\2\6 +\X1164:Determine the file extension, \\{gf\_ext}\X;\6 +\\{set\_output\_file\_name};\5 +$\\{gf\_out}(\\{pre})$;\5 +$\\{gf\_out}(\\{gf\_id\_byte})$;\C{begin to output the preamble}\6 +$\\{old\_setting}\K\\{selector}$;\5 +$\\{selector}\K\\{new\_string}$;\5 +$\\{print}(\.{"\ METAFONT\ output\ "})$;\5 +$\\{print\_int}(\\{round\_unscaled}(\\{internal}[\\{year}]))$;\5 +$\\{print\_char}(\.{"."})$;\5 +$\\{print\_dd}(\\{round\_unscaled}(\\{internal}[\\{month}]))$;\5 +$\\{print\_char}(\.{"."})$;\5 +$\\{print\_dd}(\\{round\_unscaled}(\\{internal}[\\{day}]))$;\5 +$\\{print\_char}(\.{":"})$;\6 +$\|t\K\\{round\_unscaled}(\\{internal}[\\{time}])$;\5 +$\\{print\_dd}(\|t\mathbin{\&{div}}60)$;\5 +$\\{print\_dd}(\|t\mathbin{\&{mod}}60)$;\6 +$\\{selector}\K\\{old\_setting}$;\5 +$\\{gf\_out}(\\{cur\_length})$;\5 +$\\{str\_start}[\\{str\_ptr}+1]\K\\{pool\_ptr}$;\5 +$\\{gf\_string}(0,\39\\{str\_ptr})$;\5 +$\\{pool\_ptr}\K\\{str\_start}[\\{str\_ptr}]$;\C{flush that string from memory}% +\6 +$\\{gf\_prev\_ptr}\K\\{gf\_offset}+\\{gf\_ptr}$;\6 +\&{end};\par +\fi + +\M1164. \P$\X1164:Determine the file extension, \\{gf\_ext}\X\S$\6 +\&{if} $\\{internal}[\\{hppp}]\L0$ \1\&{then}\5 +$\\{gf\_ext}\K\.{".gf"}$\6 +\4\&{else} \&{begin} \37$\\{old\_setting}\K\\{selector}$;\5 +$\\{selector}\K\\{new\_string}$;\5 +$\\{print\_char}(\.{"."})$;\5 +$\\{print\_int}(\\{make\_scaled}(\\{internal}[\\{hppp}],\3959429463))$;% +\C{$2^{32}/72.27\approx59429463.07$}\6 +$\\{print}(\.{"gf"})$;\5 +$\\{gf\_ext}\K\\{make\_string}$;\5 +$\\{selector}\K\\{old\_setting}$;\6 +\&{end}\2\par +\U1163.\fi + +\M1165. With those preliminaries out of the way, \\{ship\_out} is not +especially +difficult. + +\Y\P$\4\X1154:Declare generic font output procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37$\\{ship\_out}(\|c:\\{eight\_bits})$;\6 +\4\&{label} \37\\{done};\6 +\4\&{var} \37\|f: \37\\{integer};\C{current character extension}\6 +$\\{prev\_m},\39\|m,\39\\{mm}$: \37\\{integer};\C{previous and current pixel +column numbers}\6 +$\\{prev\_n},\39\|n$: \37\\{integer};\C{previous and current pixel row numbers}% +\6 +$\|p,\39\|q$: \37\\{pointer};\C{for list traversal}\6 +$\\{prev\_w},\39\|w,\39\\{ww}$: \37\\{integer};\C{old and new weights}\6 +\|d: \37\\{integer};\C{data from edge-weight node}\6 +\\{delta}: \37\\{integer};\C{number of rows to skip}\6 +\\{cur\_min\_m}: \37\\{integer};\C{starting column, relative to the current +offset}\6 +$\\{x\_off},\39\\{y\_off}$: \37\\{integer};\C{offsets, rounded to integers}\2\6 +\&{begin} \37\\{check\_gf};\5 +$\|f\K\\{round\_unscaled}(\\{internal}[\\{char\_ext}])$;\6 +$\\{x\_off}\K\\{round\_unscaled}(\\{internal}[\\{x\_offset}])$;\5 +$\\{y\_off}\K\\{round\_unscaled}(\\{internal}[\\{y\_offset}])$;\6 +\&{if} $\\{term\_offset}>\\{max\_print\_line}-9$ \1\&{then}\5 +\\{print\_ln}\6 +\4\&{else} \&{if} $(\\{term\_offset}>0)\V(\\{file\_offset}>0)$ \1\&{then}\5 +$\\{print\_char}(\.{"\ "})$;\2\2\6 +$\\{print\_char}(\.{"["})$;\5 +$\\{print\_int}(\|c)$;\6 +\&{if} $\|f\I0$ \1\&{then}\6 +\&{begin} \37$\\{print\_char}(\.{"."})$;\5 +$\\{print\_int}(\|f)$;\6 +\&{end};\2\6 +\\{update\_terminal};\5 +$\\{boc\_c}\K256\ast\|f+\|c$;\5 +$\\{boc\_p}\K\\{char\_ptr}[\|c]$;\5 +$\\{char\_ptr}[\|c]\K\\{gf\_prev\_ptr}$;\6 +\&{if} $\\{internal}[\\{proofing}]>0$ \1\&{then}\5 +\X1166:Send nonzero offsets to the output file\X;\2\6 +\X1167:Output the character represented in \\{cur\_edges}\X;\6 +$\\{gf\_out}(\\{eoc})$;\5 +$\\{gf\_prev\_ptr}\K\\{gf\_offset}+\\{gf\_ptr}$;\5 +$\\{incr}(\\{total\_chars})$;\5 +$\\{print\_char}(\.{"]"})$;\5 +\\{update\_terminal};\C{progress report}\6 +\&{if} $\\{internal}[\\{tracing\_output}]>0$ \1\&{then}\5 +$\\{print\_edges}(\.{"\ (just\ shipped\ out)"},\39\\{true},\39\\{x\_off},\39% +\\{y\_off})$;\2\6 +\&{end};\par +\fi + +\M1166. \P$\X1166:Send nonzero offsets to the output file\X\S$\6 +\&{begin} \37\&{if} $\\{x\_off}\I0$ \1\&{then}\6 +\&{begin} \37$\\{gf\_string}(\.{"xoffset"},\390)$;\5 +$\\{gf\_out}(\\{yyy})$;\5 +$\\{gf\_four}(\\{x\_off}\ast\\{unity})$;\6 +\&{end};\2\6 +\&{if} $\\{y\_off}\I0$ \1\&{then}\6 +\&{begin} \37$\\{gf\_string}(\.{"yoffset"},\390)$;\5 +$\\{gf\_out}(\\{yyy})$;\5 +$\\{gf\_four}(\\{y\_off}\ast\\{unity})$;\6 +\&{end};\2\6 +\&{end}\par +\U1165.\fi + +\M1167. \P$\X1167:Output the character represented in \\{cur\_edges}\X\S$\6 +$\\{prev\_n}\K4096$;\5 +$\|p\K\\{knil}(\\{cur\_edges})$;\5 +$\|n\K\\{n\_max}(\\{cur\_edges})-\\{zero\_field}$;\6 +\&{while} $\|p\I\\{cur\_edges}$ \1\&{do}\6 +\&{begin} \37\X1169:Output the pixels of edge row \|p to font row \|n\X;\6 +$\|p\K\\{knil}(\|p)$;\5 +$\\{decr}(\|n)$;\6 +\&{end};\2\6 +\&{if} $\\{prev\_n}=4096$ \1\&{then}\5 +\X1168:Finish off an entirely blank character\X\6 +\4\&{else} \&{if} $\\{prev\_n}+\\{y\_off}<\\{gf\_min\_n}$ \1\&{then}\5 +$\\{gf\_min\_n}\K\\{prev\_n}+\\{y\_off}$\2\2\par +\U1165.\fi + +\M1168. \P$\X1168:Finish off an entirely blank character\X\S$\6 +\&{begin} \37$\\{gf\_boc}(0,\390,\390,\390)$;\6 +\&{if} $\\{gf\_max\_m}<0$ \1\&{then}\5 +$\\{gf\_max\_m}\K0$;\2\6 +\&{if} $\\{gf\_min\_n}>0$ \1\&{then}\5 +$\\{gf\_min\_n}\K0$;\2\6 +\&{end}\par +\U1167.\fi + +\M1169. In this loop, \\{prev\_w} represents the weight at column \\{prev\_m}, +which is +the most recent column reflected in the output so far; \|w represents the +weight at column~\|m, which is the most recent column in the edge data. +Several edges might cancel at the same column position, so we need to +look ahead to column~\\{mm} before actually outputting anything. + +\Y\P$\4\X1169:Output the pixels of edge row \|p to font row \|n\X\S$\6 +\&{if} $\\{unsorted}(\|p)>\\{void}$ \1\&{then}\5 +$\\{sort\_edges}(\|p)$;\2\6 +$\|q\K\\{sorted}(\|p)$;\5 +$\|w\K0$;\5 +$\\{prev\_m}\K-\\{fraction\_one}$;\C{$\\{fraction\_one}\approx\infty$}\6 +$\\{ww}\K0$;\5 +$\\{prev\_w}\K0$;\5 +$\|m\K\\{prev\_m}$;\6 +\1\&{repeat} \37\&{if} $\|q=\\{sentinel}$ \1\&{then}\5 +$\\{mm}\K\\{fraction\_one}$\6 +\4\&{else} \&{begin} \37$\|d\K\\{ho}(\\{info}(\|q))$;\5 +$\\{mm}\K\|d\mathbin{\&{div}}8$;\5 +$\\{ww}\K\\{ww}+(\|d\mathbin{\&{mod}}8)-\\{zero\_w}$;\6 +\&{end};\2\6 +\&{if} $\\{mm}\I\|m$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{prev\_w}\L0$ \1\&{then}\6 +\&{begin} \37\&{if} $\|w>0$ \1\&{then}\5 +\X1170:Start black at $(m,n)$\X;\2\6 +\&{end}\6 +\4\&{else} \&{if} $\|w\L0$ \1\&{then}\5 +\X1171:Stop black at $(m,n)$\X;\2\2\6 +$\|m\K\\{mm}$;\6 +\&{end};\2\6 +$\|w\K\\{ww}$;\5 +$\|q\K\\{link}(\|q)$;\6 +\4\&{until}\5 +$\\{mm}=\\{fraction\_one}$;\2\6 +\&{if} $\|w\I0$ \1\&{then}\C{this should be impossible}\6 +$\\{print\_nl}(\.{"(There\'s\ unbounded\ black\ in\ character\ shipped\ +out!)"})$;\2\6 +\&{if} $\\{prev\_m}-\\{m\_offset}(\\{cur\_edges})+\\{x\_off}>\\{gf\_max\_m}$ \1% +\&{then}\5 +$\\{gf\_max\_m}\K\\{prev\_m}-\\{m\_offset}(\\{cur\_edges})+\\{x\_off}$\2\par +\U1167.\fi + +\M1170. \P$\X1170:Start black at $(m,n)$\X\S$\6 +\&{begin} \37\&{if} $\\{prev\_m}=-\\{fraction\_one}$ \1\&{then}\5 +\X1172:Start a new row at $(m,n)$\X\6 +\4\&{else} $\\{gf\_paint}(\|m-\\{prev\_m})$;\2\6 +$\\{prev\_m}\K\|m$;\5 +$\\{prev\_w}\K\|w$;\6 +\&{end}\par +\U1169.\fi + +\M1171. \P$\X1171:Stop black at $(m,n)$\X\S$\6 +\&{begin} \37$\\{gf\_paint}(\|m-\\{prev\_m})$;\5 +$\\{prev\_m}\K\|m$;\5 +$\\{prev\_w}\K\|w$;\6 +\&{end}\par +\U1169.\fi + +\M1172. \P$\X1172:Start a new row at $(m,n)$\X\S$\6 +\&{begin} \37\&{if} $\\{prev\_n}=4096$ \1\&{then}\6 +\&{begin} \37$\\{gf\_boc}(\\{m\_min}(\\{cur\_edges})+\\{x\_off}-\\{zero% +\_field},\39\\{m\_max}(\\{cur\_edges})+\\{x\_off}-\\{zero\_field},\39\30\\{n% +\_min}(\\{cur\_edges})+\\{y\_off}-\\{zero\_field},\39\|n+\\{y\_off})$;\5 +$\\{cur\_min\_m}\K\\{m\_min}(\\{cur\_edges})-\\{zero\_field}+\\{m\_offset}(% +\\{cur\_edges})$;\6 +\&{end}\6 +\4\&{else} \&{if} $\\{prev\_n}>\|n+1$ \1\&{then}\5 +\X1174:Skip down $\\{prev\_n}-\|n$ rows\X\6 +\4\&{else} \X1173:Skip to column $m$ in the next row and \&{goto} \\{done}, or +skip zero rows\X;\2\2\6 +$\\{gf\_paint}(\|m-\\{cur\_min\_m})$;\C{skip to column $m$, painting white}\6 +\4\\{done}: \37$\\{prev\_n}\K\|n$;\6 +\&{end}\par +\U1170.\fi + +\M1173. \P$\X1173:Skip to column $m$ in the next row and \&{goto} \\{done}, or +skip zero rows\X\S$\6 +\&{begin} \37$\\{delta}\K\|m-\\{cur\_min\_m}$;\6 +\&{if} $\\{delta}>\\{max\_new\_row}$ \1\&{then}\5 +$\\{gf\_out}(\\{skip0})$\6 +\4\&{else} \&{begin} \37$\\{gf\_out}(\\{new\_row\_0}+\\{delta})$;\5 +\&{goto} \37\\{done};\6 +\&{end};\2\6 +\&{end}\par +\U1172.\fi + +\M1174. \P$\X1174:Skip down $\\{prev\_n}-\|n$ rows\X\S$\6 +\&{begin} \37$\\{delta}\K\\{prev\_n}-\|n-1$;\6 +\&{if} $\\{delta}<\O{400}$ \1\&{then}\6 +\&{begin} \37$\\{gf\_out}(\\{skip1})$;\5 +$\\{gf\_out}(\\{delta})$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{gf\_out}(\\{skip1}+1)$;\5 +$\\{gf\_two}(\\{delta})$;\6 +\&{end};\2\6 +\&{end}\par +\U1172.\fi + +\M1175. Now that we've finished \\{ship\_out}, let's look at the other commands +by which a user can send things to the \.{GF} file. + +\Y\P$\4\X1020:Cases of \\{do\_statement} that invoke particular commands\X% +\mathrel{+}\S$\6 +\4\\{special\_command}: \37\\{do\_special};\par +\fi + +\M1176. \P$\X192:Put each of \MF's primitives into the hash table\X\mathrel{+}% +\S$\6 +$\\{primitive}(\.{"special"},\39\\{special\_command},\39\\{string\_type})$;\6 +$\\{primitive}(\.{"numspecial"},\39\\{special\_command},\39\\{known})$;\par +\fi + +\M1177. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{do\_special};\6 +\4\&{var} \37\|m: \37\\{small\_number};\C{either \\{string\_type} or \\{known}}% +\2\6 +\&{begin} \37$\|m\K\\{cur\_mod}$;\5 +\\{get\_x\_next};\5 +\\{scan\_expression};\6 +\&{if} $\\{internal}[\\{proofing}]\G0$ \1\&{then}\6 +\&{if} $\\{cur\_type}\I\|m$ \1\&{then}\5 +\X1178:Complain about improper special operation\X\6 +\4\&{else} \&{begin} \37\\{check\_gf};\6 +\&{if} $\|m=\\{string\_type}$ \1\&{then}\5 +$\\{gf\_string}(\\{cur\_exp},\390)$\6 +\4\&{else} \&{begin} \37$\\{gf\_out}(\\{yyy})$;\5 +$\\{gf\_four}(\\{cur\_exp})$;\6 +\&{end};\2\6 +\&{end};\2\2\6 +$\\{flush\_cur\_exp}(0)$;\6 +\&{end};\par +\fi + +\M1178. \P$\X1178:Complain about improper special operation\X\S$\6 +\&{begin} \37$\\{exp\_err}(\.{"Unsuitable\ expression"})$;\5 +$\\{help1}(\.{"The\ expression\ shown\ above\ has\ the\ wrong\ type\ to\ be\ +output."})$;\5 +\\{put\_get\_error};\6 +\&{end}\par +\U1177.\fi + +\M1179. \P$\X1179:Send the current expression as a title to the output file\X% +\S$\6 +\&{begin} \37\\{check\_gf};\5 +$\\{gf\_string}(\.{"title\ "},\39\\{cur\_exp})$;\6 +\&{end}\par +\U994.\fi + +\M1180. \P$\X212:Cases of \\{print\_cmd\_mod} for symbolic printing of +primitives\X\mathrel{+}\S$\6 +\4\\{special\_command}: \37\&{if} $\|m=\\{known}$ \1\&{then}\5 +$\\{print}(\.{"numspecial"})$\6 +\4\&{else} $\\{print}(\.{"special"})$;\2\par +\fi + +\M1181. \P$\X1181:Determine if a character has been shipped out\X\S$\6 +\&{begin} \37$\\{cur\_exp}\K\\{round\_unscaled}(\\{cur\_exp})\mathbin{% +\&{mod}}256$;\6 +\&{if} $\\{cur\_exp}<0$ \1\&{then}\5 +$\\{cur\_exp}\K\\{cur\_exp}+256$;\2\6 +$\\{boolean\_reset}(\\{char\_exists}[\\{cur\_exp}])$;\5 +$\\{cur\_type}\K\\{boolean\_type}$;\6 +\&{end}\par +\U906.\fi + +\M1182. At the end of the program we must finish things off by writing the +postamble. +The \.{TFM} information should have been computed first. + +An integer variable \|k and a \\{scaled} variable \|x will be declared for +use by this routine. + +\Y\P$\4\X1182:Finish the \.{GF} file\X\S$\6 +\&{begin} \37$\\{gf\_out}(\\{post})$;\C{beginning of the postamble}\6 +$\\{gf\_four}(\\{gf\_prev\_ptr})$;\5 +$\\{gf\_prev\_ptr}\K\\{gf\_offset}+\\{gf\_ptr}-5$;\C{\\{post} location}\6 +$\\{gf\_four}(\\{internal}[\\{design\_size}]\ast16)$;\6 +\&{for} $\|k\K1\mathrel{\&{to}}4$ \1\&{do}\5 +$\\{gf\_out}(\\{header\_byte}[\|k])$;\C{the check sum}\2\6 +$\\{gf\_four}(\\{internal}[\\{hppp}])$;\5 +$\\{gf\_four}(\\{internal}[\\{vppp}])$;\6 +$\\{gf\_four}(\\{gf\_min\_m})$;\5 +$\\{gf\_four}(\\{gf\_max\_m})$;\5 +$\\{gf\_four}(\\{gf\_min\_n})$;\5 +$\\{gf\_four}(\\{gf\_max\_n})$;\6 +\&{for} $\|k\K0\mathrel{\&{to}}255$ \1\&{do}\6 +\&{if} $\\{char\_exists}[\|k]$ \1\&{then}\6 +\&{begin} \37$\|x\K\\{gf\_dx}[\|k]\mathbin{\&{div}}\\{unity}$;\6 +\&{if} $(\\{gf\_dy}[\|k]=0)\W(\|x\G0)\W(\|x<256)\W(\\{gf\_dx}[\|k]=\|x\ast% +\\{unity})$ \1\&{then}\6 +\&{begin} \37$\\{gf\_out}(\\{char\_loc}+1)$;\5 +$\\{gf\_out}(\|k)$;\5 +$\\{gf\_out}(\|x)$;\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{gf\_out}(\\{char\_loc})$;\5 +$\\{gf\_out}(\|k)$;\5 +$\\{gf\_four}(\\{gf\_dx}[\|k])$;\5 +$\\{gf\_four}(\\{gf\_dy}[\|k])$;\6 +\&{end};\2\6 +$\|x\K\\{value}(\\{tfm\_width}[\|k])$;\6 +\&{if} $\\{abs}(\|x)>\\{max\_tfm\_dimen}$ \1\&{then}\6 +\&{if} $\|x>0$ \1\&{then}\5 +$\|x\K\\{three\_bytes}-1$\ \&{else} $\|x\K1-\\{three\_bytes}$\2\6 +\4\&{else} $\|x\K\\{make\_scaled}(\|x\ast16,\39\\{internal}[\\{design% +\_size}])$;\2\6 +$\\{gf\_four}(\|x)$;\5 +$\\{gf\_four}(\\{char\_ptr}[\|k])$;\6 +\&{end};\2\2\6 +$\\{gf\_out}(\\{post\_post})$;\5 +$\\{gf\_four}(\\{gf\_prev\_ptr})$;\5 +$\\{gf\_out}(\\{gf\_id\_byte})$;\6 +$\|k\K4+((\\{gf\_buf\_size}-\\{gf\_ptr})\mathbin{\&{mod}}4)$;\C{the number of +223's}\6 +\&{while} $\|k>0$ \1\&{do}\6 +\&{begin} \37$\\{gf\_out}(223)$;\5 +$\\{decr}(\|k)$;\6 +\&{end};\2\6 +\X1156:Empty the last bytes out of \\{gf\_buf}\X;\6 +$\\{print\_nl}(\.{"Output\ written\ on\ "})$;\5 +$\\{slow\_print}(\\{output\_file\_name})$;\5 +$\\{print}(\.{"\ ("})$;\5 +$\\{print\_int}(\\{total\_chars})$;\5 +$\\{print}(\.{"\ character"})$;\6 +\&{if} $\\{total\_chars}\I1$ \1\&{then}\5 +$\\{print\_char}(\.{"s"})$;\2\6 +$\\{print}(\.{",\ "})$;\5 +$\\{print\_int}(\\{gf\_offset}+\\{gf\_ptr})$;\5 +$\\{print}(\.{"\ bytes)."})$;\5 +$\\{b\_close}(\\{gf\_file})$;\6 +\&{end}\par +\U1206.\fi + +\N1183. \[48] Dumping and undumping the tables. +After \.{INIMF} has seen a collection of macros, it +can write all the necessary information on an auxiliary file so +that production versions of \MF\ 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 \\{base\_ident} is a string that is printed right +after the \\{banner} line when \MF\ is ready to start. For \.{INIMF} this +string says simply `\.{(INIMF)}'; for other versions of \MF\ it says, +for example, `\.{(preloaded base=plain 84.2.29)}', showing the year, +month, and day that the base file was created. We have $\\{base\_ident}=0$ +before \MF's tables are loaded. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{base\_ident}: \37\\{str\_number};\par +\fi + +\M1184. \P$\X21:Set initial values of key variables\X\mathrel{+}\S$\6 +$\\{base\_ident}\K0$;\par +\fi + +\M1185. \P$\X176:Initialize table entries (done by \.{INIMF} only)\X\mathrel{+}% +\S$\6 +$\\{base\_ident}\K\.{"\ (INIMF)"}$;\par +\fi + +\M1186. \P$\X995:Declare action procedures for use by \\{do\_statement}\X% +\mathrel{+}\S$\6 +\&{init} \37\&{procedure}\1\ \37\\{store\_base\_file};\6 +\4\&{var} \37\|k: \37\\{integer};\C{all-purpose index}\6 +$\|p,\39\|q$: \37\\{pointer};\C{all-purpose pointers}\6 +\|x: \37\\{integer};\C{something to dump}\6 +\|w: \37\\{four\_quarters};\C{four ASCII codes}\2\6 +\&{begin} \37\X1200:Create the \\{base\_ident}, open the base file, and inform +the user that dumping has begun\X;\6 +\X1190:Dump constants for consistency check\X;\6 +\X1192:Dump the string pool\X;\6 +\X1194:Dump the dynamic memory\X;\6 +\X1196:Dump the table of equivalents and the hash table\X;\6 +\X1198:Dump a few more things and the closing check word\X;\6 +\X1201:Close the base file\X;\6 +\&{end};\6 +\&{tini}\par +\fi + +\M1187. Corresponding to the procedure that dumps a base file, we also have a +function +that reads~one~in. The function returns \\{false} if the dumped base is +incompatible with the present \MF\ table sizes, etc. + +\Y\P\D \37$\\{off\_base}=6666$\C{go here if the base file is unacceptable}\par +\P\D \37$\\{too\_small}(\#)\S$\1\6 +\&{begin} \37\\{wake\_up\_terminal};\5 +$\\{wterm\_ln}(\.{\'---!\ Must\ increase\ the\ \'},\39\#)$;\5 +\&{goto} \37\\{off\_base};\6 +\&{end}\2\par +\Y\P\hbox{\4}\X779:Declare the function called \\{open\_base\_file}\X\6 +\4\&{function}\1\ \37\\{load\_base\_file}: \37\\{boolean};\6 +\4\&{label} \37$\\{off\_base},\39\\{exit}$;\6 +\4\&{var} \37\|k: \37\\{integer};\C{all-purpose index}\6 +$\|p,\39\|q$: \37\\{pointer};\C{all-purpose pointers}\6 +\|x: \37\\{integer};\C{something undumped}\6 +\|w: \37\\{four\_quarters};\C{four ASCII codes}\2\6 +\&{begin} \37\X1191:Undump constants for consistency check\X;\6 +\X1193:Undump the string pool\X;\6 +\X1195:Undump the dynamic memory\X;\6 +\X1197:Undump the table of equivalents and the hash table\X;\6 +\X1199:Undump a few more things and the closing check word\X;\6 +$\\{load\_base\_file}\K\\{true}$;\5 +\&{return};\C{it worked!}\6 +\4\\{off\_base}: \37\\{wake\_up\_terminal};\5 +$\\{wterm\_ln}(\.{\'(Fatal\ base\ file\ error;\ I\'}\.{\'m\ stymied)\'})$;\5 +$\\{load\_base\_file}\K\\{false}$;\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M1188. Base files consist of \\{memory\_word} items, and we use the following +macros to dump words of different types: + +\Y\P\D \37$\\{dump\_wd}(\#)\S$\1\6 +\&{begin} \37$\\{base\_file}\^\K\#$;\5 +$\\{put}(\\{base\_file})$;\ \&{end}\2\par +\P\D \37$\\{dump\_int}(\#)\S$\1\6 +\&{begin} \37$\\{base\_file}\^.\\{int}\K\#$;\5 +$\\{put}(\\{base\_file})$;\ \&{end}\2\par +\P\D \37$\\{dump\_hh}(\#)\S$\1\6 +\&{begin} \37$\\{base\_file}\^.\\{hh}\K\#$;\5 +$\\{put}(\\{base\_file})$;\ \&{end}\2\par +\P\D \37$\\{dump\_qqqq}(\#)\S$\1\6 +\&{begin} \37$\\{base\_file}\^.\\{qqqq}\K\#$;\5 +$\\{put}(\\{base\_file})$;\ \&{end}\2\par +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{base\_file}: \37\\{word\_file};\C{for input or output of base information}% +\par +\fi + +\M1189. The inverse macros are slightly more complicated, since we need to +check +the range of the values we are reading in. We say `$\\{undump}(\|a)(\|b)(\|x)$' +to +read an integer value \|x that is supposed to be in the range $\|a\L\|x\L\|b$. + +\Y\P\D \37$\\{undump\_wd}(\#)\S$\1\6 +\&{begin} \37$\\{get}(\\{base\_file})$;\5 +$\#\K\\{base\_file}\^$;\ \&{end}\2\par +\P\D \37$\\{undump\_int}(\#)\S$\1\6 +\&{begin} \37$\\{get}(\\{base\_file})$;\5 +$\#\K\\{base\_file}\^.\\{int}$;\ \&{end}\2\par +\P\D \37$\\{undump\_hh}(\#)\S$\1\6 +\&{begin} \37$\\{get}(\\{base\_file})$;\5 +$\#\K\\{base\_file}\^.\\{hh}$;\ \&{end}\2\par +\P\D \37$\\{undump\_qqqq}(\#)\S$\1\6 +\&{begin} \37$\\{get}(\\{base\_file})$;\5 +$\#\K\\{base\_file}\^.\\{qqqq}$;\ \&{end}\2\par +\P\D \37$\\{undump\_end\_end}(\#)\S\#\K\|x$;\ \&{end} \par +\P\D $\\{undump\_end}(\#)\S(\|x>\#)$ \&{then} \&{goto} \37\\{off\_base}\ % +\&{else} \37\\{undump\_end\_end}\par +\P\D $\\{undump}(\#)\S$ \6 +\&{begin} \37$\\{undump\_int}(\|x)$; \6 +\&{if} $(\|x<\#)\V\\{undump\_end}$\par +\P\D \37$\\{undump\_size\_end\_end}(\#)\S\\{too\_small}(\#)$\ \&{else} \37% +\\{undump\_end\_end}\par +\P\D \37$\\{undump\_size\_end}(\#)\S$\1\6 +\&{if} $\|x>\#$ \1\&{then}\5 +\\{undump\_size\_end\_end}\2\2\par +\P\D $\\{undump\_size}(\#)\S$ \6 +\&{begin} \37$\\{undump\_int}(\|x)$;\6 +\&{if} $\|x<\#$ \1\&{then}\5 +\&{goto} \37\\{off\_base};\2\6 +\\{undump\_size\_end}\par +\fi + +\M1190. The next few sections of the program should make it clear how we use +the +dump/undump macros. + +\Y\P$\4\X1190:Dump constants for consistency check\X\S$\6 +$\\{dump\_int}(\))$;\6 +$\\{dump\_int}(\\{mem\_min})$;\6 +$\\{dump\_int}(\\{mem\_top})$;\6 +$\\{dump\_int}(\\{hash\_size})$;\6 +$\\{dump\_int}(\\{hash\_prime})$;\6 +$\\{dump\_int}(\\{max\_in\_open})$\par +\U1186.\fi + +\M1191. Sections of a \.{WEB} program that are ``commented out'' still +contribute +strings to the string pool; therefore \.{INIMF} and \MF\ will have +the same strings. (And it is, of course, a good thing that they do.) + +\Y\P$\4\X1191:Undump constants for consistency check\X\S$\6 +$\|x\K\\{base\_file}\^.\\{int}$;\6 +\&{if} $\|x\I\)$ \1\&{then}\5 +\&{goto} \37\\{off\_base};\C{check that strings are the same}\2\6 +$\\{undump\_int}(\|x)$;\6 +\&{if} $\|x\I\\{mem\_min}$ \1\&{then}\5 +\&{goto} \37\\{off\_base};\2\6 +$\\{undump\_int}(\|x)$;\6 +\&{if} $\|x\I\\{mem\_top}$ \1\&{then}\5 +\&{goto} \37\\{off\_base};\2\6 +$\\{undump\_int}(\|x)$;\6 +\&{if} $\|x\I\\{hash\_size}$ \1\&{then}\5 +\&{goto} \37\\{off\_base};\2\6 +$\\{undump\_int}(\|x)$;\6 +\&{if} $\|x\I\\{hash\_prime}$ \1\&{then}\5 +\&{goto} \37\\{off\_base};\2\6 +$\\{undump\_int}(\|x)$;\6 +\&{if} $\|x\I\\{max\_in\_open}$ \1\&{then}\5 +\&{goto} \37\\{off\_base}\2\par +\U1187.\fi + +\M1192. \P\D \37$\\{dump\_four\_ASCII}\S\|w.\\{b0}\K\\{qi}(\\{so}(\\{str% +\_pool}[\|k]))$;\5 +$\|w.\\{b1}\K\\{qi}(\\{so}(\\{str\_pool}[\|k+1]))$;\5 +$\|w.\\{b2}\K\\{qi}(\\{so}(\\{str\_pool}[\|k+2]))$;\5 +$\|w.\\{b3}\K\\{qi}(\\{so}(\\{str\_pool}[\|k+3]))$;\5 +$\\{dump\_qqqq}(\|w)$\par +\Y\P$\4\X1192:Dump the string pool\X\S$\6 +$\\{dump\_int}(\\{pool\_ptr})$;\5 +$\\{dump\_int}(\\{str\_ptr})$;\6 +\&{for} $\|k\K0\mathrel{\&{to}}\\{str\_ptr}$ \1\&{do}\5 +$\\{dump\_int}(\\{str\_start}[\|k])$;\2\6 +$\|k\K0$;\6 +\&{while} $\|k+4<\\{pool\_ptr}$ \1\&{do}\6 +\&{begin} \37\\{dump\_four\_ASCII};\5 +$\|k\K\|k+4$;\6 +\&{end};\2\6 +$\|k\K\\{pool\_ptr}-4$;\5 +\\{dump\_four\_ASCII};\5 +\\{print\_ln};\5 +$\\{print\_int}(\\{str\_ptr})$;\5 +$\\{print}(\.{"\ strings\ of\ total\ length\ "})$;\5 +$\\{print\_int}(\\{pool\_ptr})$\par +\U1186.\fi + +\M1193. \P\D \37$\\{undump\_four\_ASCII}\S\\{undump\_qqqq}(\|w)$;\5 +$\\{str\_pool}[\|k]\K\\{si}(\\{qo}(\|w.\\{b0}))$;\5 +$\\{str\_pool}[\|k+1]\K\\{si}(\\{qo}(\|w.\\{b1}))$;\5 +$\\{str\_pool}[\|k+2]\K\\{si}(\\{qo}(\|w.\\{b2}))$;\5 +$\\{str\_pool}[\|k+3]\K\\{si}(\\{qo}(\|w.\\{b3}))$\par +\Y\P$\4\X1193:Undump the string pool\X\S$\6 +$\\{undump\_size}(0)(\\{pool\_size})(\.{\'string\ pool\ size\'})(\\{pool% +\_ptr})$;\5 +$\\{undump\_size}(0)(\\{max\_strings})(\.{\'max\ strings\'})(\\{str\_ptr})$;\6 +\&{for} $\|k\K0\mathrel{\&{to}}\\{str\_ptr}$ \1\&{do}\6 +\&{begin} \37$\\{undump}(0)(\\{pool\_ptr})(\\{str\_start}[\|k])$;\5 +$\\{str\_ref}[\|k]\K\\{max\_str\_ref}$;\6 +\&{end};\2\6 +$\|k\K0$;\6 +\&{while} $\|k+4<\\{pool\_ptr}$ \1\&{do}\6 +\&{begin} \37\\{undump\_four\_ASCII};\5 +$\|k\K\|k+4$;\6 +\&{end};\2\6 +$\|k\K\\{pool\_ptr}-4$;\5 +\\{undump\_four\_ASCII};\5 +$\\{init\_str\_ptr}\K\\{str\_ptr}$;\5 +$\\{init\_pool\_ptr}\K\\{pool\_ptr}$;\5 +$\\{max\_str\_ptr}\K\\{str\_ptr}$;\5 +$\\{max\_pool\_ptr}\K\\{pool\_ptr}$\par +\U1187.\fi + +\M1194. 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 \.{INIMF} dumps valid +information even when it has not been gathering statistics. + +\Y\P$\4\X1194:Dump the dynamic memory\X\S$\6 +\\{sort\_avail};\5 +$\\{var\_used}\K0$;\5 +$\\{dump\_int}(\\{lo\_mem\_max})$;\5 +$\\{dump\_int}(\\{rover})$;\5 +$\|p\K\\{mem\_min}$;\5 +$\|q\K\\{rover}$;\5 +$\|x\K0$;\6 +\1\&{repeat} \37\&{for} $\|k\K\|p\mathrel{\&{to}}\|q+1$ \1\&{do}\5 +$\\{dump\_wd}(\\{mem}[\|k])$;\2\6 +$\|x\K\|x+\|q+2-\|p$;\5 +$\\{var\_used}\K\\{var\_used}+\|q-\|p$;\5 +$\|p\K\|q+\\{node\_size}(\|q)$;\5 +$\|q\K\\{rlink}(\|q)$;\6 +\4\&{until}\5 +$\|q=\\{rover}$;\2\6 +$\\{var\_used}\K\\{var\_used}+\\{lo\_mem\_max}-\|p$;\5 +$\\{dyn\_used}\K\\{mem\_end}+1-\\{hi\_mem\_min}$;\6 +\&{for} $\|k\K\|p\mathrel{\&{to}}\\{lo\_mem\_max}$ \1\&{do}\5 +$\\{dump\_wd}(\\{mem}[\|k])$;\2\6 +$\|x\K\|x+\\{lo\_mem\_max}+1-\|p$;\5 +$\\{dump\_int}(\\{hi\_mem\_min})$;\5 +$\\{dump\_int}(\\{avail})$;\6 +\&{for} $\|k\K\\{hi\_mem\_min}\mathrel{\&{to}}\\{mem\_end}$ \1\&{do}\5 +$\\{dump\_wd}(\\{mem}[\|k])$;\2\6 +$\|x\K\|x+\\{mem\_end}+1-\\{hi\_mem\_min}$;\5 +$\|p\K\\{avail}$;\6 +\&{while} $\|p\I\\{null}$ \1\&{do}\6 +\&{begin} \37$\\{decr}(\\{dyn\_used})$;\5 +$\|p\K\\{link}(\|p)$;\6 +\&{end};\2\6 +$\\{dump\_int}(\\{var\_used})$;\5 +$\\{dump\_int}(\\{dyn\_used})$;\5 +\\{print\_ln};\5 +$\\{print\_int}(\|x)$;\5 +$\\{print}(\.{"\ memory\ locations\ dumped;\ current\ usage\ is\ "})$;\5 +$\\{print\_int}(\\{var\_used})$;\5 +$\\{print\_char}(\.{"\&"})$;\5 +$\\{print\_int}(\\{dyn\_used})$\par +\U1186.\fi + +\M1195. \P$\X1195:Undump the dynamic memory\X\S$\6 +$\\{undump}(\\{lo\_mem\_stat\_max}+1000)(\\{hi\_mem\_stat\_min}-1)(\\{lo\_mem% +\_max})$;\5 +$\\{undump}(\\{lo\_mem\_stat\_max}+1)(\\{lo\_mem\_max})(\\{rover})$;\5 +$\|p\K\\{mem\_min}$;\5 +$\|q\K\\{rover}$;\6 +\1\&{repeat} \37\&{for} $\|k\K\|p\mathrel{\&{to}}\|q+1$ \1\&{do}\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\&{then}\5 +\&{goto} \37\\{off\_base};\2\6 +$\|q\K\\{rlink}(\|q)$;\6 +\4\&{until}\5 +$\|q=\\{rover}$;\2\6 +\&{for} $\|k\K\|p\mathrel{\&{to}}\\{lo\_mem\_max}$ \1\&{do}\5 +$\\{undump\_wd}(\\{mem}[\|k])$;\2\6 +$\\{undump}(\\{lo\_mem\_max}+1)(\\{hi\_mem\_stat\_min})(\\{hi\_mem\_min})$;\5 +$\\{undump}(\\{null})(\\{mem\_top})(\\{avail})$;\5 +$\\{mem\_end}\K\\{mem\_top}$;\6 +\&{for} $\|k\K\\{hi\_mem\_min}\mathrel{\&{to}}\\{mem\_end}$ \1\&{do}\5 +$\\{undump\_wd}(\\{mem}[\|k])$;\2\6 +$\\{undump\_int}(\\{var\_used})$;\5 +$\\{undump\_int}(\\{dyn\_used})$\par +\U1187.\fi + +\M1196. A different scheme is used to compress the hash table, since its lower +region +is usually sparse. When $\\{text}(\|p)\I0$ for $\|p\L\\{hash\_used}$, we output +three +words: \|p, $\\{hash}[\|p]$, and $\\{eqtb}[\|p]$. The hash table is, of course, +densely +packed for $\|p\G\\{hash\_used}$, so the remaining entries are output +in~a~block. + +\Y\P$\4\X1196:Dump the table of equivalents and the hash table\X\S$\6 +$\\{dump\_int}(\\{hash\_used})$;\5 +$\\{st\_count}\K\\{frozen\_inaccessible}-1-\\{hash\_used}$;\6 +\&{for} $\|p\K1\mathrel{\&{to}}\\{hash\_used}$ \1\&{do}\6 +\&{if} $\\{text}(\|p)\I0$ \1\&{then}\6 +\&{begin} \37$\\{dump\_int}(\|p)$;\5 +$\\{dump\_hh}(\\{hash}[\|p])$;\5 +$\\{dump\_hh}(\\{eqtb}[\|p])$;\5 +$\\{incr}(\\{st\_count})$;\6 +\&{end};\2\2\6 +\&{for} $\|p\K\\{hash\_used}+1\mathrel{\&{to}}\\{hash\_end}$ \1\&{do}\6 +\&{begin} \37$\\{dump\_hh}(\\{hash}[\|p])$;\5 +$\\{dump\_hh}(\\{eqtb}[\|p])$;\6 +\&{end};\2\6 +$\\{dump\_int}(\\{st\_count})$;\6 +\\{print\_ln};\5 +$\\{print\_int}(\\{st\_count})$;\5 +$\\{print}(\.{"\ symbolic\ tokens"})$\par +\U1186.\fi + +\M1197. \P$\X1197:Undump the table of equivalents and the hash table\X\S$\6 +$\\{undump}(1)(\\{frozen\_inaccessible})(\\{hash\_used})$;\5 +$\|p\K0$;\6 +\1\&{repeat} \37$\\{undump}(\|p+1)(\\{hash\_used})(\|p)$;\5 +$\\{undump\_hh}(\\{hash}[\|p])$;\5 +$\\{undump\_hh}(\\{eqtb}[\|p])$;\6 +\4\&{until}\5 +$\|p=\\{hash\_used}$;\2\6 +\&{for} $\|p\K\\{hash\_used}+1\mathrel{\&{to}}\\{hash\_end}$ \1\&{do}\6 +\&{begin} \37$\\{undump\_hh}(\\{hash}[\|p])$;\5 +$\\{undump\_hh}(\\{eqtb}[\|p])$;\6 +\&{end};\2\6 +$\\{undump\_int}(\\{st\_count})$\par +\U1187.\fi + +\M1198. We have already printed a lot of statistics, so we set $\\{tracing% +\_stats}\K0$ +to prevent them from appearing again. + +\Y\P$\4\X1198:Dump a few more things and the closing check word\X\S$\6 +$\\{dump\_int}(\\{int\_ptr})$;\6 +\&{for} $\|k\K1\mathrel{\&{to}}\\{int\_ptr}$ \1\&{do}\6 +\&{begin} \37$\\{dump\_int}(\\{internal}[\|k])$;\5 +$\\{dump\_int}(\\{int\_name}[\|k])$;\6 +\&{end};\2\6 +$\\{dump\_int}(\\{start\_sym})$;\5 +$\\{dump\_int}(\\{interaction})$;\5 +$\\{dump\_int}(\\{base\_ident})$;\5 +$\\{dump\_int}(\\{bg\_loc})$;\5 +$\\{dump\_int}(\\{eg\_loc})$;\5 +$\\{dump\_int}(\\{serial\_no})$;\5 +$\\{dump\_int}(69069)$;\5 +$\\{internal}[\\{tracing\_stats}]\K0$\par +\U1186.\fi + +\M1199. \P$\X1199:Undump a few more things and the closing check word\X\S$\6 +$\\{undump}(\\{max\_given\_internal})(\\{max\_internal})(\\{int\_ptr})$;\6 +\&{for} $\|k\K1\mathrel{\&{to}}\\{int\_ptr}$ \1\&{do}\6 +\&{begin} \37$\\{undump\_int}(\\{internal}[\|k])$;\5 +$\\{undump}(0)(\\{str\_ptr})(\\{int\_name}[\|k])$;\6 +\&{end};\2\6 +$\\{undump}(0)(\\{frozen\_inaccessible})(\\{start\_sym})$;\5 +$\\{undump}(\\{batch\_mode})(\\{error\_stop\_mode})(\\{interaction})$;\5 +$\\{undump}(0)(\\{str\_ptr})(\\{base\_ident})$;\5 +$\\{undump}(1)(\\{hash\_end})(\\{bg\_loc})$;\5 +$\\{undump}(1)(\\{hash\_end})(\\{eg\_loc})$;\5 +$\\{undump\_int}(\\{serial\_no})$;\6 +$\\{undump\_int}(\|x)$;\ \&{if} $(\|x\I69069)\V\\{eof}(\\{base\_file})$ \1% +\&{then}\5 +\&{goto} \37\\{off\_base}\2\par +\U1187.\fi + +\M1200. \P$\X1200:Create the \\{base\_ident}, open the base file, and inform +the user that dumping has begun\X\S$\6 +$\\{selector}\K\\{new\_string}$;\5 +$\\{print}(\.{"\ (preloaded\ base="})$;\5 +$\\{print}(\\{job\_name})$;\5 +$\\{print\_char}(\.{"\ "})$;\5 +$\\{print\_int}(\\{round\_unscaled}(\\{internal}[\\{year}]))$;\5 +$\\{print\_char}(\.{"."})$;\5 +$\\{print\_int}(\\{round\_unscaled}(\\{internal}[\\{month}]))$;\5 +$\\{print\_char}(\.{"."})$;\5 +$\\{print\_int}(\\{round\_unscaled}(\\{internal}[\\{day}]))$;\5 +$\\{print\_char}(\.{")"})$;\6 +\&{if} $\\{interaction}=\\{batch\_mode}$ \1\&{then}\5 +$\\{selector}\K\\{log\_only}$\6 +\4\&{else} $\\{selector}\K\\{term\_and\_log}$;\2\6 +$\\{str\_room}(1)$;\5 +$\\{base\_ident}\K\\{make\_string}$;\5 +$\\{str\_ref}[\\{base\_ident}]\K\\{max\_str\_ref}$;\6 +$\\{pack\_job\_name}(\\{base\_extension})$;\6 +\&{while} $\R\\{w\_open\_out}(\\{base\_file})$ \1\&{do}\5 +$\\{prompt\_file\_name}(\.{"base\ file\ name"},\39\\{base\_extension})$;\2\6 +$\\{print\_nl}(\.{"Beginning\ to\ dump\ on\ file\ "})$;\5 +$\\{slow\_print}(\\{w\_make\_name\_string}(\\{base\_file}))$;\5 +$\\{flush\_string}(\\{str\_ptr}-1)$;\5 +$\\{print\_nl}(\.{""})$;\5 +$\\{slow\_print}(\\{base\_ident})$\par +\U1186.\fi + +\M1201. \P$\X1201:Close the base file\X\S$\6 +$\\{w\_close}(\\{base\_file})$\par +\U1186.\fi + +\N1202. \[49] The main program. +This is it: the part of \MF\ that executes all those procedures we have +written. + +Well---almost. We haven't put the parsing subroutines into the +program yet; and we'd better leave space for a few more routines that may +have been forgotten. + +\Y\P\X823:Declare the basic parsing subroutines\X\6 +\X224:Declare miscellaneous procedures that were declared \\{forward}\X\6 +\X1205:Last-minute procedures\X\par +\fi + +\M1203. We've noted that there are two versions of \MF84. One, called % +\.{INIMF}, +has to be run first; it initializes everything from scratch, without +reading a base file, and it has the capability of dumping a base file. +The other one is called `\.{VIRMF}'; it is a ``virgin'' program that needs +to input a base file in order to get started. \.{VIRMF} typically has +a bit more memory capacity than \.{INIMF}, because it does not need the +space consumed by the dumping/undumping routines and the numerous calls on +\\{primitive}, etc. + +The \.{VIRMF} program cannot read a base file instantaneously, of course; +the best implementations therefore allow for production versions of \MF\ that +not only avoid the loading routine for \PASCAL\ object code, they also have +a base 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 \.{VIRMF} is first +loaded.\quad(2)~After we have read in a base file and initialized +everything, we set $\\{ready\_already}\K314159$.\quad(3)~Soon \.{VIRMF} +will print `\.*', waiting for more input; and at this point we +interrupt the program and save its core image in some form that the +operating system can reload speedily.\quad(4)~When that core image is +activated, the program starts again at the beginning; but now +$\\{ready\_already}=314159$ and all the other global variables have +their initial values too. The former chastity has vanished! + +In other words, if we allow ourselves to test the condition +$\\{ready\_already}=314159$, before \\{ready\_already} has been +assigned a value, we can avoid the lengthy initialization. Dirty tricks +rarely pay off so handsomely. + +On systems that allow such preloading, the standard program called \.{MF} +should be the one that has \.{plain} base preloaded, since that agrees +with {\sl The {\logos METAFONT\/}book}. Other versions, e.g., \.{cmbase}, +should also be provided for commonly used bases. + +\Y\P$\4\X13:Global variables\X\mathrel{+}\S$\6 +\4\\{ready\_already}: \37\\{integer};\C{a sacrifice of purity for economy}\par +\fi + +\M1204. Now this is really it: \MF\ starts and ends here. + +The initial test involving \\{ready\_already} should be deleted if the +\PASCAL\ runtime system is smart enough to detect such a ``mistake.'' + +\Y\P\&{begin} \37\C{\\{start\_here}}\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}=314159$ \1\&{then}\5 +\&{goto} \37\\{start\_of\_MF};\2\6 +\X14:Check the ``constant'' values for consistency\X\6 +\&{if} $\\{bad}>0$ \1\&{then}\6 +\&{begin} \37$\\{wterm\_ln}(\.{\'Ouch---my\ internal\ constants\ have\ been\ +clobbered!\'},\39\.{\'---case\ \'},\39\\{bad}:1)$;\5 +\&{goto} \37\\{final\_end};\6 +\&{end};\2\6 +\\{initialize};\C{set global variables to their starting values}\6 +\&{init} \37\&{if} $\R\\{get\_strings\_started}$ \1\&{then}\5 +\&{goto} \37\\{final\_end};\2\6 +\\{init\_tab};\C{initialize the tables}\6 +\\{init\_prim};\C{call \\{primitive} for each primitive}\6 +$\\{init\_str\_ptr}\K\\{str\_ptr}$;\5 +$\\{init\_pool\_ptr}\K\\{pool\_ptr}$;\6 +$\\{max\_str\_ptr}\K\\{str\_ptr}$;\5 +$\\{max\_pool\_ptr}\K\\{pool\_ptr}$;\5 +\\{fix\_date\_and\_time};\6 +\&{tini}\6 +$\\{ready\_already}\K314159$;\6 +\4\\{start\_of\_MF}: \37\X55:Initialize the output routines\X;\6 +\X1211:Get the first line of input and prepare to start\X;\6 +$\\{history}\K\\{spotless}$;\C{ready to go!}\6 +\&{if} $\\{start\_sym}>0$ \1\&{then}\C{insert the `\&{everyjob}' symbol}\6 +\&{begin} \37$\\{cur\_sym}\K\\{start\_sym}$;\5 +\\{back\_input};\6 +\&{end};\2\6 +\\{main\_control};\C{come to life}\6 +\\{final\_cleanup};\C{prepare for death}\6 +\4\\{end\_of\_MF}: \37\\{close\_files\_and\_terminate};\6 +\4\\{final\_end}: \37$\\{ready\_already}\K0$;\6 +\&{end}.\par +\fi + +\M1205. Here we do whatever is needed to complete \MF'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. + +This program doesn't bother to close the input files that may still be open. + +\Y\P$\4\X1205:Last-minute procedures\X\S$\6 +\4\&{procedure}\1\ \37\\{close\_files\_and\_terminate};\6 +\4\&{var} \37\|k: \37\\{integer};\C{all-purpose index}\6 +\\{lh}: \37\\{integer};\C{the length of the \.{TFM} header, in words}\6 +\\{lk\_offset}: \37$0\to256$;\C{extra words inserted at beginning of \\{lig% +\_kern} array}\6 +\|p: \37\\{pointer};\C{runs through a list of \.{TFM} dimensions}\6 +\|x: \37\\{scaled};\C{a \\{tfm\_width} value being output to the \.{GF} file}\2% +\6 +\&{begin} \37\&{stat} \37\&{if} $\\{internal}[\\{tracing\_stats}]>0$ \1\&{then}% +\5 +\X1208:Output statistics about this job\X;\2\ \&{tats}\6 +\\{wake\_up\_terminal};\5 +\X1206:Finish the \.{TFM} and \.{GF} files\X;\6 +\&{if} $\\{log\_opened}$ \1\&{then}\6 +\&{begin} \37\\{wlog\_cr};\5 +$\\{a\_close}(\\{log\_file})$;\5 +$\\{selector}\K\\{selector}-2$;\6 +\&{if} $\\{selector}=\\{term\_only}$ \1\&{then}\6 +\&{begin} \37$\\{print\_nl}(\.{"Transcript\ written\ on\ "})$;\5 +$\\{slow\_print}(\\{log\_name})$;\5 +$\\{print\_char}(\.{"."})$;\6 +\&{end};\2\6 +\&{end};\2\6 +\&{end};\par +\As1209, 1210\ETs1212. +\U1202.\fi + +\M1206. We want to finish the \.{GF} file if and only if it has already been +started; +this will be true if and only if \\{gf\_prev\_ptr} is positive. +We want to produce a \.{TFM} file if and only if \\{fontmaking} is positive. +The \.{TFM} widths must be computed if there's a \.{GF} file, even if +there's going to be no \.{TFM}~file. + +We reclaim all of the variable-size memory at this point, so that +there is no chance of another memory overflow after the memory capacity +has already been exceeded. + +\Y\P$\4\X1206:Finish the \.{TFM} and \.{GF} files\X\S$\6 +\&{if} $(\\{gf\_prev\_ptr}>0)\V(\\{internal}[\\{fontmaking}]>0)$ \1\&{then}\6 +\&{begin} \37\X1207:Make the dynamic memory into one big available node\X;\6 +\X1124:Massage the \.{TFM} widths\X;\6 +\\{fix\_design\_size};\5 +\\{fix\_check\_sum};\6 +\&{if} $\\{internal}[\\{fontmaking}]>0$ \1\&{then}\6 +\&{begin} \37\X1126:Massage the \.{TFM} heights, depths, and italic corrections% +\X;\6 +$\\{internal}[\\{fontmaking}]\K0$;\C{avoid loop in case of fatal error}\6 +\X1134:Finish the \.{TFM} file\X;\6 +\&{end};\2\6 +\&{if} $\\{gf\_prev\_ptr}>0$ \1\&{then}\5 +\X1182:Finish the \.{GF} file\X;\2\6 +\&{end}\2\par +\U1205.\fi + +\M1207. \P$\X1207:Make the dynamic memory into one big available node\X\S$\6 +$\\{rover}\K\\{lo\_mem\_stat\_max}+1$;\5 +$\\{link}(\\{rover})\K\\{empty\_flag}$;\5 +$\\{lo\_mem\_max}\K\\{hi\_mem\_min}-1$;\6 +\&{if} $\\{lo\_mem\_max}-\\{rover}>\\{max\_halfword}$ \1\&{then}\5 +$\\{lo\_mem\_max}\K\\{max\_halfword}+\\{rover}$;\2\6 +$\\{node\_size}(\\{rover})\K\\{lo\_mem\_max}-\\{rover}$;\5 +$\\{llink}(\\{rover})\K\\{rover}$;\5 +$\\{rlink}(\\{rover})\K\\{rover}$;\5 +$\\{link}(\\{lo\_mem\_max})\K\\{null}$;\5 +$\\{info}(\\{lo\_mem\_max})\K\\{null}$\par +\U1206.\fi + +\M1208. 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 \MF\ is being used. + +\Y\P$\4\X1208:Output statistics about this job\X\S$\6 +\&{if} $\\{log\_opened}$ \1\&{then}\6 +\&{begin} \37$\\{wlog\_ln}(\.{\'\ \'})$;\5 +$\\{wlog\_ln}(\.{\'Here\ is\ how\ much\ of\ METAFONT\'}\.{\'s\ memory\'},\39\.{% +\'\ you\ used:\'})$;\5 +$\\{wlog}(\.{\'\ \'},\39\\{max\_str\_ptr}-\\{init\_str\_ptr}:1,\39\.{\'\ string% +\'})$;\6 +\&{if} $\\{max\_str\_ptr}\I\\{init\_str\_ptr}+1$ \1\&{then}\5 +$\\{wlog}(\.{\'s\'})$;\2\6 +$\\{wlog\_ln}(\.{\'\ out\ of\ \'},\39\\{max\_strings}-\\{init\_str\_ptr}:1)$;\6 +$\\{wlog\_ln}(\.{\'\ \'},\39\\{max\_pool\_ptr}-\\{init\_pool\_ptr}:1,\39\.{\'\ +string\ characters\ out\ of\ \'},\39\\{pool\_size}-\\{init\_pool\_ptr}:1)$;\6 +$\\{wlog\_ln}(\.{\'\ \'},\39\\{lo\_mem\_max}-\\{mem\_min}+\\{mem\_end}-\\{hi% +\_mem\_min}+2:1,\39\30\.{\'\ words\ of\ memory\ out\ of\ \'},\39\\{mem\_end}+1-% +\\{mem\_min}:1)$;\6 +$\\{wlog\_ln}(\.{\'\ \'},\39\\{st\_count}:1,\39\.{\'\ symbolic\ tokens\ out\ of% +\ \'},\39\\{hash\_size}:1)$;\6 +$\\{wlog\_ln}(\.{\'\ \'},\39\\{max\_in\_stack}:1,\39\.{\'i,\'},\39\30\\{int% +\_ptr}:1,\39\.{\'n,\'},\39\30\\{max\_rounding\_ptr}:1,\39\.{\'r,\'},\39\30% +\\{max\_param\_stack}:1,\39\.{\'p,\'},\39\30\\{max\_buf\_stack}+1:1,\39\.{\'b\ +stack\ positions\ out\ of\ \'},\39\30\\{stack\_size}:1,\39\.{\'i,\'},\39\\{max% +\_internal}:1,\39\.{\'n,\'},\39\\{max\_wiggle}:1,\39\.{\'r,\'},\39\\{param% +\_size}:1,\39\.{\'p,\'},\39\\{buf\_size}:1,\39\.{\'b\'})$;\6 +\&{end}\2\par +\U1205.\fi + +\M1209. We get to the \\{final\_cleanup} routine when \&{end} or \&{dump} has +been scanned. + +\Y\P$\4\X1205:Last-minute procedures\X\mathrel{+}\S$\6 +\4\&{procedure}\1\ \37\\{final\_cleanup};\6 +\4\&{label} \37\\{exit};\6 +\4\&{var} \37\|c: \37\\{small\_number};\C{0 for \&{end}, 1 for \&{dump}}\2\6 +\&{begin} \37$\|c\K\\{cur\_mod}$;\6 +\&{if} $\\{job\_name}=0$ \1\&{then}\5 +\\{open\_log\_file};\2\6 +\&{while} $\\{input\_ptr}>0$ \1\&{do}\6 +\&{if} $\\{token\_state}$ \1\&{then}\5 +\\{end\_token\_list}\ \&{else} \\{end\_file\_reading};\2\2\6 +\&{while} $\\{loop\_ptr}\I\\{null}$ \1\&{do}\5 +\\{stop\_iteration};\2\6 +\&{while} $\\{open\_parens}>0$ \1\&{do}\6 +\&{begin} \37$\\{print}(\.{"\ )"})$;\5 +$\\{decr}(\\{open\_parens})$;\6 +\&{end};\2\6 +\&{while} $\\{cond\_ptr}\I\\{null}$ \1\&{do}\6 +\&{begin} \37$\\{print\_nl}(\.{"(end\ occurred\ when\ "})$;\6 +$\\{print\_cmd\_mod}(\\{fi\_or\_else},\39\\{cur\_if})$;\C{`\.{if}' or `% +\.{elseif}' or `\.{else}'}\6 +\&{if} $\\{if\_line}\I0$ \1\&{then}\6 +\&{begin} \37$\\{print}(\.{"\ on\ line\ "})$;\5 +$\\{print\_int}(\\{if\_line})$;\6 +\&{end};\2\6 +$\\{print}(\.{"\ was\ incomplete)"})$;\5 +$\\{if\_line}\K\\{if\_line\_field}(\\{cond\_ptr})$;\5 +$\\{cur\_if}\K\\{name\_type}(\\{cond\_ptr})$;\5 +$\\{loop\_ptr}\K\\{cond\_ptr}$;\5 +$\\{cond\_ptr}\K\\{link}(\\{cond\_ptr})$;\5 +$\\{free\_node}(\\{loop\_ptr},\39\\{if\_node\_size})$;\6 +\&{end};\2\6 +\&{if} $\\{history}\I\\{spotless}$ \1\&{then}\6 +\&{if} $((\\{history}=\\{warning\_issued})\V(\\{interaction}<\\{error\_stop% +\_mode}))$ \1\&{then}\6 +\&{if} $\\{selector}=\\{term\_and\_log}$ \1\&{then}\6 +\&{begin} \37$\\{selector}\K\\{term\_only}$;\5 +$\\{print\_nl}(\.{"(see\ the\ transcript\ file\ for\ additional\ +information)"})$;\5 +$\\{selector}\K\\{term\_and\_log}$;\6 +\&{end};\2\2\2\6 +\&{if} $\|c=1$ \1\&{then}\6 +\&{begin} \37\&{init} \37\\{store\_base\_file};\5 +\&{return};\ \&{tini}\6 +$\\{print\_nl}(\.{"(dump\ is\ performed\ only\ by\ INIMF)"})$;\5 +\&{return};\6 +\&{end};\2\6 +\4\\{exit}: \37\&{end};\par +\fi + +\M1210. \P$\X1205:Last-minute procedures\X\mathrel{+}\S$\6 +\&{init} \37\&{procedure}\1\ \37\\{init\_prim};\C{initialize all the +primitives}\2\6 +\&{begin} \37\X192:Put each of \MF's primitives into the hash table\X;\6 +\&{end};\7 +\4\&{procedure}\1\ \37\\{init\_tab};\C{initialize other tables}\6 +\4\&{var} \37\|k: \37\\{integer};\C{all-purpose index}\2\6 +\&{begin} \37\X176:Initialize table entries (done by \.{INIMF} only)\X\6 +\&{end};\6 +\&{tini}\par +\fi + +\M1211. When we begin the following code, \MF'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, \MF\ is ready to call on the +\\{main\_control} routine to do its work. + +\Y\P$\4\X1211:Get the first line of input and prepare to start\X\S$\6 +\&{begin} \37\X657:Initialize the input routines\X;\6 +\&{if} $(\\{base\_ident}=0)\V(\\{buffer}[\\{loc}]=\.{"\&"})$ \1\&{then}\6 +\&{begin} \37\&{if} $\\{base\_ident}\I0$ \1\&{then}\5 +\\{initialize};\C{erase preloaded base}\2\6 +\&{if} $\R\\{open\_base\_file}$ \1\&{then}\5 +\&{goto} \37\\{final\_end};\2\6 +\&{if} $\R\\{load\_base\_file}$ \1\&{then}\6 +\&{begin} \37$\\{w\_close}(\\{base\_file})$;\5 +\&{goto} \37\\{final\_end};\6 +\&{end};\2\6 +$\\{w\_close}(\\{base\_file})$;\6 +\&{while} $(\\{loc}<\\{limit})\W(\\{buffer}[\\{loc}]=\.{"\ "})$ \1\&{do}\5 +$\\{incr}(\\{loc})$;\2\6 +\&{end};\2\6 +$\\{buffer}[\\{limit}]\K\.{"\%"}$;\6 +\\{fix\_date\_and\_time};\5 +$\\{init\_randoms}((\\{internal}[\\{time}]\mathbin{\&{div}}\\{unity})+% +\\{internal}[\\{day}])$;\6 +\X70:Initialize the print \\{selector} based on \\{interaction}\X;\6 +\&{if} $\\{loc}<\\{limit}$ \1\&{then}\6 +\&{if} $\\{buffer}[\\{loc}]\I\.{"\\"}$ \1\&{then}\5 +\\{start\_input};\C{\&{input} assumed}\2\2\6 +\&{end}\par +\U1204.\fi + +\N1212. \[50] Debugging. +Once \MF\ 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 \MF\ 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 \MF\ to succumb. + +The interface to \\{debug\_help} is primitive, but it is good enough when used +with a \PASCAL\ debugger that allows you to set breakpoints and to read +variables and change their values. After getting the prompt `\.{debug \#}', you +type either a negative number (this exits \\{debug\_help}), or zero (this +goes to a location where you can set a breakpoint, thereby entering into +dialog with the \PASCAL\ debugger), or a positive number \|m followed by +an argument \|n. The meaning of \|m and \|n will be clear from the +program below. (If $\|m=13$, there is an additional argument, \|l.) + +\Y\P\D \37$\\{breakpoint}=888$\C{place where a breakpoint is desirable}\par +\Y\P$\4\X1205:Last-minute procedures\X\mathrel{+}\S$\6 +\&{debug} \37\&{procedure}\1\ \37\\{debug\_help};\C{routine to display various +things}\6 +\4\&{label} \37$\\{breakpoint},\39\\{exit}$;\6 +\4\&{var} \37$\|k,\39\|l,\39\|m,\39\|n$: \37\\{integer};\2\6 +\&{begin} \37\~ \1\&{loop}\6 +\&{begin} \37\\{wake\_up\_terminal};\5 +$\\{print\_nl}(\.{"debug\ \#\ (-1\ to\ exit):"})$;\5 +\\{update\_terminal};\5 +$\\{read}(\\{term\_in},\39\|m)$;\6 +\&{if} $\|m<0$ \1\&{then}\5 +\&{return}\6 +\4\&{else} \&{if} $\|m=0$ \1\&{then}\6 +\&{begin} \37\&{goto} \37\\{breakpoint};\5 +\]\C{go to every label at least once}\6 +\4\\{breakpoint}: \37$\|m\K0$;\5 +$\B\.{\'BREAKPOINT\'}\T\]$\6 +\&{end}\6 +\4\&{else} \&{begin} \37$\\{read}(\\{term\_in},\39\|n)$;\6 +\&{case} $\|m$ \1\&{of}\6 +\hbox{\4}\X1213:Numbered cases for \\{debug\_help}\X\6 +\4\&{othercases} \37$\\{print}(\.{"?"})$\2\6 +\&{endcases};\6 +\&{end};\2\2\6 +\&{end};\2\6 +\4\\{exit}: \37\&{end};\6 +\&{gubed}\par +\fi + +\M1213. \P$\X1213:Numbered cases for \\{debug\_help}\X\S$\6 +\41: \37$\\{print\_word}(\\{mem}[\|n])$;\C{display $\\{mem}[\|n]$ in all forms}% +\6 +\42: \37$\\{print\_int}(\\{info}(\|n))$;\6 +\43: \37$\\{print\_int}(\\{link}(\|n))$;\6 +\44: \37\&{begin} \37$\\{print\_int}(\\{eq\_type}(\|n))$;\5 +$\\{print\_char}(\.{":"})$;\5 +$\\{print\_int}(\\{equiv}(\|n))$;\6 +\&{end};\6 +\45: \37$\\{print\_variable\_name}(\|n)$;\6 +\46: \37$\\{print\_int}(\\{internal}[\|n])$;\6 +\47: \37\\{do\_show\_dependencies};\6 +\49: \37$\\{show\_token\_list}(\|n,\39\\{null},\39100000,\390)$;\6 +\410: \37$\\{slow\_print}(\|n)$;\6 +\411: \37$\\{check\_mem}(\|n>0)$;\C{check wellformedness; print new busy +locations if $\|n>0$}\6 +\412: \37$\\{search\_mem}(\|n)$;\C{look for pointers to \|n}\6 +\413: \37\&{begin} \37$\\{read}(\\{term\_in},\39\|l)$;\5 +$\\{print\_cmd\_mod}(\|n,\39\|l)$;\6 +\&{end};\6 +\414: \37\&{for} $\|k\K0\mathrel{\&{to}}\|n$ \1\&{do}\5 +$\\{print}(\\{buffer}[\|k])$;\2\6 +\415: \37$\\{panicking}\K\R\\{panicking}$;\par +\U1212.\fi + +\N1214. \[51] System-dependent changes. +This section should be replaced, if necessary, by any special +modifications of the program +that are necessary to make \MF\ 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 + +\N1215. \[52] 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 \MF\ in a new +operating environment. A list of various things that can't happen appears +under ``this can't happen''. +Approximately 25 sections are listed under ``inner loop''; these account +for more than 60\pct! of \MF's running time, exclusive of input and output. +\fi + + +\inx +\:\9{!!!}{\.{\&} primitive}, \[893]. +\:\.{!\relax}, 68, 807. +\:\9{* }{\.{*} primitive}, \[893]. +\:\.{**}, 36, 788. +\:\.{*\relax}, 679. +\:\9{+ }{\.{+} primitive}, \[893]. +\:\9{++\_}{\.{++} primitive}, \[893]. +\:\9{+-+\_}{\.{+-+} primitive}, \[893]. +\:\9{, }{\., primitive}, \[211]. +\:\9{- }{\.{-} primitive}, \[893]. +\:\.{->}, 227. +\:\9{. }{\..\ token}, 669. +\:\9{..\_}{\.{..} primitive}, \[211]. +\:\9{/ }{\.{/} primitive}, \[893]. +\:\9{: }{\.{:} primitive}, \[211]. +\:\9{:: }{\.{::} primitive}, \[211]. +\:\9{::: }{\.{\char'174\char'174:} primitive}, \[211]. +\:\9{:=\_}{\.{:=} primitive}, \[211]. +\:\9{; }{\.; primitive}, \[211]. +\:\9{< }{\.{<} primitive}, \[893]. +\:\9{<=\_}{\.{<=} primitive}, \[893]. +\:\9{<>\_}{\.{<>} primitive}, \[893]. +\:\9{= }{\.{=} primitive}, \[893]. +\:\9{=:/>\_}{\.{=:\char'174>} primitive}, \[1108]. +\:\9{=:/>\_}{\.{\char'174=:>} primitive}, \[1108]. +\:\9{=:/>\_}{\.{\char'174=:\char'174>>} primitive}, \[1108]. +\:\9{=:/>\_}{\.{\char'174=:\char'174>} primitive}, \[1108]. +\:\9{=:/\_}{\.{=:\char'174} primitive}, \[1108]. +\:\9{=:/\_}{\.{\char'174=:\char'174} primitive}, \[1108]. +\:\9{=:/\_}{\.{\char'174=:} primitive}, \[1108]. +\:\9{=:\_}{\.{=:} primitive}, \[1108]. +\:\.{=>}, 682. +\:\9{> }{\.{>} primitive}, \[893]. +\:\9{>=\_}{\.{>=} primitive}, \[893]. +\:\.{>>}, 807, 1040. +\:\.{>\relax}, 398, 1041. +\:\.{??}, 261, 263. +\:\.{???}, 59, 60, 257, 258. +\:\.{?\relax}, 78, 638. +\:\9{[ }{\.{[} primitive}, \[211]. +\:\9{] }{\.{]} primitive}, \[211]. +\:\9{][}{\.{\char`\{} primitive}, \[211]. +\:\9{]]\\}{\.{\char`\\} primitive}, \[211]. +\:\9{]]]\#\#\#\#\_}{\.{\#\#\#\#}}, 603. +\:\9{]]]\#\#\#\_}{\.{\#\#\#}}, 817. +\:\9{]]]\#\#\_}{\.{\#\#}}, 613. +\:\9{]]]\#\AT!\_}{\.{\#\AT!} primitive}, \[688]. +\:\9{]]]\AT!\#\_}{\.{\AT!\#} primitive}, \[688]. +\:\9{]]]\AT!\_}{\.{\AT!} primitive}, \[688]. +\:\9{]]]\AT!\_Octant}{\.{\AT! Octant...}}, 509. +\:\9{]]]\AT!\_retro\_}{\.{\AT! retrograde line...}}, 510. +\:\9{]]]\AT!\_trans\_}{\.{\AT! transition line...}}, 515, 521. +\:\9{]]}{\.{\char`\}} primitive}, \[211]. +\:\|{a}, \[47], \[102], \[117], \[124], \[126], \[321], \[391], \[429], \[431], +\[433], \[440], \[568], \[722], \[773], \[774], \[778], \[976], \[977], \[978], +\[1154]. +\:\.{a font metric dimension...}, 1140. +\:\.{A group...never ended}, 832. +\:\.{A primary expression...}, 823. +\:\.{A secondary expression...}, 862. +\:\.{A statement can't begin with x}, 990. +\:\.{A tertiary expression...}, 864. +\:\\{a\_close}, \[27], 51, 655, 1205. +\:\\{a\_make\_name\_string}, \[780], 788, 793. +\:\\{a\_minus\_b}, \[865], 866. +\:\\{a\_open\_in}, \[26], 51, 793. +\:\\{a\_open\_out}, \[26], 788. +\:\\{a\_plus\_b}, \[865], 866. +\:\\{a\_tension}, \[296]. +\:\\{aa}, \[286], 288, 290, 291, 301, \[321], 322, \[440], 444, 445, 446. +\:\\{aaa}, \[321], 322. +\:\\{ab\_vs\_cd}, \[117], 152, 300, 306, 317, 375, 376, 479, 488, 502, 516, +522, 546, 548, 549, 943, 949. +\:\\{abnegate}, \[390], 413, 421. +\:\\{abort\_find}, \[242], 243. +\:\\{abs}, 65, 124, 126, 150, 151, 152, 260, 288, 289, 292, 294, 295, 299, 300, +302, 321, 326, 362, 378, 404, 408, 426, 433, 434, 437, 441, 445, 457, 459, 479, +496, 498, 502, 529, 533, 540, 543, 589, 591, 595, 596, 598, 599, 600, 603, 611, +612, 615, 616, 812, 814, 837, 866, 915, 943, 949, 965, 1008, 1056, 1098, 1129, +1140, 1182. +\:\\{absorbing}, \[659], 664, 665, 730. +\:\\{acc}, \[116], \[286], 290. +\:\\{add\_mac\_ref}, \[226], 720, 845, 862, 864, 868, 1035. +\:\\{add\_mult\_dep}, \[971], 972. +\:\\{add\_or\_subtract}, 929, \[930], 936, 939. +\:\\{add\_pen\_ref}, \[487], 621, 855, 1063. +\:\\{add\_str\_ref}, \[42], 621, 678, 855, 1083. +\:\9{add\_to\_}{\&{addto} primitive}, \[211]. +\:\\{add\_to\_command}, \[186], 211, 212, 1058. +\:\\{add\_to\_type}, \[1059], 1064. +\:\\{after}, 426, \[427], 429, 436, 439, 440, 444, 446. +\:\\{all\_safe}, \[426], \[440], 446. +\:\\{alpha}, \[296], \[433], 436, 439, \[440], 444, \[527], 528, 529, 530, 533. +\:\\{alpha\_file}, \[24], 26, 27, 30, 31, 50, 54, 631, 780. +\:\\{already\_there}, \[577], 578, 583, 584. +\:\9{also\_}{\&{also} primitive}, \[1052]. +\:\\{also\_code}, \[403], 1052, 1059. +\:\\{ampersand}, \[186], 868, 869, 874, 886, 887, 891, 893, 894. +\:\.{An expression...}, 868. +\:\9{and\_}{\&{and} primitive}, \[893]. +\:\\{and\_command}, \[186], 882, 884, 893, 894. +\:\\{and\_op}, \[189], 893, 940. +\:\\{angle}, \[106], 137, 139, 144, 145, 256, 279, 283, 527, 542, 865, 875. +\:\.{angle(0,0)...zero}, 140. +\:\9{angle\_}{\&{angle} primitive}, \[893]. +\:\\{angle\_op}, \[189], 893, 907. +\:\\{app\_lc\_hex}, \[48]. +\:\\{append\_char}, \[41], 48, 52, 58, 207, 671, 771, 780, 897, 912, 976, 977. +\:\\{append\_to\_name}, \[774], 778. +\:\\{appr\_t}, 556, \[557]. +\:\\{appr\_tt}, 556, \[557]. +\:\\{area\_delimiter}, \[768], 770, 771, 772. +\:\\{arg\_list}, 719, \[720], 721, 724, 725, 726, 728, 734, 736. +\:\\{arith\_error}, \[97], 98, 99, 100, 107, 109, 112, 114, 124, 135, 269, 270. +\:\.{Arithmetic overflow}, 99. +\:{ASCII code}, 17. +\:\9{ASCII\_}{\&{ASCII} primitive}, \[893]. +\:\\{ASCII\_code}, \[18], 19, 20, 28, 29, 30, 37, 41, 54, 58, 77, 198, 667, +771, 774, 778, 913. +\:\\{ASCII\_op}, \[189], 893, 912, 913. +\:\\{assignment}, \[186], 211, 212, 693, 733, 755, 821, 841, 868, 993, 995, +996, 1021, 1035. +\:\9{at\_}{\&{at} primitive}, \[211]. +\:\\{at\_least}, \[186], 211, 212, 882. +\:\9{at\_least\_}{\&{atleast} primitive}, \[211], \[256], \[300]. +\:\\{at\_token}, \[186], 211, 212, 1073. +\:\\{attr}, \[188], 229, 236, 239, 240, 245. +\:\\{attr\_head}, \[228], 229, 239, 241, 242, 244, 245, 246, 247, 850, 1047. +\:\\{attr\_loc}, \[229], 236, 239, 241, 244, 245, 246, 850. +\:\\{attr\_loc\_loc}, \[229], 241. +\:\\{attr\_node\_size}, \[229], 239, 241, 245, 247. +\:\\{autorounding}, \[190], 192, 193, 402. +\:\9{autorounding\_}{\&{autorounding} primitive}, \[192]. +\:\\{avail}, \[161], 163, 164, 165, 176, 177, 181, 1194, 1195. +\:\.{AVAIL list clobbered...}, 181. +\:\\{axis}, \[393], 459, 507, 517, 519. +\:\|{b}, \[124], \[126], \[321], \[391], \[429], \[431], \[433], \[440], % +\[568], \[580], \[723], \[778], \[913], \[919], \[976], \[977], \[978], % +\[1072], \[1154]. +\:\\{b\_close}, \[27], 1134, 1182. +\:\\{b\_make\_name\_string}, \[780], 791, 1134. +\:\\{b\_open\_out}, \[26], 791, 1134. +\:\\{b\_tension}, \[296]. +\:\\{back\_error}, \[653], 693, 703, 713, 726, 727, 734, 735, 747, 755, 756, +765, 820, 832, 839, 859, 861, 875, 878, 881, 990, 991, 1021, 1032, 1034, 1035, +1106, 1107, 1113. +\:\\{back\_expr}, 847, \[848]. +\:\\{back\_input}, \[652], 653, 715, 716, 733, 751, 824, 825, 837, 841, 847, +854, 862, 864, 868, 881, 1012, 1034, 1107, 1204. +\:\\{back\_list}, \[649], 652, 662, 715, 848. +\:\\{backed\_up}, \[632], 635, 636, 638, 649, 650. +\:{backpointers}, 1147. +\:\.{Backwards path...}, 1068. +\:\.{BAD}, 219. +\:\\{bad}, \[13], 14, 154, 204, 214, 310, 553, 777, 1204. +\:\.{Bad culling amounts}, 1074. +\:\.{Bad flag...}, 183. +\:\.{Bad PREVDEP...}, 617. +\:\.{Bad window number}, 1071. +\:\\{bad\_binary}, \[923], 929, 936, 940, 941, 948, 951, 952, 975, 983, 988. +\:\\{bad\_char}, \[913], 914. +\:\\{bad\_exp}, 823, \[824], 862, 864, 868. +\:\\{bad\_for}, \[754], 765. +\:\\{bad\_pool}, \[51], 52, 53. +\:\\{bad\_subscript}, 846, \[849], 861. +\:\\{bad\_unary}, 898, \[901], 903, 905, 906, 907, 909, 912, 915, 917, 921. +\:\\{bad\_vardef}, \[175], 698, 701, 702. +\:\\{balance}, \[685], 687, \[730], 731, 732. +\:\\{banner}, \[2], 61, 790, 1183. +\:\\{base}, \[374], 375, 376, \[697], 703, 704. +\:\\{base\_area\_length}, \[775], 779. +\:\\{base\_default\_length}, \[775], 777, 778, 779. +\:\\{base\_ext\_length}, \[775], 778, 779. +\:\\{base\_extension}, \[775], 784, 1200. +\:\\{base\_file}, 779, \[1188], 1189, 1191, 1199, 1200, 1201, 1211. +\:\\{base\_ident}, 34, 61, 790, \[1183], 1184, 1185, 1198, 1199, 1200, 1211. +\:\\{batch\_mode}, \[68], 70, 81, 86, 87, 88, 789, 1024, 1025, 1199, 1200. +\:\9{batch\_mode\_}{\&{batchmode} primitive}, \[1024]. +\:\\{bb}, \[286], 287, 288, 291, \[440], 444, 445, 446. +\:\\{bc}, 1088, 1089, 1091, 1093, \[1096], 1097, 1099, 1124, 1126, 1132, 1135, +1136. +\:\\{bch\_label}, \[1096], 1097, 1111, 1137, 1141. +\:\\{bchar}, \[1096], 1137, 1139. +\:\\{bchar\_label}, \[186], 211, 212, 1107. +\:\\{be\_careful}, \[107], 108, \[109], \[112], \[114], 115, \[119]. +\:\\{before}, 426, \[427], 429, 436, 439, 444, 446. +\:\\{before\_and\_after}, \[429], 434, 437, 441. +\:\&{begin}, 7, 8. +\:\\{begin\_diagnostic}, 71, \[195], 197, 254, 603, 613, 626, 721, 728, 734, +750, 762, 817, 902, 924, 945, 997, 998. +\:\\{begin\_edge\_tracing}, \[372], 465, 506. +\:\\{begin\_file\_reading}, 73, 82, \[654], 717, 793, 897. +\:\\{begin\_group}, \[186], 211, 212, 732, 823. +\:\9{begin\_group\_}{\&{begingroup} primitive}, \[211]. +\:\\{begin\_iteration}, 706, 707, \[755], 764. +\:\\{begin\_name}, 767, \[770], 781, 787. +\:\\{begin\_pseudoprint}, \[642], 644, 645. +\:\\{begin\_token\_list}, \[649], 677, 736, 760. +\:\.{Beginning to dump...}, 1200. +\:{Bernshte{\u\i}n, Serge{\u\i} Natanovich}, 303. +\:\\{beta}, \[296], \[440], 444, \[527], 528, 529, 530, 533, 536. +\:\9{Bezier}{B\'ezier, Pierre Etienne}, 255. +\:\\{bg\_loc}, 211, 698, \[699], 1198, 1199. +\:\\{big}, \[124], \[126]. +\:\\{big\_node\_size}, \[230], 231, 232, 803, 810, 857, 919, 928, 939, 966, +1005. +\:\\{big\_trans}, 952, \[966]. +\:{BigEndian order}, \[1088]. +\:\\{bilin1}, 967, \[968], 972. +\:\\{bilin2}, 970, \[972]. +\:\\{bilin3}, 973, \[974]. +\:\\{binary\_mac}, 862, \[863], 864, 868. +\:\\{bisect\_ptr}, \[309], 311, 312, 314, 553, 558, 559, 561. +\:\\{bisect\_stack}, \[309], 553. +\:\\{bistack\_size}, \[11], 309, 310, 553, 557. +\:\\{black}, \[565], 568, 577, 579, 580, 583, 584, 1143, 1144. +\:\\{blank\_line}, \[195]. +\:\\{blank\_rectangle}, 564, 566, \[567], 569, 571, 572, 574, 577. +\:\\{boc}, 1142, 1144, \[1145], 1146, 1147, 1149, 1161, 1162. +\:\\{boc\_c}, 1161, \[1162], 1165. +\:\\{boc\_p}, 1161, \[1162], 1165. +\:\\{boc1}, 1144, \[1145], 1161. +\:\\{boolean}, 26, 30, 36, 45, 47, 71, 74, 91, 97, 107, 109, 112, 114, 124, +126, 178, 180, 195, 197, 238, 246, 249, 257, 332, 406, 426, 440, 453, 455, 473, +497, 527, 564, 569, 572, 577, 592, 599, 600, 621, 661, 680, 771, 779, 782, 801, +868, 899, 913, 943, 977, 978, 1006, 1054, 1072, 1084, 1096, 1187. +\:\9{boolean\_}{\&{boolean} primitive}, \[1013]. +\:\\{boolean\_reset}, \[906], 937, 1181. +\:\\{boolean\_type}, \[187], 216, 248, 621, 798, 799, 802, 809, 855, 892, 895, +905, 906, 918, 919, 920, 936, 937, 940, 1003, 1013, 1181. +\:\\{bot}, \[1094]. +\:\\{bot\_row}, \[567], \[572], 574, 577. +\:\\{boundary\_char}, \[190], 192, 193, 1097, 1137. +\:\9{boundary\_char\_}{\&{boundarychar} primitive}, \[192]. +\:\\{break}, 33. +\:\\{break\_in}, 33. +\:\\{breakpoint}, \[1212]. +\:{Brocot, Achille}, 526. +\:\\{buf\_size}, \[11], 29, 30, 34, 66, 154, 641, 654, 667, 682, 707, 717, 779, +786, 788, 1208. +\:\\{buffer}, \[29], 30, 35, 36, 45, 66, 78, 82, 83, 205, 206, 207, 208, 210, +629, 630, 641, 644, 667, 669, 671, 673, 674, 679, 681, 682, 717, 778, 779, 781, +786, 787, 788, 794, 897, 1211, 1213. +\:\.{Buffer size exceeded}, 34. +\:\\{bypass\_eoln}, \[30]. +\:\\{byte\_file}, \[24], 26, 27, 780, 791, 1087. +\:\\{b0}, 153, \[156], 157, 214, 255, 1093, 1094, 1133, 1192, 1193. +\:\\{b1}, 153, \[156], 157, 214, 255, 1093, 1094, \[1131], 1132, 1133, 1192, +1193. +\:\\{b2}, 153, \[156], 157, 1093, 1094, \[1131], 1132, 1133, 1192, 1193. +\:\\{b3}, 153, \[156], 157, 1093, 1094, \[1131], 1132, 1133, 1192, 1193. +\:\\{b4}, \[1131], 1132. +\:\|{c}, \[47], \[77], \[189], \[210], \[217], \[391], \[440], \[491], \[527], % +\[567], \[568], \[625], \[626], \[667], \[697], \[771], \[774], \[778], \[823], +\[862], \[863], \[864], \[868], \[895], \[898], \[901], \[910], \[913], \[919], +\[922], \[923], \[930], \[953], \[960], \[962], \[963], \[966], \[985], % +\[1070], \[1072], \[1103], \[1104], \[1106], \[1165], \[1209]. +\:\\{cancel\_skips}, \[1110], 1139. +\:\.{CAPSULE}, 237. +\:\\{capsule}, \[188], 214, 219, 233, 237, 238, 619, 799, 806, 830, 856, 857, +911, 931, 982. +\:\\{capsule\_token}, \[186], 651, 676, 678, 823, 1042. +\:\\{cat}, 975, \[976]. +\:\\{cc}, \[286], 288, 289, 290, 294, 295, \[440], 444, 445, 446, \[1106]. +\:\\{cf}, \[116], 297, \[298], 299, 300, 301. +\:\\{change\_if\_limit}, \[746], 748. +\:\\{char}, 19, 25, 775, 788. +\:\9{char\_}{\&{char} primitive}, \[893]. +\:\\{char\_class}, 22, \[198], 199, 217, 223, 669, 673, 674. +\:\\{char\_code}, \[190], 192, 193, 1070. +\:\9{char\_code\_}{\&{charcode} primitive}, \[192]. +\:\\{char\_dp}, \[190], 192, 193, 1099, 1126. +\:\9{char\_dp\_}{\&{chardp} primitive}, \[192]. +\:\\{char\_dx}, \[190], 192, 193, 1099. +\:\9{char\_dx\_}{\&{chardx} primitive}, \[192]. +\:\\{char\_dy}, \[190], 192, 193, 1099. +\:\9{char\_dy\_}{\&{chardy} primitive}, \[192]. +\:\\{char\_exists}, \[1096], 1097, 1099, 1124, 1126, 1132, 1136, 1181, 1182. +\:\9{char\_exists\_}{\&{charexists} primitive}, \[893]. +\:\\{char\_exists\_op}, \[189], 893, 906. +\:\\{char\_ext}, \[190], 192, 193, 1165. +\:\9{char\_ext\_}{\&{charext} primitive}, \[192]. +\:\\{char\_ht}, \[190], 192, 193, 1099, 1126. +\:\9{char\_ht\_}{\&{charht} primitive}, \[192]. +\:\\{char\_ic}, \[190], 192, 193, 1099, 1126. +\:\9{char\_ic\_}{\&{charic} primitive}, \[192]. +\:\\{char\_info}, 1091. +\:\\{char\_info\_word}, 1089, \[1091], 1092. +\:\9{char\_list\_}{\&{charlist} primitive}, \[1101]. +\:\\{char\_list\_code}, \[1101], 1102, 1106. +\:\\{char\_loc}, 1144, \[1145], 1147, 1182. +\:\\{char\_loc0}, \[1144]. +\:\\{char\_op}, \[189], 893, 912. +\:\\{char\_ptr}, \[1149], 1163, 1165, 1182. +\:\\{char\_remainder}, \[1096], 1097, 1104, 1136, 1138. +\:\\{char\_tag}, \[1096], 1097, 1104, 1105, 1136. +\:\\{char\_wd}, \[190], 192, 193, 1099, 1124. +\:\9{char\_wd\_}{\&{charwd} primitive}, \[192]. +\:\.{Character c is already...}, 1105. +\:{character set dependencies}, 22, 49. +\:{check sum}, 53, 1090, 1131, 1146. +\:\\{check\_arith}, \[99], 269, 815, 823, 837, 895, 898, 922, 1001. +\:\\{check\_colon}, \[747], 748. +\:\\{check\_delimiter}, 703, 826, 830, \[1032]. +\:\\{check\_equals}, \[693], 694, 697. +\:\\{check\_gf}, \[1163], 1165, 1177, 1179. +\:\\{check\_interrupt}, \[91], 650, 669, 825. +\:\\{check\_mem}, 178, \[180], 617, 825, 1213. +\:\\{check\_outer\_validity}, \[661], 668, 681. +\:{Chinese characters}, 1147. +\:\\{chop\_path}, 975, \[978]. +\:\\{chop\_string}, 975, \[977]. +\:\\{chopped}, \[402], 404. +\:\\{chr}, 19, 20, 23. +\:\\{class}, \[217], 220, 221, 223, \[667], 669. +\:\\{clear\_arith}, \[99]. +\:\\{clear\_for\_error\_prompt}, 73, 78, \[656], 670, 672. +\:\\{clear\_symbol}, \[249], 252, 254, 692, 1011, 1035. +\:\\{clear\_terminal}, \[33], 656, 786. +\:\\{clear\_the\_list}, \[1117], 1124, 1126. +\:\.{CLOBBERED}, 218. +\:\\{clobbered}, \[180], 181, 182. +\:\\{clockwise}, 452, \[453], 454, 458. +\:\\{close}, 27. +\:\\{close\_files\_and\_terminate}, 73, 76, 1204, \[1205]. +\:\.{cmbase}, 1203. +\:\\{coef\_bound}, \[592], 595, 596, 598, 599, 600, 932, 943, 949. +\:\\{collective\_subscript}, \[229], 239, 241, 244, 246, 850, 1012. +\:\\{colon}, \[186], 211, 212, 747, 756, 764, 1106, 1107, 1111, 1113. +\:\\{comma}, \[186], 211, 212, 704, 725, 726, 727, 764, 826, 859, 878, 1015, +1016, 1029, 1033, 1036, 1040, 1044, 1049, 1107, 1113, 1114, 1115. +\:\\{command\_code}, \[186], 685, 694, 1072. +\:\\{common\_ending}, \[15], 865, 1071. +\:\\{compromise}, \[432], 435, 438, 443. +\:\\{concatenate}, \[189], 893, 975. +\:\\{cond\_ptr}, \[738], 739, 744, 745, 746, 748, 749, 1209. +\:\\{conditional}, 706, 707, \[748]. +\:\\{confusion}, \[90], 107, 114, 216, 236, 239, 311, 362, 378, 517, 523, 589, +655, 746, 802, 809, 855. +\:\\{const\_dependency}, \[607], 608, 969, 972, 1007. +\:\\{constant\_x}, \[406], 407, 413, 417. +\:\\{continue}, \[15], 77, 78, 79, 83, 84, 311, 314, 402, 406, 417, 447, 556, +755, 764, 862, 864, 868, 1106, 1107, 1111. +\:\\{continue\_path}, \[868], 869. +\:\9{contour\_}{\&{contour} primitive}, \[1052]. +\:\\{contour\_code}, \[403], 917, 1052, 1053. +\:\.{control?}, 258. +\:\\{controls}, \[186], 211, 212, 881. +\:\9{controls\_}{\&{controls} primitive}, \[211]. +\:\\{coord\_node\_size}, 175, \[472], 476, 481, 487. +\:{coordinates, explained}, 576. +\:\\{copied}, \[1006], 1009. +\:\\{copy\_dep\_list}, \[609], 855, 858, 947. +\:\\{copy\_edges}, \[334], 621, 855. +\:\\{copy\_knot}, \[264], 870, 885, 980, 981. +\:\\{copy\_path}, \[265], 621, 855. +\:\9{cos\_d\_}{\&{cosd} primitive}, \[893]. +\:\\{cos\_d\_op}, \[189], 893, 906. +\:\\{cosine}, \[280], 281. +\:\\{crossing\_point}, \[391], 392, 407, 411, 413, 415, 420, 424, 497, 499, +503, 545, 547, 549. +\:\\{cs}, \[1146]. +\:\\{ct}, \[116], 297, \[298], 299, 300, 301. +\:\\{cubic\_intersection}, 555, \[556], 557, 562. +\:\9{cull\_}{\&{cull} primitive}, \[211]. +\:\\{cull\_command}, \[186], 211, 212, 1069. +\:\\{cull\_edges}, \[348], 1074. +\:\\{cull\_op}, \[186], 1052, 1053, 1074. +\:\\{cur\_area}, \[767], 772, 784, 786, 793, 795. +\:\\{cur\_cmd}, 83, 186, \[624], 626, 651, 652, 658, 667, 668, 671, 675, 676, +678, 685, 686, 691, 693, 697, 700, 703, 704, 705, 706, 707, 713, 715, 718, 725, +726, 727, 731, 732, 733, 734, 735, 742, 743, 747, 755, 756, 764, 765, 796, 823, +824, 826, 832, 837, 839, 841, 844, 846, 847, 851, 852, 859, 860, 861, 862, 864, +868, 869, 874, 875, 878, 881, 882, 884, 989, 990, 991, 992, 993, 995, 996, +1011, 1012, 1015, 1016, 1017, 1021, 1029, 1032, 1033, 1034, 1035, 1036, 1040, +1041, 1042, 1044, 1049, 1051, 1062, 1072, 1074, 1106, 1107, 1111, 1113, 1114, +1115. +\:\\{cur\_edges}, \[327], 328, 329, 330, 331, 332, 333, 336, 337, 340, 341, +342, 343, 348, 352, 353, 354, 355, 356, 364, 365, 366, 367, 373, 374, 375, 376, +377, 378, 381, 382, 383, 384, 465, 577, 581, 804, 929, 963, 964, 965, 1057, +1061, 1064, 1070, 1071, 1074, 1167, 1169, 1172. +\:\\{cur\_exp}, 603, 615, 651, 713, 716, 717, 718, 726, 728, 730, 748, 750, +760, 761, 764, 765, \[796], 797, 798, 799, 800, 801, 808, 816, 819, 823, 827, +829, 830, 833, 837, 840, 841, 846, 852, 855, 856, 857, 860, 861, 863, 865, 870, +872, 875, 876, 877, 878, 879, 880, 882, 883, 885, 891, 895, 896, 897, 898, 901, +903, 905, 906, 907, 908, 910, 912, 913, 915, 916, 917, 919, 920, 921, 923, 927, +929, 930, 931, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 946, 948, 949, +951, 953, 955, 956, 962, 963, 964, 967, 968, 970, 972, 973, 976, 977, 978, 979, +984, 985, 988, 992, 994, 995, 996, 999, 1003, 1004, 1005, 1006, 1009, 1022, +1056, 1059, 1061, 1062, 1063, 1070, 1071, 1072, 1073, 1074, 1082, 1083, 1086, +1103, 1106, 1112, 1115, 1177, 1179, 1181. +\:\\{cur\_ext}, \[767], 772, 784, 786, 793, 795. +\:\\{cur\_file}, \[631], 655, 681, 793, 794. +\:\\{cur\_gran}, \[430], 431, 432, 433, 442. +\:\\{cur\_if}, \[738], 739, 744, 745, 748, 1209. +\:\\{cur\_input}, 34, 35, 82, \[628], 629, 635, 647, 648, 788. +\:\\{cur\_length}, \[40], 1163. +\:\\{cur\_min\_m}, \[1165], 1172, 1173. +\:\\{cur\_mod}, 83, \[624], 626, 651, 652, 658, 667, 668, 671, 675, 676, 678, +687, 690, 691, 694, 697, 700, 703, 705, 707, 711, 718, 726, 727, 731, 735, 742, +743, 748, 749, 751, 755, 796, 823, 824, 826, 833, 834, 835, 837, 839, 841, 846, +847, 851, 860, 861, 862, 864, 868, 990, 992, 1011, 1015, 1023, 1029, 1032, +1034, 1035, 1040, 1041, 1042, 1049, 1051, 1054, 1059, 1074, 1082, 1106, 1112, +1177, 1209. +\:\\{cur\_name}, \[767], 772, 784, 786, 793, 795. +\:\\{cur\_path\_type}, \[403], 435, 438, 442, 917, 1064, 1068. +\:\\{cur\_pen}, 402, \[403], 435, 438, 442, 506, 917, 1062, 1063, 1064, 1068. +\:\\{cur\_rounding\_ptr}, 426, \[427], 429, 433, 436, 439, 440, 444, 446. +\:\\{cur\_spec}, 394, 399, 400, 402, \[403], 404, 406, 407, 417, 419, 421, 433, +440, 447, 450, 452. +\:\\{cur\_sym}, 83, 210, 211, \[624], 651, 652, 658, 661, 662, 663, 664, 667, +668, 669, 676, 677, 683, 685, 686, 690, 691, 692, 694, 700, 703, 704, 705, 707, +718, 726, 735, 740, 751, 755, 796, 823, 824, 826, 837, 846, 847, 851, 860, 862, +864, 868, 893, 1011, 1012, 1029, 1031, 1032, 1033, 1034, 1035, 1036, 1041, +1049, 1076, 1204. +\:\\{cur\_t}, \[555], 556, 558, 559, 560, 561, 562, 988. +\:\\{cur\_tok}, \[651], 652, 685, 715, 730, 844. +\:\\{cur\_tt}, \[555], 556, 558, 559, 560, 561, 562, 988. +\:\\{cur\_type}, 603, 615, 651, 716, 718, 726, 728, 730, 760, 764, 765, \[796], +798, 799, 800, 801, 808, 816, 819, 823, 826, 827, 830, 832, 833, 837, 840, 841, +846, 852, 855, 856, 857, 860, 861, 864, 865, 870, 872, 876, 877, 878, 883, 885, +891, 892, 895, 896, 897, 898, 901, 903, 905, 906, 907, 908, 909, 910, 912, 915, +917, 918, 919, 920, 921, 923, 927, 929, 930, 931, 934, 935, 936, 937, 939, 940, +941, 942, 944, 946, 948, 951, 953, 955, 960, 962, 967, 970, 973, 975, 982, 983, +988, 989, 992, 993, 995, 996, 999, 1000, 1002, 1003, 1004, 1006, 1009, 1021, +1054, 1059, 1061, 1062, 1070, 1071, 1072, 1073, 1074, 1082, 1103, 1106, 1112, +1115, 1177, 1181. +\:\\{cur\_wt}, \[327], 372, 373, 374, 375, 376, 378, 381, 382, 383, 384, 465, +1064, 1068. +\:\\{cur\_x}, 387, 388, \[389], 390, 394, 413, 421, 445, 447, 451, 454, 457, +481, 485, 488, 489, 510, 871, 872, 873, 877, 878, 884, 984, 1072, 1073, 1074, +1075. +\:\\{cur\_y}, 387, 388, \[389], 390, 394, 413, 421, 445, 447, 451, 454, 457, +481, 485, 488, 489, 510, 871, 872, 873, 877, 878, 884, 984, 1072, 1073, 1074, +1075. +\:\\{curl}, \[256], 258, 259, 263, 271, 282, 284, 285, 290, 875, 876, 888, 889, +890, 891. +\:\9{curl\_}{\&{curl} primitive}, \[211]. +\:\\{curl\_command}, \[186], 211, 212, 875. +\:\\{curl\_ratio}, 294, 295, \[296]. +\:{curvature}, 275. +\:\.{Curve out of range}, 404. +\:\\{cycle}, \[186], 823, 869, 893, 894. +\:{cycle spec}, \[393]. +\:\.{Cycle spec at line...}, 394. +\:\9{cycle\_}{\&{cycle} primitive}, \[893]. +\:\\{cycle\_hit}, \[868], 869, 886, 891. +\:\\{cycle\_op}, \[189], 893, 920. +\:\\{c0}, \[574], 575, 576, \[1073]. +\:\\{c1}, \[574], 575, \[1073]. +\:\|{d}, \[333], \[348], \[373], \[391], \[440], \[527], \[580], \[862], % +\[864], \[868], \[944], \[1118], \[1120], \[1121], \[1128], \[1159], \[1165]. +\:{data structure assumptions}, 176. +\:\\{day}, \[190], 192, 193, 194, 790, 1163, 1200, 1211. +\:\9{day\_}{\&{day} primitive}, \[192]. +\:\\{dd}, \[286], 288, 289, \[440], 444, 445, 446. +\:{dead cubics}, \[402]. +\:\&{debug}, \[7], \[9], \[73], \[79], \[88], \[157], \[178], \[179], \[180], % +\[185], \[1212]. +\:\.{debug \#}, 1212. +\:\\{debug\_help}, 73, 79, 88, \[1212]. +\:{debugging}, 7, 79, 91, 157, 178, 1212. +\:\\{decimal}, \[189], 893, 912. +\:\9{decimal\_}{\&{decimal} primitive}, \[893]. +\:\.{Declared variable conflicts...}, 1015. +\:\\{decr}, \[16], 43, 46, 63, 66, 81, 83, 84, 86, 87, 102, 121, 123, 149, 163, +164, 177, 195, 207, 226, 291, 315, 322, 330, 331, 332, 333, 352, 364, 375, 376, +377, 382, 383, 384, 436, 439, 458, 459, 483, 487, 488, 497, 515, 516, 521, 522, +556, 560, 577, 635, 648, 650, 655, 681, 687, 731, 732, 742, 854, 862, 864, 868, +1051, 1122, 1135, 1138, 1139, 1141, 1167, 1182, 1194, 1209. +\:\9{def\_}{\&{def} primitive}, \[683]. +\:\\{def\_delims}, 1030, \[1031]. +\:\\{def\_ref}, \[720], 721, 736. +\:\\{defined\_macro}, \[186], 249, 700, 706, 707, 718, 1035, 1041, 1043. +\:\\{del}, \[406], 407, 408, 413, \[419], 420, \[453], 454. +\:\\{del\_m}, \[1144]. +\:\\{del\_n}, \[1144]. +\:\\{delete\_mac\_ref}, \[226], 249, 650, 809. +\:\\{delete\_pen\_ref}, \[487], 808, 809, 1062, 1063. +\:\\{delete\_str\_ref}, \[43], 216, 691, 743, 808, 809, 976, 977, 1042, 1083. +\:\\{deletions\_allowed}, \[71], 72, 79, 80, 93, 661, 670, 672, 675. +\:\\{delimiters}, \[186], 211, 212, 1030. +\:\9{delimiters\_}{\&{delimiters} primitive}, \[211]. +\:\\{delta}, \[103], \[279], 281, 288, \[328], \[329], 330, 331, \[342], 343, % +\[366], 367, \[378], 381, 382, 383, 384, \[527], 530, 531, 533, 534, 535, % +\[968], \[974], \[1165], 1173, 1174. +\:\\{delta\_a}, \[426]. +\:\\{delta\_b}, \[426]. +\:\\{delta\_x}, \[279], 281, 292, 293, 299, 301, 302. +\:\\{delta\_y}, \[279], 281, 292, 293, 299, 301, 302. +\:\\{delx}, \[280], 282, \[374], 375, 376, \[511], 516, 522, 552, 553, 556, % +\[557], 558, 559, 560, 561. +\:\\{dely}, \[280], 282, \[374], 375, 376, \[511], 516, 522, 552, 553, 556, % +\[557], 558, 559, 560, 561. +\:\\{del1}, \[406], 407, 408, 409, 413, 414, \[419], 420, 421, 423. +\:\\{del2}, \[406], 407, 408, 409, 411, 413, 414, 415, \[419], 420, 421, 423, +424. +\:\\{del3}, \[406], 407, 408, 409, 411, 413, 414, 415, \[419], 420, 421, 423, +424. +\:\\{denom}, \[116], \[296], \[836], 837. +\:\\{dep\_div}, 948, \[949]. +\:\\{dep\_final}, \[592], 594, 597, 601, 606, 607, 608, 609, 615, 818, 819, +829, 855, 856, 858, 971, 972, 1007. +\:\\{dep\_finish}, 934, \[935], 943, 949. +\:\\{dep\_head}, \[175], 587, 588, 604, 606, 614, 617, 812, 1050. +\:\\{dep\_list}, 585, \[587], 604, 605, 606, 614, 617, 798, 799, 801, 803, 811, +812, 816, 818, 819, 827, 855, 858, 903, 930, 931, 932, 935, 943, 947, 949, 959, +968, 969, 971, 972, 1007, 1009, 1050. +\:\\{dep\_mult}, 942, \[943], 944, 946, 968. +\:\\{dep\_node\_size}, \[587], 595, 596, 597, 598, 599, 600, 601, 603, 605, +607, 608, 609, 612, 615, 616, 818, 819, 829, 1008. +\:\\{dependent}, \[187], 216, 248, 585, 587, 588, 589, 590, 594, 595, 596, 597, +599, 600, 601, 603, 610, 612, 613, 615, 798, 799, 800, 801, 802, 808, 809, 812, +813, 815, 816, 817, 818, 819, 829, 855, 857, 858, 900, 903, 930, 932, 943, 949, +969, 1003, 1006, 1007, 1009, 1010, 1050. +\:\\{depth\_index}, \[1091]. +\:{design size}, 1146. +\:\\{design\_size}, \[190], 192, 193, 1128, 1129, 1182. +\:\9{design\_size\_}{\&{designsize} primitive}, \[192]. +\:\\{dest\_x}, \[406], 407, 409, 411, 412, 413, 415, 416, \[419], 421, 423, +424, 425. +\:\\{dest\_y}, \[406], 407, 411, 412, 413, 414, 415, 416, \[419], 421, 423, +424, 425. +\:\\{diag\_offset}, \[442], 443. +\:\\{diag\_round}, 402, \[440]. +\:\\{diagonal}, \[393], 459, 507, 508, 509, 519, 523. +\:\\{dig}, \[54], 63, 64, 102, 674. +\:\\{digit\_class}, \[198], 199, 220, 669, 673, 674. +\:\\{dimen\_head}, 1124, \[1125], 1126, 1136. +\:\\{dimen\_out}, \[1129], 1132, 1136, 1139, 1140. +\:\9{direction\_time\_}{\&{directiontime} primitive}, \[893]. +\:\\{direction\_time\_of}, \[189], 893, 983. +\:{dirty \PASCAL}, \[3], 157, 185, 1203. +\:\\{discard\_suffixes}, \[246]. +\:\\{disp\_edges}, \[577], 1071. +\:\\{disp\_err}, 716, 754, \[807], 873, 923, 937, 955, 1002. +\:\\{disp\_token}, \[1041], 1043, 1044, 1049. +\:\\{disp\_var}, \[1046], 1047, 1049. +\:\9{display\_}{\&{display} primitive}, \[211]. +\:\\{display\_command}, \[186], 211, 212, 1069. +\:\&{div}, \[95]. +\:\.{Division by zero}, 838, 950. +\:\\{dm}, \[1144]. +\:\\{dmax}, 404, \[406], 408, \[419], \[453], 457. +\:\\{do\_add\_to}, 1058, \[1059]. +\:\\{do\_assignment}, 993, 995, \[996]. +\:\\{do\_binary}, 834, 837, 839, 859, 862, 864, 868, 893, \[922], 966. +\:\\{do\_cull}, 1069, \[1074]. +\:\\{do\_display}, 1069, \[1071]. +\:\\{do\_equation}, 993, \[995], 996. +\:\\{do\_expression}, 996. +\:\\{do\_interim}, 1033, \[1034]. +\:\\{do\_let}, 1033, \[1035]. +\:\\{do\_message}, 1081, \[1082]. +\:\\{do\_new\_internal}, 1033, \[1036]. +\:\\{do\_nothing}, \[16], 33, 57, 58, 79, 146, 216, 223, 249, 669, 707, 794, +808, 809, 919, 957, 1003, 1035. +\:\\{do\_nullary}, 834, 893, \[895]. +\:\\{do\_open\_window}, 1069, \[1073]. +\:\\{do\_protection}, 1026, \[1029]. +\:\\{do\_random\_seed}, 1020, \[1021]. +\:\\{do\_ship\_out}, 1069, \[1070]. +\:\\{do\_show}, \[1040], 1051. +\:\\{do\_show\_dependencies}, \[1050], 1051, 1213. +\:\\{do\_show\_stats}, \[1045], 1051. +\:\\{do\_show\_token}, \[1044], 1051. +\:\\{do\_show\_var}, 1046, \[1049], 1051. +\:\\{do\_show\_whatever}, 1039, \[1051]. +\:\\{do\_special}, 1175, \[1177]. +\:\\{do\_statement}, 832, \[989], 992, 1017, 1020, 1034. +\:\\{do\_tfm\_command}, 1100, \[1106]. +\:\\{do\_type\_declaration}, 992, \[1015]. +\:\\{do\_unary}, 834, 835, 893, \[898]. +\:\\{done}, \[15], 47, 53, 124, 125, 126, 127, 177, 257, 269, 272, 311, 317, +344, 345, 346, 347, 348, 349, 354, 358, 366, 368, 374, 375, 378, 381, 382, 383, +384, 394, 402, 452, 458, 477, 479, 488, 491, 502, 506, 512, 518, 527, 531, 532, +539, 546, 547, 548, 577, 578, 584, 594, 597, 604, 605, 609, 635, 650, 667, 673, +685, 687, 730, 731, 732, 742, 748, 749, 755, 764, 765, 781, 786, 787, 793, 809, +812, 823, 835, 837, 839, 840, 841, 852, 860, 868, 881, 919, 922, 930, 932, 936, +953, 955, 957, 958, 959, 1001, 1003, 1004, 1005, 1006, 1007, 1011, 1012, 1049, +1059, 1068, 1106, 1107, 1110, 1165, 1172, 1173. +\:\\{done1}, \[15], 180, 181, 257, 258, 261, 374, 376, 477, 481, 506, 516, 518, +522, 527, 536, 823, 844, 922, 939, 1006, 1009. +\:\\{done2}, \[15], 180, 182, 823, 850. +\:\\{done3}, \[15]. +\:\\{done4}, \[15]. +\:\\{done5}, \[15]. +\:\\{done6}, \[15]. +\:\\{double}, \[16], 108, 115, 123, 132, 142, 143, 392, 408, 457, 496, 543, +556, 559. +\:\.{Double-AVAIL list clobbered...}, 182. +\:\\{double\_colon}, \[186], 211, 212, 1107. +\:\\{double\_dot}, \[189]. +\:\9{double\_path\_}{\&{doublepath} primitive}, \[1052]. +\:\\{double\_path\_code}, \[403], 435, 438, 442, 1052, 1053, 1059, 1064, 1068. +\:\.{Doubly free location...}, 182. +\:\\{drop\_code}, \[1052], 1053, 1074, 1075. +\:\9{dropping\_}{\&{dropping} primitive}, \[1052]. +\:{dry rot}, 90. +\:\\{ds}, \[1146]. +\:\\{du}, \[495], \[497], 498. +\:\\{dual\_moves}, 512, \[518]. +\:\.{dump...only by INIMF}, 1209. +\:\9{dump\_}{\&{dump} primitive}, \[1018]. +\:\\{dump\_four\_ASCII}, \[1192]. +\:\\{dump\_hh}, \[1188], 1196. +\:\\{dump\_int}, \[1188], 1190, 1192, 1194, 1196, 1198. +\:\\{dump\_qqqq}, \[1188], 1192. +\:\\{dump\_wd}, \[1188], 1194. +\:\\{dup\_offset}, \[476], 483. +\:\\{dv}, \[495], \[497], 498. +\:\\{dw}, \[357], 358. +\:\\{dx}, \[378], 380, 381, 382, 383, 384, \[477], 479, 480, 494, \[495], 501, +502, 1144, 1147. +\:\\{dx1}, \[453], 454, 457. +\:\\{dx2}, \[453], 454, 457. +\:\\{dy}, \[477], 479, 480, \[495], 501, 502, 1144, 1147. +\:\\{dyn\_used}, \[160], 163, 164, 165, 176, 177, 1045, 1194, 1195. +\:\\{dy1}, \[453], 454, 457. +\:\\{dy2}, \[453], 454, 457. +\:\\{d0}, \[464], 467, 468, 508, 517, 523. +\:\\{d1}, 463, \[464], 467, 468, 508, 517, 523. +\:\|{e}, \[773], \[774], \[786], \[1071], \[1074]. +\:\\{east\_edge}, \[435]. +\:\\{east\_west\_edge}, \[435]. +\:\\{ec}, 1088, 1089, 1091, 1093, \[1096], 1097, 1099, 1124, 1126, 1132, 1135, +1136. +\:\\{edge\_and\_weight}, \[378], 381, 382, 383, 384. +\:\\{edge\_header\_size}, \[326], 334, 385, 895, 964. +\:\\{edge\_prep}, \[329], 366, 375, 376, 380. +\:\\{edges\_trans}, 952, \[963]. +\:\\{ee}, \[286], 288, 289. +\:\\{eg\_loc}, 211, 698, \[699], 1198, 1199. +\:\\{eight\_bits}, \[24], 63, 624, 1096, 1103, 1131, 1149, 1152, 1163, 1165. +\:\\{eighth\_octant}, \[139], 141, 380, 387, 388, 390, 396, 426, 443, 449, 461, +462. +\:\\{el\_gordo}, \[95], 100, 107, 109, 112, 114, 124, 135, 235, 244, 917, 1118, +1140. +\:\&{else}, 10. +\:\9{else\_}{\&{else} primitive}, \[740]. +\:\\{else\_code}, \[738], 740, 741. +\:\9{else\_if\_}{\&{elseif} primitive}, \[740]. +\:\\{else\_if\_code}, \[738], 740, 748. +\:\.{Emergency stop}, 88. +\:\\{empty\_edges}, \[326], 329, 963. +\:\\{empty\_flag}, \[166], 168, 172, 176, 1207. +\:\\{encapsulate}, 855, \[856]. +\:\&{end}, 7, 8, 10. +\:\.{end occurred...}, 1209. +\:\.{End of file on the terminal}, 36, 66. +\:\9{end\_}{\&{end} primitive}, \[1018]. +\:\\{end\_attr}, \[175], 229, 239, 247, 1047. +\:\\{end\_cycle}, \[272], 281, 282, 284, 287. +\:\\{end\_def}, \[683], 992. +\:\9{end\_def\_}{\&{enddef} primitive}, \[683]. +\:\\{end\_diagnostic}, \[195], 254, 257, 332, 372, 394, 473, 603, 613, 626, +721, 728, 734, 750, 762, 817, 902, 924, 945, 997, 998. +\:\\{end\_edge\_tracing}, \[372], 465, 506. +\:\\{end\_file\_reading}, \[655], 656, 679, 681, 714, 793, 897, 1209. +\:\\{end\_for}, \[683], 707. +\:\9{end\_for\_}{\&{endfor} primitive}, \[683]. +\:\\{end\_group}, \[186], 211, 212, 732, 832, 991, 992, 993, 1017. +\:\9{end\_input\_}{\&{endinput} primitive}, \[709]. +\:\\{end\_name}, 767, \[772], 781, 787. +\:\\{end\_of\_MF}, \[6], 76, 1204. +\:\\{end\_of\_statement}, \[186], 732, 991, 1015, 1016. +\:\\{end\_round}, \[463], 464, 467, 508. +\:\\{end\_token\_list}, \[650], 652, 676, 712, 714, 736, 795, 1209. +\:\&{endcases}, \[10]. +\:\9{endgroup\_}{\&{endgroup} primitive}, \[211]. +\:\\{endpoint}, \[255], 256, 257, 258, 266, 273, 393, 394, 398, 399, 400, 401, +402, 451, 452, 457, 465, 466, 491, 506, 512, 518, 539, 562, 563, 865, 868, 870, +871, 885, 891, 916, 917, 920, 921, 962, 978, 979, 985, 987, 1064. +\:\.{Enormous chardp...}, 1098. +\:\.{Enormous charht...}, 1098. +\:\.{Enormous charic...}, 1098. +\:\.{Enormous charwd...}, 1098. +\:\.{Enormous designsize...}, 1098. +\:\.{Enormous number...}, 675. +\:\.{entering the nth octant}, 394. +\:\\{env\_move}, \[507], 513, 514, 515, 516, 517, 519, 520, 521, 522, 523. +\:\\{eoc}, 1142, 1144, \[1145], 1146, 1149, 1165. +\:\\{eof}, 25, 30, 52, 1199. +\:\\{eoln}, 30, 52. +\:\\{eq\_type}, \[200], 202, 203, 210, 211, 213, 229, 242, 249, 254, 668, 694, +700, 702, 759, 850, 1011, 1029, 1031, 1035, 1036, 1041, 1213. +\:\\{eqtb}, 158, 200, \[201], 202, 210, 211, 212, 213, 249, 250, 252, 254, 625, +632, 683, 740, 893, 1196, 1197. +\:\\{equal\_to}, \[189], 893, 936, 937. +\:\\{equals}, \[186], 693, 733, 755, 868, 893, 894, 993, 995, 996, 1035. +\:\.{Equation cannot be performed}, 1002. +\:\\{equiv}, \[200], 202, 209, 210, 211, 213, 229, 234, 239, 242, 249, 254, +664, 668, 694, 700, 702, 850, 1011, 1015, 1030, 1031, 1035, 1036, 1213. +\:\\{err\_help}, \[74], 75, 85, 1083, 1086. +\:\9{err\_help\_}{\&{errhelp} primitive}, \[1079]. +\:\\{err\_help\_code}, \[1079], 1082. +\:\9{err\_message\_}{\&{errmessage} primitive}, \[1079]. +\:\\{err\_message\_code}, \[1079], 1080, 1082. +\:\\{error}, 67, 70, 71, 73, 74, \[77], 83, 88, 93, 99, 122, 128, 134, 140, +602, 653, 670, 672, 675, 701, 708, 712, 713, 725, 751, 778, 789, 795, 820, 838, +996, 1032, 1051, 1110. +\:\\{error\_count}, \[71], 72, 77, 81, 989, 1051. +\:\\{error\_line}, \[11], 14, 54, 58, 635, 641, 642, 643, 665. +\:\\{error\_message\_issued}, \[71], 77, 90. +\:\\{error\_stop\_mode}, 67, \[68], 69, 77, 88, 93, 398, 807, 1024, 1051, 1086, +1199, 1209. +\:\9{error\_stop\_mode\_}{\&{errorstopmode} primitive}, \[1024]. +\:\\{erstat}, \[26]. +\:\\{eta\_corr}, 306, \[311], 313, 314, 317. +\:\.{ETC}, 217, 227. +\:\9{every\_job\_}{\&{everyjob} primitive}, \[211]. +\:\\{every\_job\_command}, \[186], 211, 212, 1076. +\:\\{excess}, \[1119], 1120, 1122. +\:\\{exit}, \[15], 16, 36, 46, 47, 77, 117, 167, 217, 227, 235, 242, 246, 265, +266, 284, 311, 391, 406, 488, 497, 539, 556, 562, 589, 622, 667, 746, 748, 760, +779, 868, 899, 904, 922, 928, 930, 943, 949, 953, 962, 963, 966, 1032, 1070, +1071, 1073, 1074, 1131, 1161, 1187, 1209, 1212. +\:\9{exit\_if\_}{\&{exitif} primitive}, \[211]. +\:\\{exit\_test}, \[186], 211, 212, 706, 707. +\:\\{exp\_err}, \[807], 830, 849, 872, 876, 878, 883, 892, 901, 914, 923, 937, +950, 960, 993, 996, 999, 1002, 1021, 1055, 1060, 1061, 1062, 1071, 1082, 1103, +1106, 1112, 1115, 1178. +\:\\{expand}, \[707], 715, 718. +\:\\{expand\_after}, \[186], 211, 212, 706, 707. +\:\9{expand\_after\_}{\&{expandafter} primitive}, \[211]. +\:\\{explicit}, \[256], 258, 261, 262, 266, 271, 273, 280, 282, 299, 302, 393, +407, 486, 563, 874, 880, 884, 1066. +\:\.{EXPR}, 222. +\:\9{expr\_}{\&{expr} primitive}, \[695]. +\:\\{expr\_base}, \[214], 218, 222, 676, 683, 684, 694, 695, 696, 697, 703, +705, 725, 727, 755, 764. +\:\\{expr\_macro}, \[226], 227, 705, 733. +\:\\{expression\_binary}, \[186], 893, 894. +\:\\{expression\_tertiary\_macro}, \[186], 249, 683, 868, 1035, 1043. +\:\\{ext\_bot}, \[1094], 1113. +\:\\{ext\_delimiter}, \[768], 770, 771, 772. +\:\\{ext\_mid}, \[1094], 1113. +\:\\{ext\_rep}, \[1094], 1113. +\:\\{ext\_tag}, \[1092], 1096, 1105, 1113. +\:\\{ext\_top}, \[1094], 1113. +\:\\{exten}, \[1092], 1094, \[1096], 1140. +\:\9{extensible\_}{\&{extensible} primitive}, \[1101]. +\:\\{extensible\_code}, \[1101], 1102, 1106. +\:\\{extensible\_recipe}, 1089, \[1094]. +\:{extensions to \MF}, 2. +\:\.{Extra `endfor'}, 708. +\:\.{Extra `endgroup'}, 1017. +\:\.{Extra else}, 751. +\:\.{Extra elseif}, 751. +\:\.{Extra fi}, 751. +\:\.{Extra tokens will be flushed}, 991. +\:\\{extra\_space}, 1095. +\:\\{extra\_space\_code}, \[1095]. +\:\\{extras}, 362, \[363]. +\:\|{f}, \[26], \[27], \[30], \[107], \[109], \[112], \[114], \[398], \[594], % +\[667], \[780], \[1165]. +\:\\{false}, 26, 30, 36, 45, 47, 51, 71, 75, 83, 84, 93, 98, 99, 107, 110, 114, +124, 126, 179, 180, 181, 182, 254, 269, 270, 407, 426, 446, 452, 454, 455, 456, +474, 497, 503, 505, 530, 564, 570, 573, 577, 592, 593, 600, 603, 604, 613, 626, +653, 657, 661, 670, 672, 675, 680, 681, 692, 721, 728, 734, 750, 762, 767, 771, +779, 783, 794, 801, 804, 817, 825, 869, 899, 902, 913, 924, 944, 945, 977, 978, +997, 998, 1003, 1009, 1010, 1011, 1015, 1035, 1045, 1054, 1064, 1072, 1085, +1086, 1097, 1107, 1137, 1138, 1187. +\:\9{false\_}{\&{false} primitive}, \[893]. +\:\\{false\_code}, \[189], 798, 892, 893, 895, 905, 906, 918, 919, 920, 937, +940. +\:\\{fast\_case\_down}, \[378], 380. +\:\\{fast\_case\_up}, \[378], 380. +\:\\{fast\_get\_avail}, \[165], 381, 382, 383, 384, 651, 844. +\:\.{Fatal base file error}, 1187. +\:\\{fatal\_error}, 66, \[88], 679, 714, 786, 789, 897. +\:\\{fatal\_error\_stop}, \[71], 72, 77, 88, 1204. +\:\\{ff}, \[286], 287, 289, 290, 295, \[296], 302. +\:\9{fi\_}{\&{fi} primitive}, \[740]. +\:\\{fi\_code}, \[738], 740, 741, 742, 748, 749, 751. +\:\\{fi\_or\_else}, \[186], 706, 707, 738, 740, 741, 742, 751, 1209. +\:\\{fifth\_octant}, \[139], 141, 380, 387, 388, 390, 396, 426, 443, 449, 461, +462. +\:\.{File ended while scanning...}, 663. +\:\.{File names can't...}, 795. +\:\\{file\_name\_size}, \[11], 25, 774, 777, 778, 780. +\:\\{file\_offset}, \[54], 55, 57, 58, 62, 333, 372, 793, 1048, 1165. +\:\\{file\_ptr}, 79, 80, \[634], 635, 636, 637. +\:\\{file\_state}, \[632], 635, 636, 656, 667, 714, 795. +\:\\{fill\_envelope}, 481, \[506], 518, 1064. +\:\\{fill\_spec}, \[465], 506, 511, 1064. +\:\\{fillin}, \[190], 192, 193, 525, 533. +\:\9{fillin\_}{\&{fillin} primitive}, \[192]. +\:\\{fin\_numeric\_token}, \[667], 669, 673. +\:\\{fin\_offset\_prep}, \[497], 503, 504, 505. +\:\\{final\_cleanup}, 1204, \[1209]. +\:\\{final\_end}, \[6], 34, 657, 1204, 1211. +\:\\{final\_node}, \[610], 612, 615. +\:\\{final\_value}, \[752], 761, 765. +\:\\{find\_direction\_time}, \[539], 540, 984. +\:\\{find\_edges\_var}, \[1057], 1061, 1064, 1070, 1071, 1074. +\:\\{find\_offset}, \[488], 984. +\:\\{find\_point}, 983, \[985]. +\:\\{find\_variable}, \[242], 700, 852, 1000, 1015, 1057. +\:\\{finish\_path}, \[868], 869, 874. +\:\\{firm\_up\_the\_line}, 666, 681, \[682], 794. +\:\\{first}, \[29], 30, 34, 35, 36, 66, 78, 82, 83, 654, 655, 657, 679, 681, +682, 717, 787, 794. +\:\\{first\_count}, \[54], 641, 642, 643. +\:\\{first\_octant}, \[139], 141, 378, 379, 380, 387, 388, 390, 395, 396, 406, +407, 409, 411, 426, 435, 443, 448, 449, 461, 462, 473, 480, 484, 488, 489. +\:\\{first\_text\_char}, \[19], 23. +\:\\{first\_x}, \[406], 407, \[440], 444, 445. +\:\\{first\_y}, \[406], 407, \[440], 444, 445. +\:\\{fix\_check\_sum}, \[1131], 1206. +\:\\{fix\_date\_and\_time}, \[194], 1204, 1211. +\:\\{fix\_dependencies}, \[604], 610, 815, 935, 968, 971. +\:\\{fix\_design\_size}, \[1128], 1206. +\:\\{fix\_needed}, \[592], 593, 595, 596, 598, 599, 600, 604, 610, 815, 932, +935, 968, 971. +\:\\{fix\_offset}, \[328], 329, 965. +\:\\{fix\_word}, \[1089], 1090, 1095, 1129, 1147. +\:\9{floor\_}{\&{floor} primitive}, \[893]. +\:\\{floor\_op}, \[189], 893, 906. +\:\\{floor\_scaled}, \[119], 516, 522, 906. +\:\\{floor\_unscaled}, \[119], 306, 463, 513, 515, 516, 519, 521, 522, 1074. +\:\\{flush\_below\_variable}, 246, \[247], 249. +\:\\{flush\_cur\_exp}, 717, \[808], 820, 872, 907, 913, 915, 917, 918, 919, +920, 921, 935, 936, 938, 956, 962, 982, 984, 993, 1040, 1061, 1063, 1070, 1072, +1082, 1177. +\:\\{flush\_error}, \[820], 849, 1017. +\:\\{flush\_list}, \[177], 385, 700, 736, 1015. +\:\\{flush\_node\_list}, \[177], 685, 811, 815, 852, 996, 1009, 1057. +\:\\{flush\_p}, \[621]. +\:\\{flush\_string}, \[43], 210, 793, 1200. +\:\\{flush\_token\_list}, \[216], 224, 226, 235, 650, 698, 763, 840, 1062, +1071, 1074. +\:\\{flush\_variable}, \[246], 700, 1015. +\:\\{flushing}, \[659], 664, 665, 991, 1016. +\:\.{font metric dimensions...}, 1140. +\:{font metric files}, 1087. +\:\.{Font metrics written...}, 1134. +\:\9{font\_dimen\_}{\&{fontdimen} primitive}, \[1101]. +\:\\{font\_dimen\_code}, \[1101], 1106. +\:\\{fontmaking}, \[190], 192, 193, 1206. +\:\9{fontmaking\_}{\&{fontmaking} primitive}, \[192]. +\:\9{for\_}{\&{for} primitive}, \[683]. +\:\9{for\_suffixes\_}{\&{forsuffixes} primitive}, \[683]. +\:\.{Forbidden token found...}, 663. +\:\\{force\_eof}, 657, \[680], 681, 711. +\:\9{forever\_}{\&{forever} primitive}, \[683]. +\:\\{forever\_text}, \[632], 638, 714, 760. +\:\\{forty\_five\_deg}, \[106], 145. +\:\\{forward}, 73, 216, 217, 224, 225, 666, 706, 820, 995, 1034. +\:\\{found}, \[15], 167, 170, 171, 205, 206, 207, 235, 236, 284, 291, 292, 295, +477, 527, 532, 539, 541, 543, 544, 547, 548, 577, 582, 667, 669, 685, 686, 720, +726, 748, 755, 779, 1103, 1117. +\:\\{found1}, \[15]. +\:\\{found2}, \[15]. +\:\\{four\_quarters}, \[156], 1096, 1133, 1186, 1187. +\:\\{fourth\_octant}, \[139], 141, 380, 387, 388, 390, 393, 396, 426, 435, 443, +449, 461, 462, 472. +\:\\{frac\_mult}, 837, \[944]. +\:\\{fraction}, \[105], 107, 109, 114, 116, 119, 124, 126, 144, 145, 148, 149, +150, 187, 259, 280, 283, 286, 296, 298, 299, 391, 406, 410, 419, 433, 440, 493, +495, 497, 542, 585, 587, 591, 592, 594, 599, 612, 932, 944. +\:\\{fraction\_four}, \[105], 111, 113, 116, 121, 123, 125, 126, 127, 132, 133, +296, 1116. +\:\\{fraction\_half}, \[105], 111, 152, 288, 408, 496, 543, 1098, 1128, 1140. +\:\\{fraction\_one}, \[105], 107, 108, 109, 142, 145, 148, 149, 150, 285, 288, +290, 291, 295, 300, 311, 391, 392, 402, 407, 411, 413, 415, 420, 424, 436, 439, +444, 457, 477, 478, 497, 499, 503, 530, 540, 547, 549, 599, 603, 612, 615, 816, +917, 1169, 1170. +\:\\{fraction\_three}, \[105], 116, 288, 296. +\:\\{fraction\_threshold}, \[594], 597. +\:\\{fraction\_two}, \[105], 116, 121, 124, 142. +\:\\{free}, \[178], 180, 181, 182, 183, 184. +\:\\{free\_avail}, \[164], 177, 216, 254, 349, 360, 604, 760, 763, 852, 860. +\:\\{free\_node}, \[172], 177, 216, 246, 247, 249, 254, 268, 352, 353, 354, +358, 385, 405, 452, 487, 532, 537, 595, 598, 599, 600, 601, 603, 605, 612, 615, +616, 650, 745, 763, 800, 808, 810, 818, 819, 827, 829, 837, 855, 858, 866, 890, +903, 910, 922, 925, 942, 944, 947, 955, 970, 980, 1001, 1006, 1008, 1065, 1209. +\:\9{from\_}{\&{from} primitive}, \[211]. +\:\\{from\_token}, \[186], 211, 212, 1073. +\:\\{frozen\_bad\_vardef}, \[201], 203, 702. +\:\\{frozen\_colon}, \[201], 203, 211, 751. +\:\\{frozen\_end\_def}, \[201], 203, 664, 683. +\:\\{frozen\_end\_for}, \[201], 203, 664, 683. +\:\\{frozen\_end\_group}, \[201], 203, 211, 664, 698. +\:\\{frozen\_fi}, \[201], 203, 661, 740. +\:\\{frozen\_inaccessible}, \[201], 203, 691, 1196, 1197, 1199. +\:\\{frozen\_left\_bracket}, \[201], 203, 211, 847. +\:\\{frozen\_repeat\_loop}, \[201], 757, 758, 759. +\:\\{frozen\_right\_delimiter}, \[201], 203, 664. +\:\\{frozen\_semicolon}, \[201], 203, 211, 664. +\:\\{frozen\_slash}, \[201], 203, 837, 893. +\:\\{frozen\_undefined}, \[201], 249. +\:{Fuchs, David Raymond}, 2, 1148. +\:\\{future\_pen}, \[187], 216, 248, 798, 802, 804, 808, 809, 855, 864, 865, +896, 918, 919, 921, 952, 962, 983. +\:\|{g}, \[47]. +\:\\{g\_pointer}, 216, 219, 224, \[225], 1042. +\:\\{gamma}, \[296], \[527], 528, 529, 530. +\:\\{general\_macro}, \[226], 227, 694, 697, 725. +\:\\{get}, 25, 28, 30, 32, 794, 1189. +\:\\{get\_avail}, \[163], 165, 235, 236, 250, 335, 350, 362, 375, 376, 605, +662, 694, 697, 698, 704, 728, 734, 758, 764, 841, 845, 853, 854, 860, 863, 1011. +\:\\{get\_boolean}, 706, 713, 748, \[892]. +\:\\{get\_clear\_symbol}, \[692], 694, 700, 1031, 1036. +\:\\{get\_code}, \[1103], 1106, 1107, 1110, 1112, 1113, 1114. +\:\\{get\_next}, 71, 73, 83, 624, 658, 659, 666, \[667], 676, 679, 685, 690, +691, 694, 700, 703, 704, 705, 706, 715, 718, 720, 730, 742, 781, 991, 1016, +1044, 1049. +\:\\{get\_node}, \[167], 173, 215, 232, 233, 234, 239, 240, 241, 244, 245, 252, +253, 264, 265, 266, 330, 331, 334, 341, 355, 364, 410, 451, 476, 477, 481, 486, +528, 535, 536, 537, 596, 597, 607, 608, 609, 619, 651, 694, 704, 705, 744, 755, +765, 799, 830, 856, 857, 871, 895, 896, 931, 964, 982, 1117. +\:\\{get\_pair}, \[1072], 1073, 1074. +\:\\{get\_strings\_started}, \[47], 51, 1204. +\:\\{get\_symbol}, \[691], 692, 694, 704, 705, 755, 757, 1011, 1029, 1033, +1035, 1076. +\:\\{get\_x\_next}, 694, 697, 706, 707, 716, \[718], 726, 729, 733, 734, 735, +748, 751, 752, 755, 764, 765, 799, 800, 820, 823, 824, 825, 826, 830, 835, 837, +839, 840, 841, 844, 846, 850, 851, 853, 854, 859, 860, 861, 862, 864, 868, 874, +875, 876, 878, 881, 882, 884, 886, 892, 989, 990, 995, 996, 1011, 1012, 1021, +1023, 1029, 1031, 1033, 1034, 1035, 1036, 1040, 1044, 1045, 1049, 1050, 1054, +1059, 1070, 1071, 1072, 1073, 1074, 1076, 1082, 1103, 1106, 1107, 1112, 1115, +1177. +\:\\{gf\_boc}, \[1161], 1162, 1168, 1172. +\:\\{gf\_buf}, 1151, \[1152], 1154, 1155. +\:\\{gf\_buf\_size}, \[11], 14, 1151, 1152, 1153, 1155, 1156, 1182. +\:\\{gf\_dx}, 1099, \[1149], 1182. +\:\\{gf\_dy}, 1099, \[1149], 1182. +\:\\{gf\_ext}, \[785], 791, 1164. +\:\\{gf\_file}, \[791], 1149, 1151, 1154, 1182. +\:\\{gf\_four}, \[1157], 1161, 1166, 1177, 1182. +\:\\{gf\_id\_byte}, \[1144], 1163, 1182. +\:\\{gf\_index}, \[1151], 1152, 1154. +\:\\{gf\_limit}, 1151, \[1152], 1153, 1155, 1156. +\:\\{gf\_max\_m}, \[1149], 1163, 1168, 1169, 1182. +\:\\{gf\_max\_n}, \[1149], 1161, 1163, 1182. +\:\\{gf\_min\_m}, \[1149], 1161, 1163, 1182. +\:\\{gf\_min\_n}, \[1149], 1163, 1167, 1168, 1182. +\:\\{gf\_offset}, 1151, \[1152], 1153, 1155, 1163, 1165, 1182. +\:\\{gf\_out}, \[1155], 1157, 1158, 1159, 1160, 1161, 1163, 1165, 1166, 1173, +1174, 1177, 1182. +\:\\{gf\_paint}, \[1159], 1170, 1171, 1172. +\:\\{gf\_prev\_ptr}, \[1149], 1150, 1163, 1165, 1182, 1206. +\:\\{gf\_ptr}, 1151, \[1152], 1153, 1155, 1156, 1163, 1165, 1182. +\:\\{gf\_string}, \[1160], 1163, 1166, 1177, 1179. +\:\\{gf\_swap}, \[1155]. +\:\\{gf\_three}, \[1158], 1160. +\:\\{gf\_two}, \[1158], 1159, 1174. +\:\\{given}, \[256], 258, 259, 273, 282, 284, 285, 875, 877, 888, 889. +\:\\{good\_val}, \[431], 432, 435, 438, 442. +\:\&{goto}, \[34], \[76]. +\:\\{granularity}, \[190], 192, 193, 430, 433. +\:\9{granularity\_}{\&{granularity} primitive}, \[192]. +\:\\{greater\_or\_equal}, \[189], 893, 936, 937. +\:\\{greater\_than}, \[189], 893, 936, 937. +\:\\{group\_line}, \[831], 832. +\:\&{gubed}, \[7]. +\:{Guibas, Leonidas Ioannis}, 2, 469. +\:\|{h}, \[205], \[257], \[269], \[326], \[334], \[344], \[346], \[366], % +\[369], \[385], \[402], \[465], \[473], \[477], \[484], \[488], \[491], \[506], +\[518], \[527], \[539], \[562], \[860], \[1011]. +\:\\{half}, \[96], 102, 111, 113, 121, 126, 133, 142, 150, 232, 313, 314, 317, +392, 432, 442, 445, 556, 559, 561, 596, 866, 939, 1122. +\:\\{half\_buf}, 1151, \[1152], 1153, 1155, 1156. +\:\\{half\_error\_line}, \[11], 14, 635, 641, 642, 643. +\:\\{half\_fraction\_threshold}, \[594], 599, 600, 612, 616. +\:\\{half\_scaled\_threshold}, \[594], 599, 600. +\:\\{half\_unit}, \[101], 113, 119, 374, 402, 462, 463, 468, 477, 478, 512, +515, 518, 521, 528, 530, 533, 917, 1106. +\:\\{halfword}, 153, \[156], 158, 172, 210, 246, 253, 284, 329, 346, 366, 491, +497, 624, 627, 697, 755, 862, 864, 868, 1029, 1077, 1104. +\:\\{hard\_times}, 941, \[946]. +\:\\{hash}, 200, \[201], 202, 205, 207, 625, 658, 1196, 1197. +\:\\{hash\_base}, \[200], 201, 205. +\:\\{hash\_end}, \[201], 202, 204, 209, 214, 229, 250, 253, 254, 699, 841, 996, +998, 999, 1049, 1196, 1197, 1199. +\:\\{hash\_is\_full}, \[200], 207. +\:\\{hash\_prime}, \[12], 14, 205, 208, 1190, 1191. +\:\\{hash\_size}, \[12], 14, 201, 207, 208, 1190, 1191, 1208. +\:\\{hash\_top}, \[201]. +\:\\{hash\_used}, \[200], 203, 207, 1196, 1197. +\:\\{header}, 1090. +\:\\{header\_byte}, \[1096], 1097, 1106, 1114, 1128, 1131, 1135, 1182. +\:\9{header\_byte\_}{\&{headerbyte} primitive}, \[1101]. +\:\\{header\_byte\_code}, \[1101], 1102, 1106. +\:\\{header\_size}, \[11], 14, 1096, 1097, 1114, 1135. +\:{Hedrick, Charles Locke}, 3. +\:\\{height\_index}, \[1091]. +\:\\{help\_line}, \[74], 84, 86, 661, 664, 691, 852, 1016, 1055. +\:\\{help\_ptr}, \[74], 75, 84, 86. +\:\\{help0}, \[74], 1051. +\:\\{help1}, \[74], 88, 90, 703, 713, 734, 751, 838, 839, 876, 881, 883, 914, +937, 1021, 1034, 1051, 1056, 1071, 1074, 1082, 1086, 1098, 1106, 1107, 1110, +1113, 1115, 1178. +\:\\{help2}, 67, \[74], 83, 84, 89, 90, 122, 128, 134, 140, 270, 478, 623, 670, +675, 701, 708, 712, 713, 716, 727, 735, 747, 765, 832, 865, 878, 892, 937, 950, +996, 999, 1002, 1004, 1008, 1015, 1017, 1021, 1032, 1055, 1057, 1061, 1062, +1067, 1073, 1103, 1105, 1106, 1112. +\:\\{help3}, 67, \[74], 93, 340, 342, 478, 661, 672, 691, 725, 726, 727, 755, +756, 795, 849, 859, 861, 875, 887, 901, 923, 955, 960, 963, 965, 993, 1032, +1035, 1068. +\:\\{help4}, \[74], 84, 99, 404, 602, 663, 754, 824, 830, 1060, 1086. +\:\\{help5}, \[74], 693, 851, 872, 873, 878, 990, 1016. +\:\\{help6}, \[74], 991. +\:\.{Here is how much...}, 1208. +\:\9{hex\_}{\&{hex} primitive}, \[893]. +\:\\{hex\_op}, \[189], 893, 912. +\:\\{hh}, 153, \[156], 157, 161, 214, 250, 255, \[334], \[477], 479, \[562], +563, 1188, 1189. +\:\\{hi\_mem\_min}, \[159], 161, 163, 167, 168, 176, 177, 178, 180, 181, 184, +185, 216, 218, 242, 676, 850, 1045, 1194, 1195, 1207, 1208. +\:\\{hi\_mem\_stat\_min}, \[175], 176, 1195. +\:\\{history}, \[71], 72, 77, 88, 90, 195, 1204, 1209. +\:\\{hlp1}, \[74]. +\:\\{hlp2}, \[74]. +\:\\{hlp3}, \[74]. +\:\\{hlp4}, \[74]. +\:\\{hlp5}, \[74]. +\:\\{hlp6}, \[74]. +\:\\{ho}, \[155], 324, 333, 343, 344, 349, 352, 358, 359, 360, 370, 373, 582, +1169. +\:{Hobby, John Douglas}, 274, 354, 432, 524. +\:\\{hold\_head}, \[175], 665, 685, 697, 730. +\:\\{hppp}, \[190], 192, 193, 785, \[1146], 1164, 1182. +\:\9{hppp\_}{\&{hppp} primitive}, \[192]. +\:\\{htap\_ypoc}, \[266], 921, 978, 1064, 1065. +\:\|{i}, \[19], \[150], \[641]. +\:\.{I can't find file x}, 786. +\:\.{I can't find PLAIN...}, 779. +\:\.{I can't go on...}, 90. +\:\.{I can't read MF.POOL}, 51. +\:\.{I can't write on file x}, 786. +\:\\{id\_lookup}, \[205], 210, 669. +\:\\{id\_transform}, \[233], 955. +\:\9{if\_}{\&{if} primitive}, \[740]. +\:\\{if\_code}, \[738], 740, 741, 744, 751. +\:\\{if\_limit}, \[738], 739, 744, 745, 746, 748, 751. +\:\\{if\_line}, \[738], 739, 744, 745, 748, 1209. +\:\\{if\_line\_field}, \[738], 744, 745, 1209. +\:\\{if\_node\_size}, \[738], 744, 745, 1209. +\:\\{if\_test}, \[186], 706, 707, 740, 741, 742, 748. +\:\.{illegal design size...}, 1128. +\:\.{Illegal ligtable step}, 1107. +\:\.{Illegal suffix...flushed}, 1016. +\:\.{IMPOSSIBLE}, 218. +\:\.{Improper `:='}, 996. +\:\.{Improper `addto'}, 1061, 1062. +\:\.{Improper `openwindow'}, 1073. +\:\.{Improper curl}, 876. +\:\.{Improper font parameter}, 1115. +\:\.{Improper kern}, 1112. +\:\.{Improper location}, 1106. +\:\.{Improper subscript...}, 849. +\:\.{Improper tension}, 883. +\:\.{Improper transformation argument}, 955. +\:\.{Improper type}, 1055. +\:\.{Improper...replaced by 0}, 754. +\:\\{in\_open}, \[631], 654, 655, 657. +\:\\{in\_state\_record}, \[627], 628. +\:\\{in\_window}, \[186], 211, 212, 1071. +\:\9{in\_window\_}{\&{inwindow} primitive}, \[211]. +\:\.{Incomplete if...}, 661. +\:\.{Incomplete string token...}, 672. +\:\.{Inconsistent equation}, 1004, 1008. +\:\\{incr}, \[16], 30, 36, 41, 42, 44, 45, 46, 53, 58, 59, 60, 64, 66, 77, 85, +86, 93, 108, 115, 123, 136, 143, 147, 163, 165, 183, 207, 226, 281, 284, 297, +314, 315, 317, 319, 320, 321, 322, 333, 348, 352, 362, 364, 366, 375, 376, 377, +381, 382, 383, 384, 404, 429, 458, 459, 481, 483, 487, 497, 502, 514, 515, 516, +520, 521, 522, 560, 568, 574, 577, 583, 584, 647, 654, 669, 671, 673, 674, 681, +687, 704, 705, 717, 721, 724, 728, 731, 732, 734, 736, 737, 742, 772, 774, 779, +781, 787, 793, 1036, 1104, 1107, 1112, 1113, 1114, 1115, 1118, 1121, 1129, +1137, 1138, 1140, 1155, 1165, 1196, 1211. +\:\\{independent}, \[187], 216, 219, 232, 248, 585, 589, 592, 604, 615, 798, +799, 800, 801, 802, 803, 808, 809, 816, 827, 828, 855, 857, 858, 903, 918, 925, +926, 927, 928, 944, 1003, 1006, 1007, 1009. +\:\\{independent\_being\_fixed}, \[605]. +\:\\{independent\_needing\_fix}, \[592], 595, 596, 598, 599, 600. +\:\\{index}, 627, \[629], 630, 631, 632, 654, 655, 657. +\:\\{index\_field}, \[627], 629. +\:\\{inf\_val}, \[175], 617, 1116, 1117, 1118, 1121, 1136. +\:\\{info}, \[161], 166, 168, 176, 185, 214, 218, 221, 226, 227, 228, 229, 235, +236, 242, 245, 246, 250, 252, 253, 254, 324, 325, 326, 328, 333, 335, 337, 338, +339, 342, 343, 344, 345, 346, 347, 349, 350, 351, 358, 359, 360, 362, 366, 367, +368, 370, 373, 375, 376, 378, 381, 382, 383, 384, 472, 473, 475, 481, 484, 488, +491, 509, 512, 519, 580, 582, 587, 589, 591, 594, 595, 596, 597, 598, 599, 600, +601, 604, 605, 607, 608, 609, 610, 611, 612, 614, 615, 616, 617, 651, 662, 676, +685, 686, 694, 697, 698, 700, 704, 705, 714, 719, 721, 722, 725, 726, 727, 728, +729, 733, 734, 736, 752, 755, 758, 760, 763, 764, 805, 811, 812, 816, 818, 819, +841, 850, 853, 854, 860, 863, 904, 931, 933, 935, 968, 996, 998, 999, 1006, +1007, 1010, 1011, 1015, 1050, 1121, 1122, 1127, 1136, 1169, 1207, 1213. +\:\.{INIMF}, 8, 11, 12, 47, 50, 159, 1183, 1203. +\:\&{init}, \[8], \[47], \[50], \[173], \[210], \[564], \[567], \[568], % +\[1186], \[1204], \[1209], \[1210]. +\:\\{init\_big\_node}, \[232], 233, 830, 857, 982. +\:\\{init\_edges}, \[326], 353, 364, 895, 964. +\:\\{init\_gf}, \[1163]. +\:\\{init\_pool\_ptr}, \[38], 41, 1045, 1193, 1204, 1208. +\:\\{init\_prim}, 1204, \[1210]. +\:\\{init\_randoms}, \[150], 1022, 1211. +\:\\{init\_screen}, \[564], 567, 568, 569, 570, 571. +\:\\{init\_str\_ptr}, \[38], 44, 772, 1045, 1193, 1204, 1208. +\:\\{init\_tab}, 1204, \[1210]. +\:\\{init\_terminal}, \[36], 657. +\:\\{initialize}, \[4], 1204, 1211. +\:{inner loop}, 30, 107, 108, 109, 111, 112, 113, 163, 165, 167, 169, 172, 177, +242, 244, 408, 650, 651, 667, 668, 669, 676, 718, 850. +\:\9{inner\_}{\&{inner} primitive}, \[1027]. +\:\\{input}, \[186], 706, 707, 709, 710. +\:\9{input\_}{\&{input} primitive}, \[709]. +\:\\{input\_file}, \[631]. +\:\\{input\_ln}, 29, \[30], 36, 58, 66, 681, 794. +\:\\{input\_ptr}, \[628], 635, 636, 647, 648, 656, 657, 679, 788, 1209. +\:\\{input\_stack}, 79, \[628], 635, 647, 648, 788. +\:\\{ins\_error}, \[653], 661, 663, 691, 751, 824. +\:\.{insert>}, 82. +\:\\{inserted}, \[632], 638, 650, 653. +\:\\{install}, 857, \[858], 957, 959. +\:\\{int}, 153, \[156], 157, 214, 326, 435, 738, 1188, 1189, 1191. +\:\\{int\_increment}, \[553], 559, 561. +\:\\{int\_name}, \[190], 193, 254, 998, 999, 1036, 1043, 1098, 1123, 1198, 1199. +\:\\{int\_packets}, \[553], 558, 560. +\:\\{int\_ptr}, \[190], 191, 1036, 1198, 1199, 1208. +\:\\{integer}, 13, 19, 45, 46, 47, 54, 59, 60, 64, 65, 77, 89, 91, 100, 101, +102, 105, 106, 107, 109, 112, 114, 116, 117, 119, 121, 124, 126, 129, 130, 132, +135, 139, 145, 152, 153, 156, 160, 167, 185, 200, 205, 217, 227, 242, 299, 308, +309, 311, 321, 327, 328, 329, 332, 333, 337, 340, 342, 348, 354, 357, 363, 366, +369, 371, 373, 374, 378, 391, 398, 402, 403, 453, 464, 473, 477, 484, 488, 495, +497, 507, 511, 527, 555, 557, 562, 572, 574, 577, 580, 585, 589, 594, 597, 599, +600, 601, 608, 610, 621, 624, 625, 626, 631, 633, 641, 651, 659, 667, 685, 707, +720, 723, 730, 738, 742, 773, 774, 778, 788, 796, 801, 809, 813, 831, 895, 898, +899, 900, 913, 922, 930, 943, 977, 1001, 1059, 1070, 1073, 1074, 1096, 1103, +1106, 1118, 1119, 1120, 1121, 1129, 1130, 1131, 1133, 1149, 1152, 1157, 1158, +1159, 1160, 1161, 1162, 1163, 1165, 1186, 1187, 1203, 1205, 1210, 1212. +\:\\{interaction}, 66, 67, \[68], 69, 70, 77, 79, 81, 86, 87, 88, 93, 398, 679, +682, 786, 807, 897, 1023, 1051, 1086, 1198, 1199, 1200, 1209. +\:\\{interesting}, \[238], 603, 613, 817, 1050. +\:\9{interim\_}{\&{interim} primitive}, \[211]. +\:\\{interim\_command}, \[186], 211, 212, 1033. +\:\\{internal}, \[190], 191, 194, 195, 238, 253, 254, 269, 375, 376, 381, 382, +383, 384, 402, 430, 433, 465, 468, 477, 506, 508, 510, 515, 517, 521, 523, 533, +602, 603, 610, 682, 707, 713, 720, 728, 734, 748, 760, 790, 804, 816, 832, 841, +895, 898, 922, 944, 992, 994, 995, 996, 999, 1036, 1051, 1064, 1068, 1070, +1097, 1098, 1099, 1128, 1129, 1134, 1137, 1163, 1164, 1165, 1177, 1182, 1198, +1199, 1200, 1205, 1206, 1211, 1213. +\:\.{Internal quantity...}, 999. +\:\\{internal\_quantity}, \[186], 192, 823, 844, 860, 1011, 1034, 1036, 1043. +\:\\{interrupt}, \[91], 92, 93, 825. +\:\.{Interruption}, 93. +\:\\{intersect}, \[189], 893, 988. +\:\9{intersection\_times\_}{\&{intersectiontimes} primitive}, \[893]. +\:\.{Invalid code...}, 1103. +\:\\{invalid\_class}, \[198], 199, 669. +\:\\{is\_empty}, \[166], 169, 182, 183. +\:\.{Isolated expression}, 993. +\:\\{isolated\_classes}, \[198], 223, 669. +\:\\{italic\_index}, \[1091]. +\:\\{iteration}, \[186], 683, 684, 685, 706, 707, 758. +\:\|{j}, \[45], \[46], \[59], \[60], \[77], \[150], \[205], \[210], \[357], % +\[378], \[707], \[774], \[778], \[779], \[1106]. +\:\\{j\_random}, \[148], 149, 151, 152. +\:{Japanese characters}, 1147. +\:{Jensen, Kathleen}, 10. +\:\\{jj}, \[150], \[357], 364. +\:\.{job aborted}, 679. +\:\.{job aborted, file error...}, 786. +\:\\{job\_name}, 87, \[782], 783, 784, 788, 791, 793, 895, 1134, 1200, 1209. +\:\9{job\_name\_}{\&{jobname} primitive}, \[893]. +\:\\{job\_name\_op}, \[189], 893, 895. +\:\\{jump\_out}, \[76], 77, 79, 88. +\:\|{k}, \[45], \[46], \[47], \[63], \[64], \[66], \[102], \[121], \[130], % +\[132], \[135], \[139], \[145], \[149], \[150], \[205], \[210], \[264], \[280], +\[284], \[299], \[321], \[346], \[363], \[366], \[378], \[402], \[426], \[440], +\[473], \[477], \[484], \[487], \[491], \[497], \[511], \[568], \[574], \[577], +\[667], \[682], \[697], \[707], \[774], \[778], \[780], \[786], \[788], \[895], +\[913], \[976], \[977], \[978], \[1073], \[1106], \[1131], \[1154], \[1160], % +\[1163], \[1186], \[1187], \[1205], \[1210], \[1212]. +\:\\{keep\_code}, \[1052], 1074. +\:\\{keeping}, \[1074], 1075. +\:\9{keeping\_}{\&{keeping} primitive}, \[1052]. +\:\\{kern}, 1093, \[1096], 1106, 1112, 1139. +\:\9{kern\_}{\&{kern} primitive}, \[1108]. +\:\\{kern\_flag}, \[1093], 1112. +\:\\{knil}, \[325], 326, 330, 331, 332, 334, 336, 341, 352, 354, 355, 364, 376, +377, 382, 384, 442, 472, 473, 475, 476, 482, 483, 484, 497, 503, 505, 508, 509, +513, 515, 517, 519, 521, 523, 1167. +\:\\{knot\_node\_size}, \[255], 264, 265, 266, 268, 405, 410, 451, 452, 486, +528, 532, 535, 536, 537, 866, 871, 890, 896, 980, 1065. +\:\\{knots}, \[269], 271, 272. +\:\\{known}, \[187], 214, 215, 216, 219, 233, 248, 585, 594, 603, 615, 651, +678, 726, 760, 765, 798, 799, 802, 803, 808, 809, 823, 826, 827, 829, 830, 837, +841, 846, 855, 857, 858, 861, 873, 876, 878, 883, 895, 899, 903, 906, 912, 915, +918, 919, 930, 931, 932, 935, 937, 939, 941, 942, 943, 944, 948, 949, 951, 953, +956, 957, 959, 960, 966, 968, 969, 970, 971, 972, 974, 982, 983, 999, 1003, +1006, 1007, 1009, 1021, 1052, 1054, 1062, 1071, 1073, 1074, 1103, 1106, 1112, +1115, 1176, 1177, 1180. +\:\9{known\_}{\&{known} primitive}, \[893]. +\:\\{known\_op}, \[189], 893, 918, 919. +\:\\{known\_pair}, 871, \[872], 877, 884. +\:{Knuth, Donald Ervin}, 2, 81. +\:\|{l}, \[46], \[47], \[152], \[205], \[210], \[217], \[227], \[311], \[641], % +\[742], \[746], \[788], \[977], \[978], \[1006], \[1011], \[1035], \[1118], % +\[1121], \[1160], \[1212]. +\:\\{l\_delim}, \[697], 703, \[720], 726, 727, 729, \[730], 731, 735, \[823], +826, 830, \[1031], \[1032]. +\:\\{l\_packet}, 560. +\:\\{l\_packets}, \[553], 559. +\:\\{label\_char}, \[1096], 1104, 1137, 1138. +\:\\{label\_loc}, \[1096], 1097, 1104, 1137, 1138, 1139. +\:\\{label\_ptr}, \[1096], 1097, 1104, 1137, 1138, 1139. +\:{Lane, Jeffrey Michael}, 303. +\:\\{last}, \[29], 30, 34, 35, 36, 66, 78, 82, 83, 657, 679, 682, 779, 787, 897. +\:\\{last\_nonblank}, \[30]. +\:\\{last\_text\_char}, \[19], 23. +\:\\{last\_window}, \[326], 334, 577. +\:\\{last\_window\_time}, \[326], 334, 336, 337, 340, 342, 344, 348, 364, 577, +965. +\:\\{left\_brace}, \[186], 211, 212, 874. +\:\\{left\_bracket}, \[186], 211, 212, 823, 844, 847, 860, 1011, 1012. +\:\\{left\_bracket\_class}, \[198], 199, 220, 221. +\:\\{left\_col}, \[567], \[572], 574, 577, 581. +\:\\{left\_curl}, \[256], 259, 263, 271, 282, 295, 879, 890, 891. +\:\\{left\_delimiter}, \[186], 697, 703, 726, 731, 735, 823, 1030, 1031, 1043. +\:\\{left\_given}, \[256], 259, 263, 282, 292, 301, 879, 880, 888. +\:\\{left\_length}, \[528], 531, 532, 534, 535. +\:\\{left\_octant}, \[393], 394, 398, 401, 451, 452, 458, 459, 465, 506. +\:\\{left\_tension}, \[256], 258, 260, 288, 289, 294, 295, 299, 300, 302, 880. +\:\\{left\_transition}, \[393], 459, 508. +\:\\{left\_type}, \[255], 256, 257, 258, 259, 261, 262, 263, 265, 266, 269, +271, 272, 273, 281, 282, 284, 285, 287, 299, 302, 393, 394, 397, 398, 399, 400, +401, 402, 404, 410, 451, 452, 465, 486, 506, 528, 865, 870, 871, 879, 885, 887, +888, 890, 891, 896, 916, 917, 920, 962, 978, 979, 985, 987, 1064, 1066. +\:\\{left\_v}, \[528], 531, 534, 535. +\:\\{left\_x}, \[255], 256, 261, 265, 266, 271, 282, 299, 302, 393, 397, 404, +407, 409, 410, 411, 412, 415, 416, 418, 419, 421, 423, 424, 425, 434, 436, 441, +444, 447, 451, 457, 468, 486, 492, 496, 512, 518, 528, 543, 558, 563, 866, 880, +887, 896, 962, 987, 1066. +\:\\{left\_y}, \[255], 256, 261, 265, 266, 271, 282, 299, 302, 393, 397, 404, +409, 410, 413, 414, 415, 416, 419, 423, 424, 425, 437, 439, 444, 447, 451, 457, +468, 486, 492, 496, 512, 518, 528, 543, 558, 563, 866, 880, 887, 896, 962, 987, +1066. +\:\\{length}, \[39], 46, 205, 671, 716, 717, 793, 912, 913, 915, 976, 977, +1083, 1103, 1160. +\:\9{length\_}{\&{length} primitive}, \[893]. +\:\\{length\_op}, \[189], 893, 915. +\:\\{less\_or\_equal}, \[189], 893, 936, 937. +\:\\{less\_than}, \[189], 893, 936, 937. +\:\9{let\_}{\&{let} primitive}, \[211]. +\:\\{let\_command}, \[186], 211, 212, 1033. +\:\\{letter\_class}, \[198], 199, 218, 223. +\:\\{lf}, 1088. +\:\\{lh}, 153, \[156], 157, 161, 200, \[491], 502, 505, 1088, 1089, 1135, % +\[1205]. +\:\\{lhs}, \[995], \[996], 997, 998, 999, 1000, \[1001], 1002, 1003, \[1059], +1061, 1062, 1064. +\:\\{lig\_kern}, 1092, 1093, \[1096], 1137, 1139, 1205. +\:\\{lig\_kern\_command}, 1089, \[1093]. +\:\\{lig\_kern\_token}, \[186], 1107, 1108, 1109. +\:\9{lig\_table\_}{\&{ligtable} primitive}, \[1101]. +\:\\{lig\_table\_code}, \[1101], 1102, 1106. +\:\\{lig\_table\_size}, \[11], 14, 1096, 1107, 1137, 1141. +\:\\{lig\_tag}, \[1092], 1104, 1105, 1111. +\:\\{limit}, 627, \[629], 630, 632, 644, 654, 656, 657, 669, 671, 672, 679, +681, 682, 717, 793, 794, 1211. +\:\\{limit\_field}, 34, 82, \[627], 629, 788. +\:\\{line}, 79, 197, \[631], 637, 654, 655, 657, 681, 742, 744, 748, 794, 832. +\:\\{line\_edges}, \[374], 378, 507, 510. +\:\\{line\_stack}, \[631], 654, 655. +\:\\{linear\_eq}, \[610], 1006. +\:\\{link}, \[161], 163, 164, 165, 166, 167, 168, 172, 176, 177, 181, 185, 216, +217, 227, 228, 229, 230, 232, 234, 235, 236, 237, 238, 239, 240, 241, 242, 244, +245, 246, 247, 250, 252, 253, 254, 255, 257, 265, 266, 268, 271, 272, 273, 281, +284, 297, 324, 325, 326, 328, 330, 331, 332, 334, 335, 336, 337, 338, 339, 341, +343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 359, 360, 362, +364, 366, 367, 368, 369, 370, 375, 376, 377, 381, 382, 383, 384, 385, 394, 398, +399, 400, 401, 402, 404, 405, 406, 410, 411, 412, 413, 415, 416, 418, 419, 424, +425, 433, 435, 436, 439, 440, 442, 444, 447, 450, 451, 452, 458, 459, 465, 466, +468, 472, 473, 475, 476, 477, 479, 481, 482, 483, 484, 485, 487, 488, 491, 492, +493, 497, 499, 502, 503, 504, 506, 508, 509, 512, 513, 515, 517, 518, 519, 521, +523, 528, 532, 535, 536, 537, 539, 556, 558, 562, 577, 582, 587, 589, 591, 594, +595, 596, 597, 598, 599, 600, 601, 603, 604, 605, 606, 608, 609, 611, 612, 614, +616, 617, 639, 640, 650, 651, 665, 676, 678, 685, 686, 694, 697, 698, 700, 702, +704, 705, 719, 720, 721, 722, 723, 724, 725, 727, 728, 730, 734, 736, 738, 744, +745, 746, 752, 758, 760, 762, 763, 764, 799, 805, 811, 812, 814, 815, 816, 818, +819, 827, 844, 845, 848, 850, 851, 852, 853, 854, 860, 863, 867, 870, 871, 885, +887, 890, 891, 896, 904, 910, 916, 921, 931, 933, 947, 962, 968, 978, 980, 981, +985, 986, 1007, 1010, 1011, 1015, 1043, 1047, 1050, 1065, 1068, 1117, 1118, +1121, 1122, 1124, 1126, 1136, 1169, 1194, 1207, 1209, 1213. +\:\\{list\_tag}, \[1092], 1105, 1106. +\:\\{lk\_offset}, 1135, 1137, 1138, 1139, \[1205]. +\:\\{lk\_started}, \[1096], 1107, 1112, 1137, 1138, 1139. +\:\\{ll}, \[1096], 1110, 1111, 1139. +\:\\{llink}, \[166], 168, 169, 171, 172, 173, 176, 182, 1207. +\:\\{lll}, \[1096], 1110, 1111. +\:\\{lo\_mem\_max}, \[159], 163, 167, 168, 176, 178, 180, 182, 183, 184, 185, +1045, 1194, 1195, 1207, 1208. +\:\\{lo\_mem\_stat\_max}, \[175], 176, 1195, 1207. +\:\\{load\_base\_file}, \[1187], 1211. +\:\\{loc}, \[35], 36, 82, 627, \[629], 630, 632, 636, 638, 644, 645, 649, 652, +654, 656, 657, 669, 671, 672, 673, 674, 676, 678, 679, 681, 712, 717, 736, 779, +781, 793, 794, 795, 1211. +\:\\{loc\_field}, 34, 35, \[627], 629. +\:\.{local label l:: was missing}, 1139. +\:\\{log\_file}, \[54], 56, 70, 788, 1205. +\:\\{log\_name}, \[782], 788, 1205. +\:\\{log\_only}, \[54], 57, 58, 62, 70, 93, 679, 788, 1022, 1200. +\:\\{log\_opened}, 87, 88, \[782], 783, 788, 789, 1023, 1205, 1208. +\:\.{Logarithm...replaced by 0}, 134. +\:\\{long\_help\_seen}, \[1084], 1085, 1086. +\:\&{loop}, 15, \[16]. +\:\.{loop confusion}, 714. +\:\.{loop value=n}, 762. +\:\\{loop\_defining}, \[659], 664, 665, 758. +\:\\{loop\_list}, \[752], 760, 763, 764. +\:\\{loop\_list\_loc}, \[752], 764. +\:\\{loop\_node\_size}, \[752], 755, 763. +\:\\{loop\_ptr}, 712, 713, 714, \[752], 753, 758, 760, 763, 1209. +\:\\{loop\_repeat}, 685. +\:\\{loop\_text}, \[632], 638, 714, 760. +\:\\{loop\_type}, \[752], 755, 760, 763, 764, 765. +\:\.{Lost loop}, 712. +\:\\{ls}, \[46]. +\:\\{lt}, \[46], \[286], 289, 294, 295, \[299], 302. +\:\|{m}, \[47], \[64], \[311], \[333], \[337], \[348], \[357], \[369], \[373], % +\[473], \[484], \[511], \[574], \[580], \[608], \[625], \[626], \[641], \[694], +\[697], \[755], \[788], \[913], \[1029], \[1082], \[1098], \[1118], \[1120], % +\[1121], \[1123], \[1165], \[1177], \[1212]. +\:\\{m\_adjustment}, \[580], 581, 582. +\:\\{m\_exp}, \[135], 906. +\:\9{m\_exp\_}{\&{mexp} primitive}, \[893]. +\:\\{m\_exp\_op}, \[189], 893, 906. +\:\\{m\_log}, \[132], 134, 152, 906. +\:\9{m\_log\_}{\&{mlog} primitive}, \[893]. +\:\\{m\_log\_op}, \[189], 893, 906. +\:\\{m\_magic}, \[354], 361, 362, 365. +\:\\{m\_max}, \[326], 329, 334, 337, 342, 348, 352, 354, 356, 357, 364, 366, +965, 1172. +\:\\{m\_min}, \[326], 329, 334, 337, 342, 348, 352, 354, 356, 357, 364, 365, +366, 965, 1172. +\:\\{m\_offset}, \[326], 328, 329, 333, 334, 337, 342, 348, 352, 364, 365, 366, +367, 373, 375, 376, 381, 382, 383, 384, 581, 965, 1169, 1172. +\:\\{m\_spread}, 356, \[357], 364. +\:\\{m\_window}, \[572], 576, 581. +\:\\{mac\_name}, \[862], \[864], \[868]. +\:\\{macro}, \[632], 638, 645, 649, 736. +\:\\{macro\_at}, \[688], 689. +\:\\{macro\_call}, 707, 718, 719, \[720], 853, 854, 863. +\:\\{macro\_def}, \[186], 683, 684, 685, 694, 698, 992, 1043. +\:\\{macro\_name}, \[720], 721, 725, 726, 734, 736. +\:\\{macro\_prefix}, \[688], 689. +\:\\{macro\_ref}, \[843], 845, 854. +\:\\{macro\_special}, \[186], 685, 688, 689, 700. +\:\\{macro\_suffix}, \[688], 689, 700. +\:\\{main\_control}, \[1017], 1204, 1211. +\:\\{major\_axis}, \[527], 530, 533, \[865], 866. +\:\\{make\_choices}, \[269], 274, 277, 278, 891. +\:\\{make\_ellipse}, \[527], 528, 866. +\:\\{make\_eq}, 995, 1000, \[1001]. +\:\\{make\_exp\_copy}, 651, 823, 852, \[855], 859, 903, 910, 926, 927, 944, +967, 970, 973, 1000. +\:\\{make\_fraction}, \[107], 109, 116, 125, 127, 145, 152, 281, 288, 289, 290, +291, 294, 295, 296, 300, 302, 375, 376, 436, 439, 444, 454, 498, 516, 522, 530, +533, 540, 548, 549, 612, 818, 944. +\:\\{make\_known}, \[603], 604, 614, 818, 819. +\:\\{make\_moves}, 309, \[311], 321, 468, 512, 514, 518, 550. +\:\\{make\_name\_string}, \[780]. +\:\\{make\_op\_def}, \[694], 992. +\:\\{make\_path}, \[484], 921, 962. +\:\9{make\_path\_}{\&{makepath} primitive}, \[893]. +\:\\{make\_path\_op}, \[189], 893, 921. +\:\\{make\_pen}, \[477], 865. +\:\9{make\_pen\_}{\&{makepen} primitive}, \[893]. +\:\\{make\_pen\_op}, \[189], 893, 921. +\:\\{make\_safe}, \[426], 427, 436, 439, 440, 446. +\:\\{make\_scaled}, \[114], 116, 600, 612, 819, 837, 948, 949, 980, 1128, 1129, +1164, 1182. +\:\\{make\_spec}, \[402], 403, 409, 448, 460, 493, 917, 1064. +\:\\{make\_string}, \[44], 48, 52, 207, 671, 772, 780, 840, 897, 912, 976, 977, +1164, 1200, 1205. +\:{Marple, Jane}, 1086. +\:\\{materialize\_pen}, 864, \[865], 921, 983. +\:\\{max}, \[539], 543. +\:\\{max\_allowed}, 402, \[403], 404, 434, 437. +\:\\{max\_buf\_stack}, \[29], 30, 657, 717, 1208. +\:\\{max\_c}, 812, \[813], 814, 815, 816, 817. +\:\\{max\_class}, \[198]. +\:\\{max\_coef}, \[495], 496, \[591], 932, 943, 949. +\:\\{max\_command\_code}, \[186], 821, 823, 824, 868. +\:\\{max\_d}, \[348], 351, 352. +\:\\{max\_expression\_command}, \[186], 868. +\:\\{max\_font\_dimen}, \[11], 1096, 1115, 1141. +\:\\{max\_given\_internal}, \[190], 191, 1199. +\:\\{max\_halfword}, 11, 12, 14, \[153], 154, 156, 166, 167, 168, 173, 174, +204, 214, 324, 348, 351, 358, 1207. +\:\\{max\_in\_open}, \[12], 631, 632, 654, 1190, 1191. +\:\\{max\_in\_stack}, \[628], 647, 657, 1208. +\:\\{max\_internal}, \[11], 190, 204, 1036, 1199, 1208. +\:\\{max\_kerns}, \[11], 1096, 1106, 1112, 1141. +\:\\{max\_link}, 812, \[813], 814, 815, 818, 819. +\:\\{max\_m}, 1144, \[1146], \[1161]. +\:\\{max\_n}, \[348], 351, 352, 1144, \[1146], \[1161]. +\:\\{max\_new\_row}, \[1145], 1173. +\:\\{max\_offset}, \[472], 475, 477, 962, 1064. +\:\\{max\_param\_stack}, \[633], 657, 736, 737, 1208. +\:\\{max\_patience}, \[555], 556. +\:\\{max\_pool\_ptr}, \[38], 41, 47, 1045, 1193, 1204, 1208. +\:\\{max\_primary\_command}, \[186], 823, 836, 862, 864, 868, 989, 990. +\:\\{max\_print\_line}, \[11], 14, 54, 58, 61, 67, 333, 372, 793, 1046, 1048, +1165. +\:\\{max\_ptr}, \[813], 814, 815, 816. +\:\\{max\_quarterword}, \[153], 154, 156, 399, 404, 481. +\:\\{max\_rounding\_ptr}, \[427], 428, 429, 1208. +\:\\{max\_secondary\_command}, \[186], 862. +\:\\{max\_selector}, \[54], 196, 635, 788. +\:\\{max\_statement\_command}, \[186], 989. +\:\\{max\_str\_ptr}, \[38], 44, 47, 772, 1045, 1193, 1204, 1208. +\:\\{max\_str\_ref}, \[42], 43, 48, 52, 207, 793, 1193, 1200. +\:\\{max\_strings}, \[11], 37, 44, 154, 772, 780, 1045, 1193, 1208. +\:\\{max\_suffix\_token}, \[186], 844. +\:\\{max\_t}, \[555], 556. +\:\\{max\_tertiary\_command}, \[186], 864. +\:\\{max\_tfm\_dimen}, 1128, 1129, \[1130], 1182. +\:\\{max\_wiggle}, \[11], 426, 427, 429, 440, 1208. +\:\\{mc}, \[477], 478, 479. +\:{Meggitt, John E.}, 143. +\:\\{mem}, 11, 12, 158, \[159], 161, 166, 168, 173, 175, 176, 178, 180, 185, +214, 216, 229, 241, 242, 244, 250, 255, 264, 326, 334, 435, 472, 475, 587, 594, +738, 752, 827, 947, 961, 1194, 1195, 1213. +\:\\{mem\_end}, 159, \[161], 163, 176, 178, 180, 181, 184, 185, 218, 1194, +1195, 1208. +\:\\{mem\_max}, \[11], 12, 14, 153, 154, 159, 163, 166, 167, 178, 179. +\:\\{mem\_min}, \[12], 14, 154, 158, 159, 163, 167, 168, 175, 176, 178, 179, +180, 182, 183, 184, 185, 218, 1190, 1191, 1194, 1195, 1208. +\:\\{mem\_top}, 11, \[12], 14, 154, 159, 175, 176, 1190, 1191, 1195. +\:\.{Memory usage...}, 1045. +\:\\{memory\_word}, 153, \[156], 157, 159, 242, 1188. +\:\\{merge\_edges}, \[366], 929, 1061. +\:\9{message\_}{\&{message} primitive}, \[1079]. +\:\\{message\_code}, \[1079], 1082. +\:\\{message\_command}, \[186], 1079, 1080, 1081. +\:\.{METAFONT capacity exceeded ...}, 89. +\:\9{METAFONT capacity exceeded buffer size}{\quad buffer size}, 34, 654, 717. +\:\9{METAFONT capacity exceeded extensible}{\quad extensible}, 1113. +\:\9{METAFONT capacity exceeded fontdimen}{\quad fontdimen}, 1115. +\:\9{METAFONT capacity exceeded hash size}{\quad hash size}, 207. +\:\9{METAFONT capacity exceeded headerbyte}{\quad headerbyte}, 1114. +\:\9{METAFONT capacity exceeded input stack size}{\quad input stack size}, 647. +\:\9{METAFONT capacity exceeded kern}{\quad kern}, 1112. +\:\9{METAFONT capacity exceeded ligtable size}{\quad ligtable size}, 1107. +\:\9{METAFONT capacity exceeded main memory size}{\quad main memory size}, 163, +167. +\:\9{METAFONT capacity exceeded move table size}{\quad move table size}, 356, +468, 508. +\:\9{METAFONT capacity exceeded number of int}{\quad number of internals}, 1036. +\:\9{METAFONT capacity exceeded number of strings}{\quad number of strings}, +44, 772. +\:\9{METAFONT capacity exceeded parameter stack size}{\quad parameter stack +size}, 704, 736, 737. +\:\9{METAFONT capacity exceeded path size}{\quad path size}, 281. +\:\9{METAFONT capacity exceeded pen polygon size}{\quad pen polygon size}, 481. +\:\9{METAFONT capacity exceeded pool size}{\quad pool size}, 41. +\:\9{METAFONT capacity exceeded rounding table size}{\quad rounding table +size}, 429. +\:\9{METAFONT capacity exceeded text input levels}{\quad text input levels}, +654. +\:\9{METAFONTbook}{\sl The {\logos METAFONT\/}book}, 1, 199, 574, 824, 872, +873, 878, 990, 991, 1068, 1203. +\:\9{METAFONT84}{\MF84}, \[1]. +\:\\{metric\_file\_name}, \[1087], 1134. +\:\\{MF}, \[4]. +\:\.{MF.POOL check sum...}, 53. +\:\.{MF.POOL doesn't match}, 53. +\:\.{MF.POOL has no check sum}, 52. +\:\.{MF.POOL line doesn't...}, 52. +\:\\{MF\_area}, \[769], 793. +\:\\{MF\_base\_default}, \[775], 776, 778. +\:\.{MFbases}, 11, 776. +\:\.{MFinputs}, 769. +\:\.{mfput}, 34, 788. +\:\\{mid}, \[1094]. +\:\\{min\_col}, \[580], 581, 582, 583. +\:\\{min\_command}, \[186], 706, 715, 718. +\:\\{min\_cover}, \[1118], 1120. +\:\\{min\_d}, \[348], 351, 352. +\:\\{min\_expression\_command}, \[186], 868, 869. +\:\\{min\_halfword}, 12, \[153], 154, 155, 156, 324, 326, 337, 342, 348, 350, +365, 375, 376, 381, 382, 383, 384, 580. +\:\\{min\_m}, 1144, \[1146], \[1161]. +\:\\{min\_n}, \[348], 351, 352, 1144, \[1146], \[1161]. +\:\\{min\_of}, \[189], 923. +\:\\{min\_primary\_command}, \[186], 823, 837, 862, 864, 868, 989. +\:\\{min\_quarterword}, \[153], 154, 155, 156, 1093. +\:\\{min\_secondary\_command}, \[186], 862. +\:\\{min\_suffix\_token}, \[186], 844. +\:\\{min\_tension}, \[883]. +\:\\{min\_tertiary\_command}, \[186], 864. +\:\\{minor\_axis}, \[527], 530, 533, \[865], 866. +\:\\{minus}, \[189], 859, 893, 898, 903, 922, 929, 930, 936, 939. +\:\.{Missing `)'}, 727, 735, 1032. +\:\.{Missing `)'...}, 725. +\:\.{Missing `,'}, 727, 878. +\:\.{Missing `..'}, 881. +\:\.{Missing `:'}, 747, 751, 756, 1106. +\:\.{Missing `:='}, 1021. +\:\.{Missing `;'}, 713. +\:\.{Missing `='}, 693, 755, 1035. +\:\.{Missing `\char`\#'}, 1113. +\:\.{Missing `\char`\}'}, 875. +\:\.{Missing `]'}, 859, 861. +\:\.{Missing `of'}, 734, 839. +\:\.{Missing `until'}, 765. +\:\.{Missing argument...}, 726. +\:\.{Missing parameter type}, 703. +\:\.{Missing symbolic token...}, 691. +\:\.{Missing...inserted}, 94. +\:\\{missing\_err}, \[94], 693, 713, 727, 734, 735, 747, 751, 755, 756, 765, +839, 859, 861, 875, 878, 881, 1021, 1032, 1035, 1106, 1113. +\:\\{missing\_extensible\_punctuation}, \[1113]. +\:\\{ml}, \[329]. +\:\\{mm}, \[348], 349, \[357], 358, 362, 364, \[580], 582, \[1165], 1169. +\:\\{mm0}, \[511], 513, 517, 519, 523. +\:\\{mm1}, \[511], 513, 517, 519, 523. +\:{mock curvature}, 275. +\:\\{mode\_command}, \[186], 1023, 1024, 1025. +\:{Moler, Cleve Barry}, 124. +\:\\{month}, \[190], 192, 193, 194, 790, 1163, 1200. +\:\9{month\_}{\&{month} primitive}, \[192]. +\:\\{months}, \[788], 790. +\:\\{more\_name}, 767, \[771], 781, 787. +\:{Morrison, Donald Ross}, 124. +\:\\{move}, \[308], 311, 315, 316, 319, 320, 321, 322, 354, 356, 357, 362, 364, +378, 379, 381, 382, 383, 384, 468, 507, 512, 514, 517, 518, 520, 523. +\:\\{move\_increment}, \[309], 310, 312, 314. +\:\\{move\_ptr}, \[308], 311, 315, 316, 319, 320, 468, 511, 512, 513, 514, 515, +516, 517, 518, 519, 520, 521, 522, 523. +\:\\{move\_size}, \[11], 308, 311, 321, 356, 357, 362, 378, 468, 507, 508, 511. +\:\\{move\_to\_edges}, \[378], 465, 517, 523. +\:\\{mr}, \[329]. +\:\&{mtype}, \[4]. +\:\.{Must increase the x}, 1187. +\:\\{my\_var\_flag}, \[823], 841, 852, \[868]. +\:\\{m0}, \[374], 375, 376, \[378], 380, 381, 382, 383, 384, \[464], 465, 467, +508, 511, 517, 523. +\:\\{m1}, \[374], 375, 376, \[378], 380, 463, \[464], 465, 467, 508, 511, 517, +523. +\:\|{n}, \[47], \[64], \[65], \[89], \[107], \[109], \[112], \[114], \[242], % +\[246], \[280], \[284], \[311], \[332], \[348], \[366], \[369], \[373], \[374], +\[378], \[473], \[477], \[484], \[488], \[491], \[497], \[511], \[539], \[562], +\[568], \[574], \[580], \[610], \[641], \[667], \[697], \[720], \[722], \[723], +\[755], \[773], \[774], \[778], \[863], \[913], \[916], \[944], \[985], % +\[1046], \[1165], \[1212]. +\:\\{n\_arg}, \[139], 140, 141, 147, 256, 281, 282, 292, 293, 301, 387, 541, +544, 866, 877, 907. +\:\\{n\_cos}, \[144], 145, 259, 263, 297, 301, 530, 533, 906, 958. +\:\\{n\_magic}, \[354], 361, 362, 365. +\:\\{n\_max}, \[326], 329, 331, 332, 334, 336, 340, 348, 352, 364, 365, 366, +965, 1167. +\:\\{n\_min}, \[326], 329, 330, 334, 336, 340, 348, 352, 364, 366, 577, 965, +1172. +\:\\{n\_pos}, \[326], 330, 331, 334, 336, 352, 364, 374, 377, 378, 965. +\:\\{n\_rover}, \[326], 330, 331, 334, 352, 364, 374, 377, 378. +\:\\{n\_sin}, \[144], 145, 259, 263, 297, 301, 530, 533, 906, 958. +\:\\{n\_sin\_cos}, 144, \[145], 147, 259, 263, 297, 301, 530, 906, 958. +\:\\{n\_window}, \[572], 576, 577. +\:\\{name}, 627, \[629], 630, 631, 632, 635, 637, 638, 649, 654, 655, 657, 679, +717, 736, 793, 897. +\:\\{name\_field}, 79, \[627], 629. +\:\\{name\_length}, \[25], 51, 774, 778, 780. +\:\\{name\_of\_file}, \[25], 26, 51, 774, 778, 780, 786. +\:\\{name\_type}, 188, \[214], 215, 219, 228, 229, 230, 232, 233, 234, 235, +236, 237, 238, 239, 240, 244, 245, 246, 247, 249, 254, 619, 651, 678, 702, 738, +744, 745, 799, 806, 830, 856, 857, 911, 931, 982, 1047, 1209. +\:\\{nd}, 1088, 1089, \[1096], 1126, 1135, 1141. +\:\\{ne}, 1088, 1089, \[1096], 1097, 1113, 1135, 1140, 1141. +\:\\{NE\_SW\_edge}, \[435]. +\:\\{negate}, \[16], 64, 103, 107, 110, 114, 118, 139, 146, 380, 409, 411, 412, +414, 415, 416, 418, 423, 424, 425, 480, 882, 903, 904, 930, 959, 1007, 1068. +\:\\{negate\_dep\_list}, 903, \[904], 930, 959. +\:\\{negate\_edges}, \[344], 345, 903, 929. +\:\\{negate\_x}, \[139], 390, 406, 409, 411, 418, 480, 489. +\:\\{negate\_y}, \[139], 390, 406, 414, 415, 418, 437, 438, 439, 480, 489. +\:\\{negative}, \[107], \[109], 110, \[112], \[114]. +\:\.{New busy locs}, 184. +\:\\{new\_boundary}, \[451], 452, 458. +\:\\{new\_dep}, \[606], 615, 829, 856, 858, 947, 969, 972. +\:\\{new\_if\_limit}, \[748]. +\:\\{new\_indep}, \[585], 586, 816, 855. +\:\\{new\_internal}, \[186], 211, 212, 1033. +\:\9{new\_internal\_}{\&{newinternal} primitive}, \[211]. +\:\\{new\_knot}, 870, \[871], 885, 908. +\:\\{new\_num\_tok}, \[215], 236, 860. +\:\\{new\_randoms}, 148, \[149], 150. +\:\\{new\_ring\_entry}, \[619], 855. +\:\\{new\_root}, \[234], 242, 1011. +\:\\{new\_row\_0}, 1144, \[1145], 1173. +\:\\{new\_row\_1}, \[1144]. +\:\\{new\_row\_164}, \[1144], 1145. +\:\\{new\_string}, \[54], 57, 58, 840, 912, 1163, 1164, 1200. +\:\\{new\_structure}, \[239], 243. +\:\\{next}, \[200], 202, 205, 207. +\:\\{next\_a}, \[426], \[440], 446. +\:\\{next\_char}, \[1093], 1107, 1112, 1137. +\:\\{next\_random}, \[149], 151, 152. +\:\\{nh}, 1088, 1089, \[1096], 1126, 1135, 1141. +\:\\{ni}, 1088, 1089, \[1096], 1126, 1135, 1141. +\:\\{nice\_pair}, \[899], 900, 907, 915, 941, 975, 983, 1072. +\:\&{nil}, 16. +\:\\{ninety\_deg}, \[106], 141, 530. +\:\\{nk}, 1088, 1089, \[1096], 1097, 1112, 1135, 1139, 1141. +\:\\{nl}, \[329], 330, 1088, 1089, 1093, \[1096], 1097, 1107, 1110, 1111, 1112, +1135, 1137, 1139, 1141. +\:\\{nn}, \[562]. +\:\.{No loop is in progress}, 713. +\:\.{No new edges added}, 372. +\:\\{no\_crossing}, \[391], 392. +\:\\{no\_op}, \[1144], 1147. +\:\\{no\_print}, \[54], 57, 58, 70, 93. +\:\\{no\_tag}, \[1092], 1096, 1097, 1104. +\:\\{node\_size}, \[166], 168, 169, 170, 172, 176, 182, 1194, 1195, 1207. +\:\\{node\_to\_round}, 426, \[427], 429, 436, 439, 444, 445, 446. +\:\.{NONEXISTENT}, 218. +\:\\{nonlinear\_eq}, \[621], 1003. +\:\.{Nonnumeric...replaced by 0}, 830. +\:\\{nonstop\_mode}, \[68], 81, 679, 682, 897, 1024, 1025. +\:\9{nonstop\_mode\_}{\&{nonstopmode} primitive}, \[1024]. +\:\\{norm\_rand}, \[152], 895. +\:\\{normal}, \[659], 660, 661, 694, 697, 730, 738, 739, 742, 758, 991, 1016. +\:\\{normal\_deviate}, \[189], 893, 895. +\:\9{normal\_deviate\_}{\&{normaldeviate} primitive}, \[893]. +\:\\{normalize\_selector}, 73, \[87], 88, 89, 90. +\:\\{north\_edge}, \[435], 438. +\:\\{north\_south\_edge}, \[435]. +\:\.{Not a cycle}, 1067. +\:\.{Not a string}, 716, 1082. +\:\.{Not a suitable variable}, 1060. +\:\.{Not implemented...}, 901, 923. +\:\9{not\_}{\&{not} primitive}, \[893]. +\:\\{not\_found}, \[15], 45, 394, 477, 479, 491, 494, 496, 539, 541, 556, 560, +561, 760, 1001, 1004, 1059, 1064, 1067, 1071, 1073, 1074, 1075. +\:\\{not\_op}, \[189], 893, 905. +\:\\{nothing\_printed}, \[473], 474. +\:\\{np}, 1088, 1089, \[1096], 1097, 1115, 1135, 1140, 1141. +\:\\{nr}, \[329], 331. +\:\\{nuline}, \[197], \[257], \[332], \[473]. +\:\\{null}, \[158], 159, 161, 163, 165, 167, 168, 176, 177, 181, 182, 202, 214, +216, 217, 226, 227, 229, 232, 233, 234, 235, 237, 242, 246, 249, 251, 252, 253, +254, 257, 258, 324, 346, 355, 364, 368, 398, 472, 475, 477, 479, 487, 528, 532, +536, 537, 587, 589, 591, 594, 597, 599, 600, 604, 605, 607, 609, 611, 612, 614, +615, 616, 617, 618, 619, 620, 632, 636, 638, 639, 640, 650, 651, 652, 665, 676, +685, 686, 694, 697, 698, 700, 707, 712, 713, 714, 716, 718, 719, 720, 721, 722, +723, 724, 726, 728, 730, 734, 735, 736, 738, 739, 746, 752, 753, 754, 755, 760, +762, 763, 764, 795, 801, 802, 805, 806, 807, 810, 811, 812, 816, 818, 819, 840, +844, 845, 848, 850, 851, 852, 853, 854, 857, 902, 904, 924, 925, 926, 927, 928, +929, 930, 931, 933, 934, 935, 936, 942, 943, 944, 945, 948, 949, 968, 970, 972, +997, 998, 1000, 1003, 1006, 1007, 1008, 1009, 1010, 1011, 1015, 1035, 1040, +1041, 1043, 1048, 1049, 1050, 1057, 1061, 1064, 1068, 1070, 1071, 1074, 1194, +1195, 1207, 1209, 1213. +\:\\{null\_coords}, \[175], 214, 475. +\:\\{null\_pen}, \[175], 435, 438, 442, 475, 477, 487, 865, 895, 917, 962, 1062. +\:\9{null\_pen\_}{\&{nullpen} primitive}, \[893]. +\:\\{null\_pen\_code}, \[189], 893, 895. +\:\9{null\_picture\_}{\&{nullpicture} primitive}, \[893]. +\:\\{null\_picture\_code}, \[189], 893, 895. +\:\\{null\_tally}, \[217]. +\:\\{nullary}, \[186], 713, 823, 893, 894, 895. +\:\\{num}, \[116], \[296], \[836], 837. +\:\9{num\_special\_}{\&{numspecial} primitive}, \[1176]. +\:\.{Number too large}, 914. +\:\9{numeric\_}{\&{numeric} primitive}, \[1013]. +\:\\{numeric\_token}, \[186], 651, 675, 678, 823, 824, 836, 837, 844, 846, 860, +861, 1016, 1042. +\:\\{numeric\_type}, \[187], 189, 229, 242, 248, 585, 798, 802, 809, 855, 918, +1013. +\:\\{nw}, 1088, 1089, \[1096], 1124, 1135, 1141. +\:\\{NW\_SE\_edge}, \[435]. +\:\\{n0}, \[373], \[374], 375, 376, 377, \[378], 380, 382, 383, 384, \[464], +465, 467, 468, 508, 513, 515, 517, 519, 521, 523. +\:\\{n1}, \[373], \[374], 375, 376, \[378], 380, 463, \[464], 465, 467, 468, +508, 513, 517, 519, 523. +\:\|{o}, \[210], \[431], \[477]. +\:\\{obliterated}, \[851], 852, 1000, 1057. +\:\9{oct\_}{\&{oct} primitive}, \[893]. +\:\\{oct\_op}, \[189], 893, 912, 913, 914. +\:\\{octant}, \[139], 141, \[379], 380, \[387], \[388], \[394], 434, 437, % +\[451], 463, 465, 468, 473, 479, 480, 481, 484, 485, \[488], 489, 506, 508, +509, 510, 512, 513, 515, 516, 518, 519, 521, 522. +\:\\{octant\_after}, \[390]. +\:\\{octant\_before}, \[390]. +\:\\{octant\_code}, \[448], 449, 458, 473, 481, 484. +\:\\{octant\_dir}, 394, \[395], 396, 398, 401, 509. +\:\\{octant\_number}, \[448], 449, 452, 459, 479, 488, 508, 512. +\:\\{octant\_subdivide}, 402, \[419]. +\:\\{odd}, 62, 111, 113, 145, 390, 417, 434, 435, 436, 442, 445, 459, 473, 482, +483, 484, 488, 508, 512, 530, 560, 906. +\:\9{odd\_}{\&{odd} primitive}, \[893]. +\:\\{odd\_op}, \[189], 893, 906. +\:\9{of\_}{\&{of} primitive}, \[211]. +\:\\{of\_macro}, \[226], 227, 705, 733. +\:\\{of\_token}, \[186], 211, 212, 705, 734, 839. +\:\\{off\_base}, \[1187], 1189, 1191, 1195, 1199. +\:\\{offset\_prep}, \[491], 494, 500, 506. +\:\.{OK}, 1051. +\:\\{OK\_to\_interrupt}, 83, \[91], 92, 93, 653, 825. +\:\\{old\_exp}, \[922], 925, 927, \[944]. +\:\\{old\_p}, \[922], 925, 926. +\:\\{old\_rover}, \[173]. +\:\\{old\_setting}, 195, \[196], \[635], 636, \[788], 840, 912, 1022, 1163, +1164. +\:\\{one\_byte}, \[1161]. +\:\\{one\_crossing}, \[391]. +\:\\{one\_eighty\_deg}, \[106], 139, 141, 292, 544. +\:\\{oo}, \[477], 479. +\:\\{op\_byte}, \[1093], 1107, 1112, 1137. +\:\\{op\_defining}, \[659], 664, 665, 694, 700. +\:\\{open}, \[256], 258, 262, 263, 271, 272, 273, 280, 282, 284, 285, 865, 868, +870, 874, 875, 877, 879, 885, 887, 888, 889, 890, 891, 896. +\:\.{open?}, 258, 262. +\:\\{open\_a\_window}, \[574], 1073. +\:\\{open\_base\_file}, \[779], 1211. +\:\\{open\_log\_file}, 73, 87, 679, \[788], 789, 791, 793, 895, 1134, 1209. +\:\\{open\_parens}, \[631], 657, 681, 793, 1209. +\:\\{open\_window}, \[186], 211, 212, 1069. +\:\9{open\_window\_}{\&{openwindow} primitive}, \[211]. +\:\9{or\_}{\&{or} primitive}, \[893]. +\:\\{or\_op}, \[189], 893, 940. +\:\\{ord}, 20. +\:{oriental characters}, 1147. +\:\&{othercases}, \[10]. +\:\\{others}, 10. +\:\.{Ouch...clobbered}, 1204. +\:\.{Out of order...}, 617. +\:\9{outer\_}{\&{outer} primitive}, \[1027]. +\:\\{outer\_tag}, \[186], 242, 249, 254, 668, 759, 850, 1029, 1041. +\:\\{output}, \[4]. +\:\.{Output written...}, 1182. +\:\\{output\_file\_name}, \[791], 792, 1163, 1182. +\:\\{over}, \[189], 837, 893, 948. +\:\\{overflow}, 34, 41, 44, \[89], 163, 167, 207, 281, 356, 429, 468, 481, 508, +647, 654, 704, 705, 717, 736, 737, 772, 1036, 1107, 1112, 1113, 1114, 1115, +1205. +\:{Overflow in arithmetic}, 9. +\:\\{o1}, 452, \[453], 458, 459. +\:\\{o2}, 452, \[453], 458, 459. +\:\|{p}, \[107], \[109], \[112], \[114], \[163], \[167], \[172], \[173], % +\[177], \[180], \[185], \[205], \[215], \[216], \[217], \[226], \[227], \[232], +\[233], \[234], \[235], \[238], \[239], \[242], \[246], \[247], \[248], \[249], +\[252], \[253], \[254], \[257], \[264], \[265], \[266], \[268], \[269], \[284], +\[299], \[328], \[329], \[332], \[334], \[336], \[337], \[340], \[342], \[344], +\[346], \[348], \[354], \[366], \[369], \[374], \[378], \[385], \[394], \[398], +\[402], \[405], \[406], \[410], \[419], \[429], \[433], \[440], \[451], \[465], +\[473], \[477], \[484], \[486], \[487], \[488], \[491], \[493], \[497], \[506], +\[510], \[518], \[527], \[539], \[556], \[562], \[577], \[589], \[591], \[594], +\[597], \[599], \[600], \[601], \[603], \[604], \[606], \[608], \[609], \[610], +\[619], \[620], \[621], \[622], \[641], \[649], \[650], \[651], \[652], \[661], +\[685], \[694], \[697], \[707], \[720], \[722], \[730], \[737], \[746], \[748], +\[755], \[760], \[763], \[799], \[800], \[801], \[805], \[807], \[809], \[823], +\[827], \[848], \[855], \[856], \[858], \[860], \[862], \[863], \[864], \[865], +\[868], \[872], \[898], \[899], \[904], \[910], \[916], \[919], \[922], \[923], +\[928], \[930], \[935], \[943], \[944], \[946], \[949], \[953], \[961], \[962], +\[963], \[966], \[968], \[971], \[972], \[974], \[976], \[977], \[978], \[982], +\[984], \[985], \[995], \[996], \[1001], \[1006], \[1015], \[1046], \[1050], % +\[1057], \[1059], \[1072], \[1117], \[1118], \[1121], \[1165], \[1186], % +\[1187], \[1205]. +\:\\{p\_over\_v}, \[600], 819, 932, 949. +\:\\{p\_plus\_fq}, 592, \[594], 597, 601, 818, 819, 932, 968, 971, 1010. +\:\\{p\_plus\_q}, \[597], 932, 1010. +\:\\{p\_times\_v}, \[599], 943, 969. +\:\\{p\_with\_x\_becoming\_q}, \[601], 614. +\:\\{pack\_buffered\_name}, \[778], 779. +\:\\{pack\_cur\_name}, \[784], 786, 793. +\:\\{pack\_file\_name}, \[774], 784, 793. +\:\\{pack\_job\_name}, \[784], 788, 791, 1134, 1200. +\:\\{packed\_ASCII\_code}, \[37], 38. +\:\\{page}, \[631]. +\:\\{page\_stack}, \[631]. +\:\\{paint\_row}, 3, 564, 566, \[568], 569, 571, 578, 579. +\:\\{paint\_switch}, \[1143], 1144. +\:\\{paint\_0}, 1144, \[1145], 1159. +\:\\{paint1}, 1144, \[1145], 1159. +\:\\{paint2}, \[1144]. +\:\\{paint3}, \[1144]. +\:\9{pair\_}{\&{pair} primitive}, \[1013]. +\:\\{pair\_node\_size}, \[230], 231. +\:\\{pair\_to\_path}, \[908], 921, 975, 983, 988, 1003, 1062. +\:\\{pair\_type}, \[187], 216, 230, 231, 232, 248, 798, 799, 800, 802, 808, +809, 830, 837, 855, 868, 870, 872, 877, 898, 899, 900, 903, 909, 917, 918, 919, +921, 926, 927, 929, 936, 941, 942, 944, 946, 948, 952, 957, 975, 982, 983, 988, +995, 1001, 1002, 1003, 1013, 1062. +\:\\{pair\_value}, \[982], 984, 987, 988. +\:\\{panicking}, \[178], 179, 825, 1213. +\:\\{param}, 1090, 1095, \[1096], 1106, 1115, 1140. +\:\\{param\_ptr}, \[633], 649, 650, 657, 736, 737. +\:\\{param\_size}, \[12], 214, 633, 677, 697, 704, 705, 736, 737, 1208. +\:\\{param\_stack}, 632, \[633], 639, 640, 650, 676, 677, 720, 736, 737. +\:\\{param\_start}, \[632], 639, 640, 649, 650, 676, 677. +\:\\{param\_type}, \[186], 227, 695, 696, 697, 703. +\:\\{parameter}, \[632], 638, 677. +\:\\{parent}, \[229], 236, 239, 240, 241, 245. +\:\9{PASCAL H}{\ph}, \[3], 26. +\:\9{PASCAL}{\PASCAL}, 1, 10. +\:\\{pass\_text}, 706, \[742], 749, 751. +\:\.{Path at line...}, 257. +\:\9{path\_}{\&{path} primitive}, \[1013]. +\:\\{path\_intersection}, \[562], 988. +\:\\{path\_join}, \[186], 211, 212, 874, 881, 886, 887. +\:\\{path\_length}, 915, \[916], 978. +\:\\{path\_size}, \[11], 279, 280, 281, 283, 284. +\:\\{path\_tail}, 266, \[267], 1065. +\:\\{path\_trans}, 952, \[962]. +\:\\{path\_type}, \[187], 216, 248, 621, 798, 802, 804, 808, 809, 855, 868, +870, 885, 891, 908, 915, 917, 918, 919, 920, 921, 952, 975, 983, 988, 1003, +1013, 1062. +\:\.{Paths don't touch}, 887. +\:\\{pause\_for\_instructions}, 91, \[93]. +\:\\{pausing}, \[190], 192, 193, 682. +\:\9{pausing\_}{\&{pausing} primitive}, \[192]. +\:\\{pd}, \[357], 358, 360. +\:\.{Pen cycle must be convex}, 478. +\:\.{Pen path must be a cycle}, 865. +\:\.{Pen too large}, 478. +\:\9{pen\_}{\&{pen} primitive}, \[1013]. +\:\\{pen\_circle}, \[189], 893, 895. +\:\9{pen\_circle\_}{\&{pencircle} primitive}, \[893]. +\:\\{pen\_edge}, \[433], 435, 438, \[440], 442, 443. +\:\\{pen\_head}, \[484]. +\:\\{pen\_node\_size}, 175, \[472], 477, 487. +\:\9{pen\_offset\_}{\&{penoffset} primitive}, \[893]. +\:\\{pen\_offset\_of}, \[189], 893, 983. +\:\\{pen\_type}, \[187], 216, 248, 621, 798, 802, 804, 808, 809, 855, 865, 895, +918, 919, 921, 952, 962, 983, 1003, 1013, 1052, 1053, 1054, 1055. +\:\\{percent\_class}, \[198], 199, 217, 669. +\:\\{period\_class}, \[198], 199, 669. +\:\\{perturbation}, 1118, \[1119], 1120, 1121, 1122, 1123, 1124, 1126. +\:\\{phi}, 541, \[542], 544. +\:\9{picture\_}{\&{picture} primitive}, \[1013]. +\:\\{picture\_type}, \[187], 216, 248, 621, 798, 802, 804, 808, 809, 855, 895, +898, 903, 918, 919, 921, 929, 952, 1003, 1013, 1057, 1061, 1070. +\:\\{pixel\_color}, \[565], 566, 568, 580. +\:\.{plain}, 776, 779, 1203. +\:\.{Please type...}, 679, 786. +\:\\{plus}, \[189], 859, 893, 898, 922, 930. +\:\\{plus\_or\_minus}, \[186], 823, 836, 837, 893, 894. +\:\\{pm}, \[357], 358, 360. +\:\9{point\_}{\&{point} primitive}, \[893]. +\:\\{point\_of}, \[189], 893, 983, 987. +\:\\{pointer}, \[158], 159, 161, 163, 166, 167, 172, 173, 177, 178, 180, 185, +200, 205, 215, 216, 225, 226, 227, 232, 233, 234, 235, 238, 239, 242, 246, 247, +248, 249, 250, 252, 253, 254, 257, 264, 265, 266, 267, 268, 269, 280, 284, 299, +326, 327, 328, 329, 332, 333, 334, 336, 337, 340, 342, 344, 346, 348, 354, 366, +369, 373, 374, 378, 385, 394, 398, 402, 403, 405, 406, 410, 419, 427, 429, 433, +440, 451, 465, 473, 476, 477, 484, 486, 487, 488, 491, 493, 497, 506, 510, 511, +518, 527, 539, 556, 562, 577, 589, 591, 592, 594, 597, 599, 600, 601, 603, 604, +606, 607, 608, 609, 610, 619, 620, 621, 622, 633, 649, 650, 651, 652, 661, 685, +694, 697, 707, 718, 720, 722, 723, 730, 737, 738, 746, 748, 752, 755, 760, 763, +799, 800, 801, 805, 807, 809, 813, 823, 827, 843, 848, 851, 855, 856, 858, 860, +862, 863, 864, 865, 868, 871, 872, 898, 904, 910, 916, 919, 922, 923, 928, 930, +935, 943, 944, 946, 949, 953, 961, 962, 963, 966, 968, 971, 972, 974, 976, 977, +978, 982, 984, 985, 995, 996, 1001, 1006, 1011, 1015, 1031, 1032, 1035, 1046, +1050, 1057, 1059, 1071, 1072, 1074, 1117, 1118, 1121, 1125, 1165, 1186, 1187, +1205. +\:\\{pool\_file}, 47, \[50], 51, 52, 53. +\:\\{pool\_name}, \[11], 51. +\:\\{pool\_pointer}, \[37], 38, 45, 46, 59, 60, 77, 210, 707, 768, 774, 913, +976, 1160. +\:\\{pool\_ptr}, 37, \[38], 40, 41, 43, 44, 47, 52, 58, 771, 780, 1045, 1163, +1192, 1193, 1204. +\:\\{pool\_size}, \[11], 37, 41, 52, 58, 780, 1045, 1193, 1208. +\:\\{pop\_input}, \[648], 650, 655. +\:\\{post}, 1142, 1144, \[1145], 1146, 1148, 1182. +\:\\{post\_head}, 842, \[843], 844, 845, 851, 852, 854. +\:\\{post\_post}, 1144, \[1145], 1146, 1148, 1182. +\:\9{postcontrol\_}{\&{postcontrol} primitive}, \[893]. +\:\\{postcontrol\_of}, \[189], 893, 983, 987. +\:\\{pp}, \[242], 243, 244, 245, \[265], \[266], \[334], 335, \[340], 341, % +\[366], 367, 368, \[406], 413, 414, 415, 416, 417, 418, \[440], 444, 445, 446, % +\[556], 558, \[562], \[589], 590, \[594], 595, \[597], 598, \[755], 765, % +\[809], 816, \[868], 885, 886, 887, 889, 890, \[966], 970, \[978], 980, 981, % +\[1006], 1009, 1010. +\:\\{pre}, 1142, 1144, \[1145], 1163. +\:\\{pre\_head}, 842, \[843], 844, 850, 851, 852, 853, 854. +\:\9{precontrol\_}{\&{precontrol} primitive}, \[893]. +\:\\{precontrol\_of}, \[189], 893, 983, 987. +\:\\{prev\_dep}, \[587], 603, 606, 617, 799, 811, 816, 827, 931, 947, 1007. +\:\\{prev\_m}, \[1165], 1169, 1170, 1171. +\:\\{prev\_n}, \[1165], 1167, 1172, 1174. +\:\\{prev\_r}, \[610], 614. +\:\\{prev\_w}, \[348], 349, 350, \[1165], 1169, 1170, 1171. +\:\9{primary\_}{\&{primary} primitive}, \[695]. +\:\\{primary\_binary}, \[186], 189, 823, 839, 893, 894. +\:\9{primary\_def\_}{\&{primarydef} primitive}, \[683]. +\:\\{primary\_macro}, \[226], 227, 695, 733. +\:\\{primitive}, 192, \[210], 211, 212, 625, 683, 688, 695, 709, 740, 893, +1013, 1018, 1024, 1027, 1037, 1052, 1079, 1101, 1108, 1176, 1203, 1204. +\:\\{print}, 54, \[59], 60, 62, 66, 68, 79, 80, 81, 84, 85, 89, 90, 94, 122, +128, 134, 187, 189, 197, 212, 217, 218, 219, 221, 222, 227, 235, 237, 257, 258, +259, 260, 261, 262, 263, 332, 372, 394, 397, 398, 401, 509, 510, 515, 521, 589, +613, 625, 638, 639, 643, 644, 663, 664, 665, 682, 684, 689, 696, 710, 721, 723, +725, 734, 741, 750, 754, 786, 788, 790, 802, 804, 805, 807, 817, 824, 832, 839, +851, 900, 902, 923, 924, 945, 997, 998, 999, 1002, 1008, 1019, 1025, 1028, +1032, 1034, 1038, 1041, 1043, 1045, 1048, 1050, 1053, 1057, 1080, 1098, 1102, +1105, 1109, 1123, 1139, 1140, 1163, 1164, 1180, 1182, 1192, 1194, 1196, 1200, +1208, 1209, 1212, 1213. +\:\\{print\_arg}, 721, \[723], 728, 734. +\:\\{print\_capsule}, 217, 219, \[224], 1042. +\:\\{print\_char}, \[58], 59, 60, 63, 64, 65, 77, 85, 89, 90, 103, 104, 157, +184, 185, 189, 197, 209, 212, 219, 220, 221, 222, 223, 224, 227, 237, 254, 259, +263, 332, 333, 372, 373, 394, 398, 401, 509, 589, 590, 602, 603, 613, 626, 637, +643, 681, 689, 725, 762, 790, 793, 802, 803, 806, 817, 824, 900, 902, 914, 924, +945, 990, 998, 1002, 1008, 1022, 1041, 1042, 1045, 1046, 1050, 1057, 1134, +1163, 1164, 1165, 1182, 1194, 1200, 1205, 1213. +\:\\{print\_cmd\_mod}, 212, 227, \[625], 626, 751, 824, 839, 990, 1041, 1043, +1209, 1213. +\:\\{print\_dd}, \[65], 790, 1163. +\:\\{print\_dependency}, \[589], 613, 805, 817, 1050. +\:\\{print\_diagnostic}, \[197], 257, 332, 372, 394, 473. +\:\\{print\_dp}, 802, 803, \[805]. +\:\\{print\_edges}, \[332], 804, 1165. +\:\\{print\_err}, 67, \[68], 88, 89, 90, 93, 94, 99, 122, 128, 134, 140, 270, +340, 342, 398, 404, 478, 602, 623, 661, 663, 670, 672, 675, 691, 701, 703, 708, +712, 713, 725, 726, 751, 786, 795, 807, 824, 832, 838, 851, 865, 887, 914, 963, +965, 990, 991, 1004, 1008, 1015, 1016, 1017, 1032, 1034, 1051, 1056, 1057, +1067, 1073, 1074, 1086, 1098, 1105, 1107, 1110. +\:\\{print\_exp}, 224, 639, 723, 762, \[801], 807, 902, 924, 945, 997, 998, +1040, 1046. +\:\\{print\_file\_name}, \[773], 786. +\:\\{print\_int}, \[64], 79, 89, 103, 157, 181, 182, 183, 184, 185, 197, 209, +222, 237, 332, 333, 372, 397, 398, 509, 515, 521, 617, 637, 661, 723, 790, 832, +914, 1045, 1105, 1139, 1140, 1163, 1164, 1165, 1182, 1192, 1194, 1196, 1200, +1209, 1213. +\:\\{print\_known\_or\_unknown\_type}, \[900], 901, 923. +\:\\{print\_ln}, \[57], 58, 61, 62, 66, 81, 84, 85, 86, 157, 195, 257, 394, +473, 638, 643, 656, 665, 679, 682, 721, 788, 793, 1023, 1041, 1043, 1045, 1165, +1192, 1194, 1196. +\:\\{print\_locs}, \[180]. +\:\\{print\_macro\_name}, 721, \[722], 725, 726, 734. +\:\\{print\_nl}, \[62], 68, 77, 79, 80, 86, 181, 182, 183, 184, 185, 195, 197, +209, 254, 257, 259, 332, 333, 372, 373, 394, 397, 398, 473, 474, 509, 510, 515, +521, 603, 613, 617, 626, 637, 638, 639, 665, 679, 723, 725, 762, 786, 788, 807, +817, 902, 924, 945, 994, 997, 998, 1022, 1040, 1041, 1045, 1046, 1048, 1050, +1082, 1123, 1128, 1134, 1139, 1140, 1169, 1182, 1200, 1205, 1209, 1212. +\:\\{print\_op}, \[189], 894, 901, 902, 923, 924. +\:\\{print\_path}, \[257], 269, 402, 804. +\:\\{print\_pen}, \[473], 477, 484, 804. +\:\\{print\_scaled}, \[103], 104, 122, 128, 134, 157, 220, 254, 259, 260, 263, +589, 590, 602, 603, 802, 803, 817, 912, 945, 1008, 1022, 1042, 1123. +\:\\{print\_spec}, \[394], 402. +\:\\{print\_strange}, \[398], 399, 1068. +\:\\{print\_the\_digs}, \[63], 64. +\:\\{print\_two}, \[104], 258, 261, 394, 473, 510. +\:\\{print\_two\_true}, \[394], 397, 474, 509, 515, 521. +\:\\{print\_type}, \[187], 189, 802, 804, 806, 900, 1002, 1014, 1057. +\:\\{print\_variable\_name}, 221, \[235], 589, 603, 613, 664, 802, 803, 806, +817, 1046, 1048, 1050, 1213. +\:\\{print\_weight}, 332, \[333]. +\:\\{print\_word}, \[157], 1213. +\:\\{procrustes}, \[404]. +\:\\{progression\_node\_size}, \[752], 763, 765. +\:\\{prompt\_file\_name}, \[786], 789, 791, 793, 1134, 1200. +\:\\{prompt\_input}, \[66], 78, 82, 679, 682, 786, 897. +\:\\{proofing}, \[190], 192, 193, 994, 1070, 1147, 1165, 1177. +\:\9{proofing\_}{\&{proofing} primitive}, \[192]. +\:\\{protection\_command}, \[186], 1026, 1027, 1028. +\:\\{proto\_dependent}, \[187], 216, 248, 588, 589, 594, 597, 599, 601, 603, +610, 612, 798, 799, 800, 802, 808, 809, 812, 813, 815, 817, 818, 819, 855, 857, +903, 932, 943, 949, 968, 969, 971, 972, 1003, 1010. +\:\\{pseudo}, \[54], 57, 58, 59, 60, 642. +\:\\{psi}, \[279], 281, 290, 294, 297. +\:\\{push\_input}, \[647], 649, 654. +\:\\{put}, 25, 28, 1188. +\:\\{put\_get\_error}, 270, 340, 342, 404, 478, 623, \[820], 865, 873, 887, +901, 914, 923, 950, 955, 963, 965, 993, 999, 1000, 1002, 1004, 1008, 1015, +1016, 1051, 1057, 1067, 1068, 1073, 1074, 1082, 1086, 1098, 1105, 1106, 1178. +\:\\{put\_get\_flush\_error}, 716, 754, \[820], 830, 852, 872, 876, 878, 883, +892, 937, 960, 1021, 1055, 1056, 1060, 1061, 1062, 1071, 1103, 1112, 1115. +\:\\{pyth\_add}, \[124], 145, 281, 454, 530, 533, 866, 915, 951. +\:\\{pyth\_sub}, \[126], 951. +\:\\{pythag\_add}, \[189], 893, 951. +\:\\{pythag\_sub}, \[189], 893, 951. +\:\.{Pythagorean...}, 128. +\:\|{q}, \[107], \[109], \[112], \[114], \[117], \[121], \[145], \[167], % +\[172], \[173], \[177], \[180], \[185], \[216], \[217], \[227], \[232], \[233], +\[235], \[239], \[242], \[246], \[247], \[249], \[252], \[253], \[254], \[257], +\[264], \[265], \[266], \[268], \[269], \[284], \[299], \[311], \[328], \[329], +\[332], \[333], \[336], \[337], \[340], \[342], \[344], \[346], \[348], \[354], +\[366], \[369], \[385], \[394], \[398], \[402], \[405], \[406], \[410], \[419], +\[433], \[440], \[451], \[465], \[477], \[491], \[493], \[506], \[518], \[527], +\[539], \[556], \[577], \[589], \[594], \[597], \[601], \[603], \[604], \[606], +\[608], \[609], \[610], \[619], \[620], \[621], \[622], \[641], \[685], \[694], +\[697], \[720], \[722], \[723], \[746], \[755], \[760], \[763], \[801], \[805], +\[809], \[823], \[827], \[851], \[855], \[858], \[863], \[865], \[868], \[871], +\[898], \[919], \[922], \[928], \[930], \[935], \[943], \[946], \[949], \[953], +\[961], \[962], \[966], \[968], \[972], \[978], \[985], \[996], \[1001], % +\[1006], \[1015], \[1046], \[1059], \[1117], \[1121], \[1165], \[1186], \[1187]. +\:\\{qi}, \[155], 1107, 1110, 1111, 1112, 1113, 1137, 1192. +\:\\{qo}, \[155], 1110, 1111, 1133, 1193. +\:\\{qq}, 229, \[242], 245, \[265], \[266], \[334], \[366], 367, 368, \[406], +413, 414, 415, 416, 417, 418, \[556], 558, \[594], 595, 596, \[597], 598, % +\[868], 885, 886, 887, 890, \[966], 970, \[978], 980, 981. +\:\\{qqq}, 229. +\:\\{qqqq}, 153, \[156], 157, 1188, 1189. +\:\\{qqq1}, 229. +\:\\{qqq2}, 229. +\:\\{qq1}, 229. +\:\\{qq2}, 229. +\:\\{quad}, 1095. +\:\\{quad\_code}, \[1095]. +\:\\{quadrant\_subdivide}, 402, \[406], 426. +\:\\{quarter\_unit}, \[101]. +\:\\{quarterword}, 153, \[156], 189, 627, 649, 823, 895, 898, 899, 901, 910, +913, 919, 922, 923, 930, 953, 960, 962, 963, 966, 985. +\:\\{quote}, \[688], 690. +\:\9{quote\_}{\&{quote} primitive}, \[688]. +\:\\{q1}, 229. +\:\|{r}, \[117], \[124], \[126], \[145], \[167], \[173], \[177], \[180], % +\[217], \[227], \[233], \[235], \[239], \[242], \[246], \[247], \[268], \[284], +\[311], \[332], \[334], \[336], \[337], \[340], \[344], \[346], \[348], \[354], +\[366], \[373], \[374], \[378], \[402], \[406], \[410], \[419], \[451], \[465], +\[476], \[477], \[491], \[493], \[506], \[518], \[527], \[567], \[568], \[577], +\[594], \[597], \[599], \[600], \[601], \[604], \[606], \[610], \[621], \[622], +\[694], \[697], \[720], \[809], \[823], \[855], \[858], \[863], \[868], \[922], +\[928], \[930], \[946], \[953], \[966], \[968], \[971], \[1006], \[1104], % +\[1117], \[1121]. +\:\\{r\_delim}, \[697], 703, \[720], 725, 726, 727, 729, \[730], 731, 735, % +\[823], 826, 830, 1031, \[1032]. +\:\\{r\_packet}, 560. +\:\\{r\_packets}, \[553], 558. +\:{Ramshaw, Lyle Harold}, 2, 469, 1087. +\:\\{random\_seed}, \[186], 211, 212, 1020. +\:\9{random\_seed\_}{\&{randomseed} primitive}, \[211]. +\:\\{randoms}, \[148], 149, 150, 151, 152. +\:\\{rd}, \[357], 358, 359. +\:\\{read}, 52, 53, 1212, 1213. +\:\\{read\_ln}, 52. +\:\9{read\_string\_}{\&{readstring} primitive}, \[893]. +\:\\{read\_string\_op}, \[189], 893, 895. +\:\\{ready\_already}, \[1203], 1204. +\:\\{real}, 3, 120. +\:{recursion}, 71, 73, 217, 224, 246, 706, 719, 748, 796, 995, 1041. +\:\\{recycle\_value}, 224, 246, 247, 650, 763, 808, \[809], 810, 829, 873, 903, +910, 922, 925, 935, 944, 955, 968, 970, 972, 1000, 1001. +\:\\{reduce\_angle}, \[292], 293. +\:\.{Redundant equation}, 623. +\:\.{Redundant or inconsistent equation}, 1004. +\:\\{ref\_count}, \[226], 475, 477, 487, 694, 697, 854, 862, 864, 868. +\:{reference counts}, 42, 226, 632. +\:\\{relax}, \[186], 211, 212, 686, 706, 707. +\:\\{rem\_byte}, \[1093], 1107, 1112, 1137. +\:\\{remainder}, \[1091], 1092, 1093, 1096. +\:\\{remove\_cubic}, \[405], 417, 447, 492. +\:\\{rep}, \[1094]. +\:\\{repeat\_loop}, \[186], 706, 707, 759, 1043. +\:\\{reset}, 25, 26, 32. +\:\\{reset\_OK}, \[26]. +\:\\{restart}, \[15], 167, 168, 667, 668, 670, 672, 676, 677, 679, 681, 691, +823, 853, 854, 855, 862, 864, 868, 1001, 1003. +\:\\{restore\_cur\_exp}, \[801]. +\:\\{result}, \[45], \[1054], 1056. +\:\\{resume\_iteration}, 706, 712, 755, \[760], 763. +\:\\{reswitch}, \[15], 748. +\:\.{retrograde line...}, 510. +\:\&{return}, 15, \[16]. +\:\\{return\_sign}, \[117], 118. +\:\\{rev\_turns}, 452, 454, \[455], 456, 1064. +\:\\{reverse}, \[189], 893, 921. +\:\9{reverse\_}{\&{reverse} primitive}, \[893]. +\:\\{reversed}, \[977], \[978]. +\:\\{rewrite}, 25, 26, 32. +\:\\{rewrite\_OK}, \[26]. +\:\\{rh}, 153, \[156], 157, 161, 200. +\:\\{rhs}, \[1059], 1062, 1064, 1065, 1066, 1067. +\:{Riesenfeld, Richard Franklin}, 303. +\:\\{right\_brace}, \[186], 211, 212, 875. +\:\\{right\_bracket}, \[186], 211, 212, 846, 859, 861, 1012. +\:\\{right\_bracket\_class}, \[198], 199, 220, 221. +\:\\{right\_class}, \[528], 531, 532, 534, 535. +\:\\{right\_col}, \[567], \[572], 574, 577, 581, 583, 584. +\:\\{right\_curl}, \[256], 263, 271, 282, 294, 890, 891. +\:\\{right\_delimiter}, \[186], 203, 726, 727, 731, 735, 1030, 1031, 1032, 1043. +\:\\{right\_edge}, \[580], 581, 582. +\:\\{right\_given}, \[256], 263, 282, 293, 301, 879, 888, 889. +\:\\{right\_octant}, \[393], 451, 452, 458, 459. +\:\\{right\_paren\_class}, \[198], 199, 219, 222. +\:\\{right\_tension}, \[256], 258, 260, 288, 289, 294, 295, 299, 300, 302, 881, +882, 886, 887. +\:\\{right\_transition}, \[393], 459, 509, 517, 523. +\:\\{right\_type}, \[255], 256, 258, 263, 265, 266, 269, 271, 272, 273, 282, +285, 290, 299, 302, 393, 394, 404, 405, 407, 409, 410, 411, 412, 413, 414, 415, +416, 417, 418, 421, 423, 424, 425, 426, 434, 435, 436, 437, 438, 439, 441, 442, +443, 445, 447, 450, 451, 452, 454, 457, 466, 479, 481, 486, 491, 494, 497, 499, +512, 515, 518, 521, 528, 539, 562, 563, 870, 871, 874, 879, 880, 884, 885, 888, +889, 890, 891, 896, 921, 962, 978, 987, 1065, 1066. +\:\\{right\_u}, \[528], 531, 532, 534, 535, 537. +\:\\{right\_x}, \[255], 256, 261, 265, 266, 271, 282, 299, 302, 393, 397, 404, +405, 407, 409, 410, 411, 412, 415, 416, 418, 419, 421, 423, 424, 425, 434, 436, +441, 444, 447, 457, 468, 486, 492, 496, 512, 518, 528, 543, 558, 563, 866, 884, +890, 896, 962, 987, 1065, 1066. +\:\\{right\_y}, \[255], 256, 261, 265, 266, 271, 282, 299, 302, 393, 397, 404, +405, 410, 413, 414, 415, 416, 419, 423, 424, 425, 437, 439, 444, 447, 457, 468, +486, 492, 496, 512, 518, 528, 543, 558, 563, 866, 884, 890, 896, 962, 987, +1065, 1066. +\:\\{ring\_delete}, \[620], 809. +\:\\{ring\_merge}, \[622], 1003. +\:\\{rising}, \[497]. +\:\\{rlink}, \[166], 167, 168, 169, 171, 172, 173, 174, 176, 182, 1194, 1195, +1207. +\:\\{rm}, \[357], 358, 359. +\:\\{root}, \[188], 229, 230, 234, 239, 254, 702. +\:\\{rotate}, 389. +\:\9{rotated\_}{\&{rotated} primitive}, \[893]. +\:\\{rotated\_by}, \[189], 893, 952, 957. +\:\\{round\_decimals}, \[102], 103, 674. +\:\\{round\_fraction}, \[119], 590, 600, 817, 819, 906, 958, 1010. +\:\\{round\_unscaled}, \[119], 374, 375, 376, 575, 576, 790, 906, 912, 965, +977, 1056, 1070, 1071, 1073, 1103, 1106, 1137, 1163, 1165, 1181, 1200. +\:\\{rover}, \[166], 167, 168, 169, 170, 171, 172, 173, 174, 176, 182, 1194, +1195, 1207. +\:\\{row\_node\_size}, \[325], 330, 331, 334, 341, 352, 353, 354, 355, 358, +364, 385. +\:\\{row\_transition}, 578, \[579], 580, 582, 583, 584. +\:\\{rr}, \[242], 245, \[266], \[299], 300, \[334], 335, \[340], \[366], 368, % +\[922], 939, \[978], 980. +\:\\{rt}, \[286], 289, 294, 295, \[299], 302. +\:\\{runaway}, 163, 663, \[665]. +\:\\{r0}, \[574], 575, 576, \[1073]. +\:\\{r1}, 229, \[574], 575, \[1073]. +\:\|{s}, \[43], \[45], \[46], \[58], \[59], \[60], \[62], \[88], \[89], \[90], % +\[94], \[103], \[167], \[172], \[197], \[210], \[232], \[242], \[257], \[280], % +\[284], \[311], \[332], \[337], \[340], \[342], \[344], \[346], \[348], \[354], +\[394], \[398], \[402], \[406], \[419], \[465], \[473], \[477], \[488], \[495], +\[497], \[506], \[518], \[527], \[594], \[597], \[599], \[600], \[601], \[604], +\[610], \[754], \[755], \[784], \[786], \[807], \[809], \[824], \[930], \[943], +\[949], \[966], \[977], \[1160]. +\:\\{s\_scale}, \[585], 589, 608, 610, 817. +\:\\{safety\_margin}, \[402]. +\:\9{save\_}{\&{save} primitive}, \[211]. +\:\\{save\_boundary\_item}, \[250], 832. +\:\\{save\_command}, \[186], 211, 212, 1033. +\:\\{save\_cond\_ptr}, \[748], 749. +\:\\{save\_exp}, \[651], \[718]. +\:\\{save\_flag}, \[824]. +\:\\{save\_internal}, \[253], 1034. +\:\\{save\_node\_size}, \[250], 252, 253, 254. +\:\\{save\_ptr}, \[250], 251, 252, 253, 254. +\:\\{save\_type}, \[651]. +\:\\{save\_variable}, \[252], 1033. +\:\\{save\_word}, \[242], 244. +\:\.{SAVED}, 235. +\:\\{saved\_equiv}, \[250], 252, 254. +\:\\{saved\_root}, \[188], 230, 235, 247, 249. +\:\\{saving}, \[249]. +\:\\{sc}, 153, \[156], 157, 229, 255, 472, 752, 961. +\:\\{scaled}, \[101], 102, 103, 104, 105, 112, 114, 116, 119, 121, 132, 135, +150, 151, 152, 153, 156, 187, 190, 194, 214, 215, 228, 229, 250, 259, 279, 280, +286, 296, 299, 304, 306, 311, 369, 374, 387, 388, 389, 390, 402, 403, 406, 410, +419, 426, 427, 429, 430, 431, 432, 433, 434, 440, 463, 477, 486, 488, 497, 510, +511, 527, 539, 542, 555, 574, 585, 587, 588, 594, 599, 600, 602, 607, 612, 798, +808, 820, 836, 865, 868, 875, 916, 917, 935, 944, 946, 949, 954, 961, 968, 971, +972, 974, 978, 982, 985, 1073, 1096, 1098, 1117, 1118, 1119, 1120, 1121, 1128, +1129, 1130, 1144, 1146, 1147, 1182, 1205. +\:\.{Scaled picture...big}, 340, 342. +\:\9{scaled\_}{\&{scaled} primitive}, \[893]. +\:\\{scaled\_by}, \[189], 893, 952, 957. +\:\\{scaled\_threshold}, \[594], 597. +\:\\{scaling\_down}, \[599], \[600]. +\:\\{scan\_declared\_variable}, 700, \[1011], 1015. +\:\\{scan\_def}, \[697], 992. +\:\\{scan\_direction}, \[875], 879, 880. +\:\\{scan\_expression}, 706, 729, 733, 734, 764, 765, 796, 798, 821, 826, 830, +839, 846, 859, 861, \[868], 876, 877, 878, 892, 993, 995, 996, 1021, 1040, +1054, 1059, 1070, 1071, 1072, 1073, 1082, 1103, 1106, 1112, 1115, 1177. +\:\\{scan\_file\_name}, \[781], 795. +\:\\{scan\_primary}, 706, 716, 733, 734, 796, 798, 821, \[823], 835, 837, 839, +842, 862, 882, 884, 893, 1059, 1071, 1074. +\:\\{scan\_secondary}, 706, 733, 796, 798, 821, \[862], 864. +\:\\{scan\_suffix}, 706, 729, 735, 764, 840, \[860]. +\:\\{scan\_tertiary}, 706, 733, 796, 798, 821, \[864], 868, 869. +\:\\{scan\_text\_arg}, 729, \[730], 733. +\:\\{scan\_tokens}, \[186], 211, 212, 706, 707. +\:\9{scan\_tokens\_}{\&{scantokens} primitive}, \[211]. +\:\\{scan\_toks}, \[685], 694, 698, 758. +\:\\{scan\_with}, \[1054], 1062, 1074. +\:\\{scanner\_status}, \[659], 660, 661, 663, 664, 665, 694, 697, 700, 730, +742, 758, 991, 1016. +\:\\{screen\_col}, \[565], 566, 567, 568, 572, 580. +\:\\{screen\_depth}, \[11], 565, 567, 568, 575. +\:\\{screen\_OK}, \[569], 570, 574, 577. +\:\\{screen\_pixel}, \[566], 567, 568. +\:\\{screen\_row}, \[565], 566, 567, 568, 572. +\:\\{screen\_started}, \[569], 570. +\:\\{screen\_width}, \[11], 565, 567, 568, 575. +\:\\{scroll\_mode}, 66, \[68], 79, 81, 88, 786, 1024, 1025, 1084. +\:\9{scroll\_mode\_}{\&{scrollmode} primitive}, \[1024]. +\:\\{search\_mem}, 178, \[185], 1213. +\:\\{second\_octant}, \[139], 141, 380, 387, 388, 396, 435, 443, 449, 461, 462. +\:\9{secondary\_}{\&{secondary} primitive}, \[695]. +\:\\{secondary\_binary}, \[186], 893, 894. +\:\9{secondary\_def\_}{\&{secondarydef} primitive}, \[683]. +\:\\{secondary\_macro}, \[226], 227, 695, 696, 733. +\:\\{secondary\_primary\_macro}, \[186], 249, 683, 684, 862, 1035, 1043. +\:\.{see the transcript file...}, 1209. +\:\\{seed}, \[150]. +\:\\{selector}, \[54], 55, 57, 58, 59, 60, 62, 66, 70, 81, 86, 87, 93, 195, +635, 636, 642, 679, 788, 789, 804, 840, 912, 1022, 1023, 1163, 1164, 1200, +1205, 1209. +\:\\{semicolon}, \[186], 211, 212, 713, 732, 832, 989, 990, 991, 1017, 1051, +1070. +\:\\{sentinel}, \[175], 177, 324, 328, 330, 331, 332, 335, 339, 343, 344, 345, +346, 347, 348, 349, 355, 356, 358, 364, 367, 368, 369, 582, 1169. +\:\\{serial\_no}, \[585], 587, 1198, 1199. +\:\\{set\_controls}, 297, 298, \[299], 301. +\:\\{set\_min\_max}, \[554], 558, 559. +\:\\{set\_output\_file\_name}, \[791], 1163. +\:\\{set\_tag}, \[1104], 1106, 1111, 1113. +\:\\{set\_trick\_count}, \[642], 643, 644, 646. +\:\\{set\_two}, \[387], 388. +\:\\{set\_two\_end}, \[387]. +\:\\{set\_up\_direction\_time}, 983, \[984]. +\:\\{set\_up\_known\_trans}, \[960], 962, 963, 967. +\:\\{set\_up\_offset}, 983, \[984]. +\:\\{set\_up\_trans}, \[953], 960, 970. +\:\\{seventh\_octant}, \[139], 141, 380, 387, 388, 396, 435, 443, 449, 461, 462. +\:\\{sf}, \[116], 297, \[298], 299, 300, 301. +\:\9{shifted\_}{\&{shifted} primitive}, \[893]. +\:\\{shifted\_by}, \[189], 893, 952, 957. +\:\\{ship\_out}, 1070, 1149, \[1165], 1175. +\:\9{ship\_out\_}{\&{shipout} primitive}, \[211]. +\:\\{ship\_out\_command}, \[186], 211, 212, 1069. +\:\9{show\_}{\&{show} primitive}, \[1037]. +\:\\{show\_cmd\_mod}, \[626], 713, 895. +\:\\{show\_code}, \[1037], 1038, 1040, 1051. +\:\\{show\_command}, \[186], 1037, 1038, 1039. +\:\\{show\_context}, 54, 73, 77, 83, 634, \[635], 644, 786, 789, 793. +\:\\{show\_cur\_cmd\_mod}, \[626], 707, 832, 992. +\:\9{show\_dependencies\_}{\&{showdependencies} primitive}, \[1037]. +\:\\{show\_dependencies\_code}, \[1037], 1051. +\:\\{show\_macro}, \[227], 645, 721, 1041, 1048. +\:\9{show\_stats\_}{\&{showstats} primitive}, \[1037]. +\:\\{show\_stats\_code}, \[1037], 1038, 1051. +\:\9{show\_token\_}{\&{showtoken} primitive}, \[1037]. +\:\\{show\_token\_code}, \[1037], 1038, 1051. +\:\\{show\_token\_list}, \[217], 224, 227, 235, 639, 640, 645, 646, 665, 722, +723, 762, 840, 851, 998, 1043, 1057, 1213. +\:\9{show\_var\_}{\&{showvariable} primitive}, \[1037]. +\:\\{show\_var\_code}, \[1037], 1038, 1051. +\:\\{showstopping}, \[190], 192, 193, 1051. +\:\9{showstopping\_}{\&{showstopping} primitive}, \[192]. +\:\\{si}, \[37], 41, 85, 1193. +\:\9{sin\_d\_}{\&{sind} primitive}, \[893]. +\:\\{sin\_d\_op}, \[189], 893, 906. +\:\\{sine}, \[280], 281, \[299], 300. +\:\\{single\_dependency}, \[608], 829, 855, 858, 1007, 1009. +\:\\{sixth\_octant}, \[139], 141, 379, 380, 387, 388, 395, 396, 443, 448, 449, +461, 462, 488. +\:\\{skew}, \[387], 421, 445, 447, 451, 457, 481. +\:\\{skew\_line\_edges}, 508, \[510], 517, 523. +\:\\{skimp}, \[1121], 1124, 1126. +\:\\{skip\_byte}, \[1093], 1107, 1110, 1111, 1112, 1137. +\:\\{skip\_error}, \[1110], 1111. +\:\\{skip\_table}, \[1096], 1097, 1110, 1111, 1139. +\:\\{skip\_to}, \[186], 211, 212, 1107. +\:\9{skip\_to\_}{\&{skipto} primitive}, \[211]. +\:\\{skipping}, \[659], 661, 742. +\:\\{skip0}, 1144, \[1145], 1173. +\:\\{skip1}, 1144, \[1145], 1174. +\:\\{skip2}, \[1144]. +\:\\{skip3}, \[1144]. +\:\\{slant}, 1095. +\:\\{slant\_code}, \[1095]. +\:\9{slanted\_}{\&{slanted} primitive}, \[893]. +\:\\{slanted\_by}, \[189], 893, 952, 957. +\:\\{slash}, \[186], 837, 893, 894. +\:\\{slow\_add}, \[100], 594, 597, 930, 931, 933. +\:\\{slow\_case\_down}, \[378], 380. +\:\\{slow\_case\_up}, \[378], 380. +\:\\{slow\_print}, \[60], 61, 79, 219, 223, 254, 638, 664, 722, 725, 773, 790, +793, 802, 994, 998, 999, 1032, 1034, 1041, 1042, 1043, 1082, 1086, 1134, 1182, +1200, 1205, 1213. +\:{small computers}, 95. +\:\\{small\_number}, \[101], 102, 121, 135, 139, 145, 187, 210, 217, 230, 232, +238, 248, 311, 387, 388, 390, 394, 451, 453, 477, 589, 594, 597, 599, 600, 601, +610, 621, 651, 685, 738, 746, 778, 796, 801, 805, 809, 843, 875, 900, 930, 935, +943, 949, 966, 1001, 1015, 1054, 1098, 1104, 1123, 1177, 1209. +\:\\{smooth\_bot}, \[511], 512, 517, 518, 523. +\:\\{smooth\_moves}, \[321], 468, 517, 523. +\:\\{smooth\_top}, \[511], 512, 517, 518, 523. +\:\\{smoothing}, \[190], 192, 193, 468, 517, 523. +\:\9{smoothing\_}{\&{smoothing} primitive}, \[192]. +\:\\{so}, \[37], 45, 59, 60, 85, 210, 223, 717, 774, 913, 976, 977, 1103, 1160, +1192. +\:\\{solve\_choices}, 278, \[284]. +\:\.{some chardps...}, 1123. +\:\.{some charhts...}, 1123. +\:\.{some charics...}, 1123. +\:\.{some charwds...}, 1123. +\:\.{Some number got too big}, 270. +\:\.{Sorry, I can't find...}, 779. +\:\\{sort\_avail}, \[173], 1194. +\:\\{sort\_edges}, \[346], 348, 354, 578, 1169. +\:\\{sort\_in}, \[1117], 1124, 1126. +\:\\{sorted}, 324, \[325], 328, 330, 331, 332, 335, 339, 343, 344, 345, 346, +347, 348, 349, 355, 356, 358, 364, 367, 368, 369, 385, 580, 582, 1169. +\:\\{sorted\_loc}, \[325], 335, 345, 347, 368. +\:\\{south\_edge}, \[435], 438. +\:\\{space}, 1095. +\:\\{space\_class}, \[198], 199, 669. +\:\\{space\_code}, \[1095]. +\:\\{space\_shrink}, 1095. +\:\\{space\_shrink\_code}, \[1095]. +\:\\{space\_stretch}, 1095. +\:\\{space\_stretch\_code}, \[1095]. +\:\\{spec\_atan}, \[137], 138, 143, 147. +\:\\{spec\_head}, \[506]. +\:\\{spec\_log}, \[129], 131, 133, 136. +\:\9{special\_}{\&{special} primitive}, \[1176]. +\:\\{special\_command}, \[186], 1175, 1176, 1180. +\:\\{split\_cubic}, \[410], 411, 412, 415, 416, 424, 425, 493, 980, 981, 986. +\:\\{split\_for\_offset}, \[493], 499, 503, 504. +\:\\{spotless}, \[71], 72, 195, 1204, 1209. +\:\9{sqrt\_}{\&{sqrt} primitive}, \[893]. +\:\\{sqrt\_op}, \[189], 893, 906. +\:\.{Square root...replaced by 0}, 122. +\:\\{square\_rt}, \[121], 122, 906. +\:\\{ss}, \[242], 243, 245, \[299], 300, \[334], 335, \[340], \[978], 980. +\:\\{st}, \[116], 297, \[298], 299, 300, 301. +\:\\{st\_count}, \[200], 203, 207, 1196, 1197, 1208. +\:\\{stack\_argument}, \[737], 760. +\:\\{stack\_dx}, \[553], 559, 561. +\:\\{stack\_dy}, \[553], 559, 561. +\:\\{stack\_l}, \[309], 312, 314. +\:\\{stack\_m}, \[309], 312, 314. +\:\\{stack\_max}, \[553], 554, 556. +\:\\{stack\_min}, \[553], 554, 556. +\:\\{stack\_n}, \[309], 312, 314. +\:\\{stack\_r}, \[309], 312, 314. +\:\\{stack\_s}, \[309], 312, 314. +\:\\{stack\_size}, \[11], 628, 634, 647, 1208. +\:\\{stack\_tol}, \[553], 559, 561. +\:\\{stack\_uv}, \[553], 559, 561. +\:\\{stack\_xy}, \[553], 559, 561. +\:\\{stack\_x1}, \[309], 312, 314. +\:\\{stack\_x2}, \[309], 312, 314. +\:\\{stack\_x3}, \[309], 312, 314. +\:\\{stack\_y1}, \[309], 312, 314. +\:\\{stack\_y2}, \[309], 312, 314. +\:\\{stack\_y3}, \[309], 312, 314. +\:\\{stack\_1}, \[553], 554, 559, 560. +\:\\{stack\_2}, \[553], 554, 559, 560. +\:\\{stack\_3}, \[553], 554, 559, 560. +\:\\{start}, 627, \[629], 630, 632, 644, 645, 649, 650, 654, 655, 657, 679, +681, 682, 714, 717, 794, 897. +\:\\{start\_decimal\_token}, \[667], 669. +\:\\{start\_def}, \[683], 684, 697, 698, 700. +\:\\{start\_field}, \[627], 629. +\:\\{start\_forever}, \[683], 684, 755. +\:\\{start\_here}, 5, \[1204]. +\:\\{start\_input}, 706, 709, 711, \[793], 1211. +\:\\{start\_numeric\_token}, \[667], 669. +\:\\{start\_of\_MF}, \[6], 1204. +\:\\{start\_screen}, \[570], 574. +\:\\{start\_sym}, 1076, \[1077], 1078, 1198, 1199, 1204. +\:\\{stash\_cur\_exp}, 651, 718, 728, 734, 760, 764, \[799], 800, 801, 837, +839, 848, 859, 862, 863, 864, 868, 926, 946, 955, 970, 988, 995, 1000. +\:\\{stash\_in}, \[827], 830, 903. +\:\&{stat}, \[7], \[160], \[163], \[164], \[165], \[167], \[172], \[177], % +\[207], \[508], \[510], \[515], \[521], \[1045], \[1134], \[1205]. +\:\\{state}, 670. +\:\9{step\_}{\&{step} primitive}, \[211]. +\:\\{step\_size}, \[752], 760, 761, 765. +\:\\{step\_token}, \[186], 211, 212, 764. +\:{Stern, Moritz Abraham}, 526. +\:{Stolfi, Jorge}, 469. +\:\\{stop}, \[186], 732, 991, 1017, 1018, 1019. +\:\\{stop\_flag}, \[1093], 1107, 1110. +\:\\{stop\_iteration}, 706, 714, 760, \[763], 1209. +\:\\{store\_base\_file}, \[1186], 1209. +\:\9{str\_}{\&{str} primitive}, \[211]. +\:\\{str\_eq\_buf}, \[45], 205. +\:\\{str\_number}, \[37], 38, 42, 43, 44, 45, 46, 47, 62, 74, 88, 89, 90, 94, +190, 197, 210, 214, 257, 332, 394, 395, 398, 473, 754, 767, 774, 780, 782, 784, +785, 786, 791, 807, 824, 976, 977, 1087, 1160, 1183. +\:\\{str\_op}, \[186], 211, 212, 823. +\:\\{str\_pool}, 37, \[38], 41, 44, 45, 46, 47, 59, 60, 85, 200, 210, 223, 630, +707, 717, 774, 913, 976, 977, 1103, 1160, 1192, 1193, 1208. +\:\\{str\_ptr}, 37, \[38], 40, 43, 44, 47, 59, 60, 210, 218, 772, 780, 793, +798, 1045, 1163, 1192, 1193, 1199, 1200, 1204. +\:\\{str\_ref}, \[42], 43, 44, 48, 52, 207, 793, 1193, 1200. +\:\\{str\_room}, \[41], 207, 671, 771, 780, 897, 912, 976, 977, 1200, 1205. +\:\\{str\_start}, 37, \[38], 39, 40, 43, 44, 45, 46, 47, 59, 60, 85, 200, 210, +223, 717, 772, 774, 913, 976, 977, 1103, 1160, 1163, 1192, 1193. +\:\\{str\_to\_num}, 912, \[913]. +\:\\{str\_vs\_str}, \[46], 936, 1004. +\:\.{Strange path...}, 1068. +\:\.{String contains illegal digits}, 914. +\:{string pool}, 47, 1191. +\:\9{string\_}{\&{string} primitive}, \[1013]. +\:\\{string\_class}, \[198], 199, 219, 669. +\:\\{string\_token}, \[186], 671, 678, 691, 743, 823. +\:\\{string\_type}, \[187], 189, 214, 216, 219, 248, 621, 651, 716, 798, 802, +808, 809, 833, 840, 855, 895, 897, 912, 915, 918, 919, 936, 975, 993, 1003, +1004, 1013, 1082, 1103, 1176, 1177. +\:\\{string\_vacancies}, \[11], 52. +\:\\{structured}, \[187], 188, 228, 229, 239, 242, 243, 246, 247, 809, 850, +1046. +\:\\{structured\_root}, \[188], 229, 236, 239. +\:\9{subpath\_}{\&{subpath} primitive}, \[893]. +\:\\{subpath\_of}, \[189], 893, 975. +\:\\{subscr}, \[188], 229, 236, 239, 244, 246, 247, 1047. +\:\\{subscr\_head}, \[228], 229, 239, 240, 244, 246, 247, 1047. +\:\\{subscr\_head\_loc}, \[228], 240, 241, 244, 246. +\:\\{subscr\_node\_size}, \[229], 240, 244, 246, 247. +\:\\{subscript}, \[229], 236, 240, 244. +\:\\{subscript\_loc}, \[229], 244. +\:\\{subst\_list}, \[685], 686. +\:\9{substring\_}{\&{substring} primitive}, \[893]. +\:\\{substring\_of}, \[189], 893, 975. +\:\\{succumb}, \[88], 89, 90. +\:\.{SUFFIX}, 222. +\:\9{suffix\_}{\&{suffix} primitive}, \[695]. +\:\\{suffix\_base}, \[214], 222, 676, 677, 683, 690, 695, 696, 697, 705, 726, +729, 755, 764. +\:\\{suffix\_count}, \[685], 690. +\:\\{suffix\_macro}, \[226], 227, 705, 733. +\:\\{suffixed\_macro}, \[187], 700, 798, 809, 845, 1048. +\:\\{sum}, \[378]. +\:\\{switch}, \[667], 669, 670, 672. +\:\\{switch\_x\_and\_y}, \[139], 406, 423, 424, 441, 442, 445, 480, 489. +\:\\{sx}, \[601]. +\:\\{symmetric}, \[527], 528, 530. +\:{system dependencies}, 2, \[3], 4, 9, 10, 11, 12, 19, 21, 22, 25, 26, 27, 31, +32, 33, 34, 36, 49, 56, 59, 67, 76, 79, 91, 107, 109, 153, 155, 156, 194, 199, +564, 567, 568, 631, 637, 654, 766, 767, 768, 769, 770, 771, 772, 773, 774, 775, +776, 778, 780, 781, 794, 1148, 1152, 1154, 1203, 1204, 1205, 1212, 1214. +\:\\{s1}, \[77], 83. +\:\\{s2}, \[77], 83. +\:\\{s3}, \[77], 83. +\:\|{t}, \[46], \[116], \[139], \[145], \[167], \[187], \[197], \[238], \[242], +\[246], \[280], \[284], \[311], \[321], \[340], \[342], \[344], \[398], \[406], +\[410], \[419], \[493], \[495], \[497], \[542], \[589], \[594], \[597], \[601], +\[603], \[604], \[610], \[621], \[649], \[801], \[805], \[809], \[843], \[855], +\[860], \[868], \[875], \[899], \[900], \[930], \[935], \[943], \[949], \[968], +\[972], \[974], \[1001], \[1006], \[1011], \[1015], \[1029], \[1054], \[1057], % +\[1104], \[1160], \[1163]. +\:\\{t\_of\_the\_way}, \[410], 411, 415, 424, 499, 503, 504, 547, 548. +\:\\{t\_of\_the\_way\_end}, \[410]. +\:\\{t\_open\_in}, \[32], 36. +\:\\{t\_open\_out}, \[32], 1204. +\:\\{tag}, \[1091], 1092. +\:\\{tag\_token}, \[186], 202, 229, 234, 242, 249, 254, 702, 823, 844, 850, +860, 1011, 1035, 1043, 1049. +\:\\{tail}, \[720], 724, 728, 734, 842, \[843], 844, 845. +\:\\{tail\_end}, \[685]. +\:\\{take\_fraction}, \[109], 112, 116, 125, 127, 151, 152, 281, 287, 288, 289, +290, 291, 294, 295, 296, 297, 299, 300, 302, 375, 376, 410, 436, 439, 444, 454, +498, 516, 522, 530, 533, 543, 594, 595, 596, 599, 943, 944. +\:\\{take\_part}, 909, \[910], 939. +\:\\{take\_scaled}, \[112], 594, 595, 596, 599, 942, 943, 961, 968, 971, 974. +\:\\{tally}, \[54], 55, 57, 58, 217, 227, 235, 636, 639, 640, 641, 642, 643. +\:\\{tarnished}, 926, 927, \[928], 944. +\:\&{tats}, \[7]. +\:\\{temp\_head}, \[175], 335, 346, 347, 349, 351, 484, 594, 597, 599, 600, +601, 612, 616, 1117, 1118, 1121, 1124, 1126. +\:\\{temp\_val}, \[175], 910, 911. +\:\\{tension}, \[186], 211, 212, 881. +\:\9{tension\_}{\&{tension} primitive}, \[211]. +\:\\{term\_and\_log}, \[54], 57, 58, 66, 70, 87, 195, 788, 804, 1200, 1209. +\:\\{term\_in}, \[31], 32, 33, 35, 36, 66, 1212, 1213. +\:\\{term\_input}, \[66], 73. +\:\\{term\_offset}, \[54], 55, 57, 58, 61, 62, 66, 793, 1165. +\:\\{term\_only}, \[54], 55, 57, 58, 66, 70, 87, 789, 804, 1205, 1209. +\:\\{term\_out}, \[31], 32, 33, 34, 35, 36, 51, 56. +\:\\{terminal\_input}, \[631], 637, 654, 656. +\:\\{terminator}, \[685]. +\:\9{tertiary\_}{\&{tertiary} primitive}, \[695]. +\:\\{tertiary\_binary}, \[186], 893, 894. +\:\9{tertiary\_def\_}{\&{tertiarydef} primitive}, \[683]. +\:\\{tertiary\_macro}, \[226], 227, 695, 733. +\:\\{tertiary\_secondary\_macro}, \[186], 249, 683, 684, 864, 1035, 1043. +\:\\{test\_known}, 918, \[919]. +\:\\{text}, \[200], 202, 203, 205, 206, 207, 210, 218, 254, 638, 664, 722, 725, +727, 735, 759, 1032, 1034, 1036, 1041, 1043, 1196. +\:\.{TEXT}, 222. +\:\.{Text line contains...}, 670. +\:\9{text\_}{\&{text} primitive}, \[695]. +\:\\{text\_base}, \[214], 222, 677, 695, 697, 723, 729. +\:\\{text\_char}, \[19], 20, 24, 26, 47. +\:\\{text\_macro}, \[226], 227, 697, 705, 723, 733. +\:\9{TFM files}{\.{TFM} files}, 1087. +\:\\{tfm\_changed}, 1129, \[1130], 1132, 1136, 1140. +\:\\{tfm\_check}, \[1098], 1099. +\:\\{tfm\_command}, \[186], 1100, 1101, 1102. +\:\\{tfm\_depth}, \[1096], 1097, 1099, 1126, 1136. +\:\\{tfm\_file}, \[1087], 1133, 1134. +\:\\{tfm\_four}, \[1133], 1136, 1139, 1140. +\:\\{tfm\_height}, \[1096], 1097, 1099, 1126, 1136. +\:\\{tfm\_ital\_corr}, \[1096], 1097, 1099, 1126, 1136. +\:\\{tfm\_out}, \[1133], 1135, 1136, 1139. +\:\\{tfm\_qqqq}, \[1133], 1139, 1140. +\:\\{tfm\_two}, \[1133], 1135, 1139. +\:\\{tfm\_warning}, \[1123], 1124, 1126. +\:\\{tfm\_width}, \[1096], 1097, 1099, 1124, 1131, 1132, 1136, 1182, 1205. +\:\.{That makes 100 errors...}, 77. +\:\.{That transformation...}, 963. +\:\.{The token...delimiter}, 1032. +\:\.{The token...quantity}, 1034. +\:\.{There's unbounded black...}, 1169. +\:\\{theta}, \[283], 291, 292, 295, 297, \[527], 530, 533, \[542], 544, \[865], +866. +\:\\{thing\_to\_add}, \[186], 1052, 1053, 1059. +\:\\{third\_octant}, \[139], 141, 379, 380, 387, 388, 393, 396, 406, 443, 449, +461, 462. +\:\.{This can't happen}, 90. +\:\9{this can't happen /}{\quad \./}, 107, 114. +\:\9{this can't happen copy}{\quad copy}, 855. +\:\9{this can't happen dep}{\quad dep}, 589. +\:\9{this can't happen endinput}{\quad endinput}, 655. +\:\9{this can't happen exp}{\quad exp}, 802. +\:\9{this can't happen if}{\quad if}, 746. +\:\9{this can't happen m}{\quad m}, 311. +\:\9{this can't happen recycle}{\quad recycle}, 809. +\:\9{this can't happen struct}{\quad struct}, 239. +\:\9{this can't happen token}{\quad token}, 216. +\:\9{this can't happen var}{\quad var}, 236. +\:\9{this can't happen xy}{\quad xy}, 362. +\:\9{this can't happen 0}{\quad 0}, 378. +\:\.{This variable already...}, 701. +\:\\{three}, \[101], 296. +\:\\{three\_bytes}, \[1128], 1129, 1133, 1157, 1182. +\:\\{three\_choices}, \[156]. +\:\\{three\_l}, \[557], 558, 559, 560, 561. +\:\\{three\_quarter\_unit}, \[101], 883. +\:\\{three\_sixty\_deg}, \[106], 145, 292. +\:\\{three\_sixty\_units}, \[906], 958. +\:\\{threshold}, \[594], 595, 596, \[597], 598, \[599], \[600], \[1120], 1121. +\:\\{time}, \[190], 192, 193, 194, 790, 1163, 1211. +\:\9{time\_}{\&{time} primitive}, \[192]. +\:\\{time\_to\_go}, \[555], 556. +\:\\{times}, \[189], 837, 859, 893, 941, 944. +\:\&{tini}, \[8]. +\:\9{to\_}{\&{to} primitive}, \[211]. +\:\\{to\_token}, \[186], 211, 212, 1073. +\:{token}, 214. +\:\\{token}, \[188], 214, 215, 219, 651, 678. +\:\\{token\_list}, \[187], 670, 726, 728, 730, 798, 799, 809, 841, 852, 860, +996, 1059, 1070, 1071, 1074. +\:\\{token\_node\_size}, \[214], 215, 216, 651, 694, 704, 705, 755. +\:\\{token\_recycle}, 216, \[224]. +\:\\{token\_state}, \[632], 652, 672, 712, 736, 795, 1209. +\:\\{token\_type}, \[632], 635, 636, 638, 645, 649, 650, 653, 714. +\:\\{tol}, 552, 553, 556, \[557], 558, 559, 560, 561. +\:\\{tol\_step}, \[552], 557, 559, 561, 562. +\:\.{Too far to shift}, 965. +\:\.{Too far to skip}, 1110. +\:\.{Too many arguments...}, 725. +\:\\{too\_small}, \[1187], 1189. +\:\\{top}, \[1094]. +\:\\{top\_row}, \[567], \[572], 574, 577. +\:\\{toss\_edges}, \[385], 808, 809, 964. +\:\\{toss\_knot\_list}, \[268], 465, 506, 808, 809, 865, 921, 978, 1064, 1067. +\:\\{toss\_pen}, 475, \[487]. +\:\\{total\_chars}, \[1149], 1150, 1165, 1182. +\:\\{total\_weight}, \[369], 921. +\:\9{total\_weight\_}{\&{totalweight} primitive}, \[893]. +\:\\{total\_weight\_op}, \[189], 893, 921. +\:\\{trace\_a\_corner}, \[372], 373. +\:\\{trace\_new\_edge}, \[373], 375, 376, 381, 382, 383, 384. +\:\\{trace\_x}, \[371], 372, 373. +\:\\{trace\_y}, \[371], 372, 373. +\:\\{trace\_yy}, \[371], 372, 373. +\:\\{tracing}, \[402]. +\:\\{tracing\_capsules}, \[190], 192, 193, 238. +\:\9{tracing\_capsules\_}{\&{tracingcapsules} primitive}, \[192]. +\:\\{tracing\_choices}, \[190], 192, 193, 269. +\:\9{tracing\_choices\_}{\&{tracingchoices} primitive}, \[192]. +\:\\{tracing\_commands}, \[190], 192, 193, 707, 713, 748, 760, 832, 895, 898, +922, 944, 992, 995, 996. +\:\9{tracing\_commands\_}{\&{tracingcommands} primitive}, \[192]. +\:\\{tracing\_edges}, \[190], 192, 193, 371, 375, 376, 381, 382, 383, 384, 465, +506, 508, 510, 515, 521. +\:\9{tracing\_edges\_}{\&{tracingedges} primitive}, \[192]. +\:\\{tracing\_equations}, \[190], 192, 193, 603, 610, 816. +\:\9{tracing\_equations\_}{\&{tracingequations} primitive}, \[192]. +\:\\{tracing\_macros}, \[190], 192, 193, 720, 728, 734. +\:\9{tracing\_macros\_}{\&{tracingmacros} primitive}, \[192]. +\:\\{tracing\_online}, \[190], 192, 193, 195, 804. +\:\9{tracing\_online\_}{\&{tracingonline} primitive}, \[192]. +\:\\{tracing\_output}, \[190], 192, 193, 1165. +\:\9{tracing\_output\_}{\&{tracingoutput} primitive}, \[192]. +\:\\{tracing\_pens}, \[190], 192, 193, 253, 477. +\:\9{tracing\_pens\_}{\&{tracingpens} primitive}, \[192]. +\:\\{tracing\_restores}, \[190], 192, 193, 254. +\:\9{tracing\_restores\_}{\&{tracingrestores} primitive}, \[192]. +\:\\{tracing\_specs}, \[190], 192, 193, 1064. +\:\9{tracing\_specs\_}{\&{tracingspecs} primitive}, \[192]. +\:\\{tracing\_stats}, 160, \[190], 192, 193, 1134, 1198, 1205. +\:\9{tracing\_stats\_}{\&{tracingstats} primitive}, \[192]. +\:\\{tracing\_titles}, \[190], 192, 193, 994. +\:\9{tracingtitles\_}{\&{tracingtitles} primitive}, \[192]. +\:\\{trans}, \[961], 962. +\:\\{trans\_spec}, \[565], 568, 579. +\:\.{Transcript written...}, 1205. +\:\.{Transform components...}, 960. +\:\9{transform\_}{\&{transform} primitive}, \[1013]. +\:\\{transform\_node\_size}, \[230], 231, 233, 956. +\:\\{transform\_type}, \[187], 216, 230, 231, 232, 233, 248, 798, 799, 800, +802, 808, 809, 855, 909, 918, 919, 926, 927, 936, 944, 952, 953, 955, 967, 970, +973, 1003, 1013, 1015. +\:\9{transformed\_}{\&{transformed} primitive}, \[893]. +\:\\{transformed\_by}, \[189], 893, 952, 953, 957. +\:\.{transition line...}, 515, 521. +\:\\{trick\_buf}, \[54], 58, 641, 643. +\:\\{trick\_count}, \[54], 58, 641, 642, 643. +\:\\{trivial\_knot}, 484, 485, \[486]. +\:\\{true}, 4, 16, 30, 33, 36, 45, 49, 51, 53, 66, 72, 83, 92, 93, 97, 100, +107, 109, 110, 112, 114, 124, 126, 135, 181, 182, 238, 257, 269, 332, 372, 394, +402, 407, 426, 446, 452, 454, 455, 473, 477, 497, 503, 504, 530, 564, 567, 568, +569, 570, 574, 577, 592, 593, 595, 596, 598, 599, 600, 621, 653, 654, 661, 670, +672, 675, 680, 681, 700, 711, 767, 771, 779, 788, 801, 886, 899, 913, 942, 946, +968, 969, 977, 978, 1003, 1009, 1010, 1054, 1056, 1064, 1072, 1086, 1099, 1112, +1137, 1165, 1187. +\:\9{true\_}{\&{true} primitive}, \[893]. +\:\\{true\_code}, \[189], 713, 748, 750, 798, 802, 892, 893, 895, 905, 906, +918, 919, 920, 940. +\:\\{try\_eq}, 1003, 1005, \[1006]. +\:\\{tt}, \[167], 169, \[539], 541, 547, 548, \[594], 595, 596, 842, \[843], +844, 845, 850, \[1006], 1009, 1010. +\:\\{turning\_check}, \[190], 192, 193, 1068. +\:\9{turning\_check\_}{\&{turningcheck} primitive}, \[192]. +\:\\{turning\_number}, \[403], 450, 459, 917, 1068. +\:\9{turning\_number\_}{\&{turningnumber} primitive}, \[893]. +\:\\{turning\_op}, \[189], 893, 917. +\:\\{two}, \[101], 102, 256, 294, 295, 556, 895, 898, 922, 944, 995, 996. +\:\\{two\_choices}, \[156]. +\:\\{two\_halves}, \[156], 161, 166, 185, 201. +\:\\{two\_to\_the}, \[129], 131, 133, 136, 143, 147, 314, 317, 608, 616. +\:\\{tx}, \[374], 375, 376, \[511], 516, 522, 866, 867, 953, \[954], 956, 960, +961, 962, 965, 967, 973. +\:\\{txx}, 866, 953, \[954], 956, 960, 961, 963, 964, 967, 973. +\:\\{txy}, 866, 953, \[954], 956, 960, 961, 963, 967, 973. +\:\\{ty}, \[511], 516, 522, 866, 867, 953, \[954], 956, 960, 961, 962, 965, +967, 973. +\:\\{type}, \[4], 188, \[214], 215, 216, 219, 228, 229, 232, 233, 234, 239, +242, 243, 244, 245, 246, 247, 248, 585, 587, 589, 595, 596, 598, 599, 600, 603, +604, 605, 614, 615, 619, 621, 651, 678, 700, 738, 744, 745, 746, 799, 800, 801, +803, 809, 812, 819, 827, 829, 830, 842, 850, 855, 856, 857, 858, 868, 873, 899, +903, 910, 919, 923, 926, 928, 929, 930, 931, 932, 935, 936, 939, 940, 941, 942, +943, 946, 947, 948, 949, 951, 952, 956, 957, 959, 966, 968, 969, 971, 972, 975, +982, 983, 988, 995, 1000, 1001, 1002, 1006, 1007, 1009, 1015, 1046, 1048, 1050, +1057. +\:\.{Type <return> to proceed...}, 80. +\:\\{type\_name}, \[186], 823, 989, 992, 1013, 1014, 1015. +\:\\{type\_range}, \[918]. +\:\\{type\_range\_end}, \[918]. +\:\\{type\_test}, \[918]. +\:\\{type\_test\_end}, \[918]. +\:\\{tyx}, 866, 953, \[954], 956, 960, 961, 963, 967, 973. +\:\\{tyy}, 866, 953, \[954], 956, 960, 961, 963, 964, 967, 973. +\:\\{t0}, \[495], \[497], 498, 503, \[599], \[600]. +\:\\{t1}, \[495], \[497], 498, 499, 503, \[599], \[600]. +\:\\{t2}, \[495], \[497], 498, 499, 503. +\:\|{u}, \[152], \[311], \[344], \[432], \[527], \[946], \[968], \[972], \[974]. +\:\\{u\_packet}, \[553], 556, 559, 560. +\:\\{ul\_packet}, \[553], 559. +\:\\{unary}, \[186], 823, 893, 894. +\:\\{und\_type}, \[248], 1000. +\:\\{undefined}, \[187], 229, 234, 239, 242, 244, 245, 247, 248, 585, 809, 842, +844, 845, 850, 1046. +\:\.{Undefined condition...}, 892. +\:\.{Undefined coordinates...}, 872, 873, 878. +\:\\{undefined\_label}, \[1096], 1097, 1110, 1111, 1137, 1139, 1141. +\:\\{undump}, \[1189], 1193, 1195, 1197, 1199. +\:\\{undump\_end}, \[1189]. +\:\\{undump\_end\_end}, \[1189]. +\:\\{undump\_four\_ASCII}, \[1193]. +\:\\{undump\_hh}, \[1189], 1197. +\:\\{undump\_int}, \[1189], 1191, 1195, 1197, 1199. +\:\\{undump\_qqqq}, \[1189], 1193. +\:\\{undump\_size}, \[1189], 1193. +\:\\{undump\_size\_end}, \[1189]. +\:\\{undump\_size\_end\_end}, \[1189]. +\:\\{undump\_wd}, \[1189], 1195. +\:\\{unequal\_to}, \[189], 893, 936, 937. +\:\\{unif\_rand}, \[151], 906. +\:\\{uniform\_deviate}, \[189], 893, 906. +\:\9{uniform\_deviate\_}{\&{uniformdeviate} primitive}, \[893]. +\:\\{unity}, \[101], 103, 112, 114, 115, 116, 119, 132, 194, 233, 256, 258, +271, 282, 288, 294, 295, 296, 300, 302, 311, 374, 375, 376, 402, 430, 431, 433, +462, 463, 508, 510, 515, 516, 521, 522, 530, 539, 548, 555, 556, 562, 590, 674, +675, 707, 713, 748, 760, 816, 817, 819, 876, 881, 883, 886, 887, 890, 891, 896, +906, 913, 915, 916, 917, 932, 943, 949, 960, 963, 964, 968, 969, 972, 974, 978, +980, 985, 1010, 1068, 1071, 1074, 1097, 1128, 1133, 1157, 1158, 1166, 1182, +1211. +\:\.{Unknown relation...}, 937. +\:\.{Unknown value...ignored}, 1021. +\:\9{unknown\_}{\&{unknown} primitive}, \[893]. +\:\\{unknown\_boolean}, \[187], 229, 248, 618, 798, 799, 918, 936. +\:\\{unknown\_op}, \[189], 893, 918. +\:\\{unknown\_path}, \[187], 248, 618, 798, 918, 995, 1003. +\:\\{unknown\_pen}, \[187], 248, 618, 798. +\:\\{unknown\_picture}, \[187], 248, 618, 798, 918. +\:\\{unknown\_string}, \[187], 248, 618, 798, 918, 936. +\:\\{unknown\_tag}, \[187], 621, 1003, 1015. +\:\\{unknown\_types}, \[187], 216, 799, 800, 802, 808, 809, 855, 1003. +\:\\{unrotate}, 389. +\:\\{unsave}, \[254], 832. +\:\\{unskew}, \[388], 394, 421, 445, 447, 451, 454, 457, 485, 488, 510. +\:\\{unsorted}, 324, \[325], 326, 328, 330, 331, 332, 335, 338, 343, 344, 346, +348, 354, 355, 364, 367, 368, 369, 375, 376, 381, 382, 383, 384, 385, 578, 1169. +\:\\{unstash\_cur\_exp}, 718, \[800], 801, 859, 870, 926, 942, 946, 948, 962, +963, 988, 995, 1000. +\:\\{unsuffixed\_macro}, \[187], 700, 798, 809, 842, 844, 845, 1046, 1048. +\:\.{Unsuitable expression}, 1178. +\:\9{until\_}{\&{until} primitive}, \[211]. +\:\\{until\_token}, \[186], 211, 212, 765. +\:\\{update\_screen}, \[564], 569, 571, 574, 577. +\:\\{update\_terminal}, \[33], 36, 61, 66, 81, 564, 681, 779, 793, 994, 1165, +1212. +\:\\{ur\_packet}, \[553], 558, 559. +\:\\{use\_err\_help}, \[74], 75, 84, 86, 1086. +\:\\{uu}, \[283], 285, 287, 288, 290, 291, 293, 294, 295, 297. +\:\\{uv}, 553, 556, \[557], 558, 559, 560, 561. +\:\\{u1l}, \[553], 559. +\:\\{u1r}, \[553], 558, 559. +\:\\{u2l}, \[553], 559. +\:\\{u2r}, \[553], 558, 559. +\:\\{u3l}, \[553], 559. +\:\\{u3r}, \[553], 558, 559. +\:\|{v}, \[215], \[217], \[410], \[432], \[497], \[527], \[589], \[594], % +\[597], \[599], \[600], \[601], \[607], \[610], \[621], \[801], \[808], \[809], +\[820], \[900], \[922], \[930], \[935], \[943], \[944], \[946], \[949], \[961], +\[971], \[972], \[974], \[985], \[1001], \[1117], \[1121]. +\:\\{v\_is\_scaled}, \[599], \[943]. +\:\\{v\_packet}, \[553], 556, 559, 560. +\:\\{vacuous}, \[187], 216, 219, 248, 621, 764, 798, 799, 800, 802, 809, 827, +844, 855, 919, 989, 992, 993, 996, 1003, 1054, 1059, 1070, 1071, 1074. +\:\\{val\_too\_big}, \[602], 603, 615. +\:\\{valid\_range}, \[326], 329, 965. +\:\\{value}, \[214], 215, 216, 219, 220, 228, 229, 230, 232, 233, 239, 242, +244, 246, 250, 253, 254, 585, 587, 589, 590, 591, 594, 595, 596, 597, 598, 599, +600, 601, 603, 604, 605, 607, 608, 609, 610, 611, 612, 615, 616, 617, 619, 620, +621, 622, 651, 678, 685, 686, 694, 698, 700, 704, 705, 752, 755, 760, 765, 798, +799, 800, 801, 803, 806, 809, 812, 814, 816, 817, 818, 819, 827, 829, 830, 845, +853, 855, 857, 858, 872, 873, 899, 903, 904, 907, 910, 915, 919, 928, 929, 930, +931, 933, 935, 936, 938, 939, 940, 942, 943, 944, 946, 948, 949, 951, 955, 956, +957, 958, 959, 966, 967, 968, 969, 970, 971, 972, 973, 974, 975, 976, 977, 978, +982, 983, 984, 988, 1000, 1001, 1005, 1006, 1007, 1008, 1009, 1010, 1015, 1048, +1057, 1072, 1116, 1117, 1118, 1121, 1122, 1127, 1132, 1136, 1182. +\:\.{Value is too large}, 602. +\:\\{value\_loc}, \[214], 587, 605, 812, 827, 947. +\:\\{value\_node\_size}, \[228], 233, 234, 239, 247, 249, 603, 615, 619, 650, +763, 799, 800, 808, 827, 830, 837, 855, 856, 857, 858, 903, 910, 922, 925, 931, +942, 944, 947, 955, 970, 982, 1001, 1006, 1117. +\:\\{var\_def}, \[683], 684, 697, 992. +\:\9{var\_def\_}{\&{vardef} primitive}, \[683]. +\:\\{var\_defining}, \[659], 664, 665, 700. +\:\\{var\_flag}, \[821], 822, 823, 824, 868, 993, 995, 996, 1059, 1070, 1071, +1074. +\:\\{var\_used}, \[160], 167, 172, 176, 1045, 1194, 1195. +\:\.{Variable x is the wrong type}, 1057. +\:\.{Variable...obliterated}, 851. +\:\\{velocity}, \[116], 275, 299. +\:\\{verbosity}, \[801], 802, 803, 804, \[805], 1040. +\:\.{VIRMF}, 1203. +\:{virtual memory}, 168. +\:{Vitter, Jeffrey Scott}, 208. +\:\\{vl\_packet}, \[553], 559. +\:\\{void}, \[324], 326, 328, 330, 331, 332, 335, 338, 343, 344, 346, 348, 354, +367, 368, 369, 385, 578, 639, 650, 719, 723, 752, 755, 760, 762, 763, 799, 926, +927, 928, 944, 1169. +\:\\{vppp}, \[190], 192, 193, \[1146], 1182. +\:\9{vppp\_}{\&{vppp} primitive}, \[192]. +\:\\{vr\_packet}, \[553], 558, 559. +\:\\{vv}, \[283], 285, 290, 291, 293, 294, 295, 297, \[809], 817, \[935], % +\[972]. +\:\\{v1l}, \[553], 559. +\:\\{v1r}, \[553], 558, 559. +\:\\{v2l}, \[553], 559. +\:\\{v2r}, \[553], 558, 559. +\:\\{v3l}, \[553], 559. +\:\\{v3r}, \[553], 558, 559. +\:\|{w}, \[157], \[333], \[342], \[348], \[357], \[373], \[473], \[476], % +\[477], \[484], \[487], \[488], \[491], \[497], \[510], \[511], \[580], \[599], +\[600], \[610], \[1059], \[1074], \[1165], \[1186], \[1187]. +\:\\{w\_close}, \[27], 1201, 1211. +\:\\{w\_hi}, \[348], 349. +\:\\{w\_in}, \[348], 349, \[1074], 1075. +\:\\{w\_lo}, \[348], 349. +\:\\{w\_make\_name\_string}, \[780], 1200. +\:\\{w\_open\_in}, \[26], 779. +\:\\{w\_open\_out}, \[26], 1200. +\:\\{w\_out}, \[348], 349, \[1074], 1075. +\:\\{wake\_up\_terminal}, \[33], 36, 51, 66, 68, 398, 682, 779, 786, 807, 1051, +1187, 1205, 1212. +\:\\{warning\_check}, \[190], 192, 193, 602. +\:\9{warning\_check\_}{\&{warningcheck} primitive}, \[192]. +\:\\{warning\_info}, \[659], 661, 664, 694, 698, 700, 701, 730, 742, 758. +\:\\{warning\_issued}, \[71], 195, 1209. +\:\\{was\_free}, \[178], 180, 184. +\:\\{was\_hi\_min}, \[178], 179, 180, 184. +\:\\{was\_lo\_max}, \[178], 179, 180, 184. +\:\\{was\_mem\_end}, \[178], 179, 180, 184. +\:\\{watch\_coefs}, \[592], 593, 595, 596, 598, 1010. +\:\\{we\_found\_it}, \[547], 548, 549. +\:\.{WEB}, 1, 4, 37, 39, 50, 1191. +\:\.{Weight must be...}, 1056. +\:\\{west\_edge}, \[435]. +\:\\{white}, \[565], 567, 568, 577, 579, 583, 584, 1143, 1144. +\:\\{width\_index}, \[1091]. +\:\\{window\_number}, \[571], 572, 574, 577. +\:\\{window\_open}, \[572], 573, 574, 1071. +\:\\{window\_time}, \[572], 573, 574, 577. +\:{Wirth, Niklaus}, 10. +\:\\{with\_option}, \[186], 1052, 1053, 1062, 1074. +\:\9{with\_pen\_}{\&{withpen} primitive}, \[1052]. +\:\9{with\_weight\_}{\&{withweight} primitive}, \[1052]. +\:\\{wlog}, \[56], 58, 564, 568, 790, 1208. +\:\\{wlog\_cr}, \[56], 57, 58, 567, 1205. +\:\\{wlog\_ln}, \[56], 564, 567, 568, 1141, 1208. +\:\\{word\_file}, 24, 26, 27, \[156], 780, 1188. +\:\\{write}, 36, 56, 1133, 1154. +\:\\{write\_gf}, \[1154], 1155, 1156. +\:\\{write\_ln}, 34, 36, 51, 56. +\:\\{wterm}, \[56], 58, 61. +\:\\{wterm\_cr}, \[56], 57, 58. +\:\\{wterm\_ln}, \[56], 61, 779, 1187, 1204. +\:\\{ww}, \[283], 285, 290, 291, 293, 294, \[348], 349, \[357], 362, \[473], +474, \[484], 485, \[487], \[488], \[491], \[497], 498, 502, 503, 508, 509, % +\[510], \[511], 513, 519, \[580], 582, 583, 584, \[1165], 1169. +\:\\{www}, \[506], 508. +\:\|{x}, \[100], \[104], \[119], \[121], \[132], \[135], \[139], \[145], % +\[149], \[151], \[152], \[234], \[387], \[388], \[390], \[391], \[463], \[486], +\[488], \[539], \[574], \[591], \[601], \[602], \[604], \[610], \[868], \[875], +\[898], \[982], \[1011], \[1129], \[1131], \[1133], \[1157], \[1158], \[1186], % +\[1187], \[1205]. +\:\\{x\_coord}, \[255], 256, 258, 265, 266, 271, 281, 282, 299, 302, 393, 394, +397, 404, 405, 406, 407, 409, 410, 411, 412, 413, 415, 416, 418, 419, 421, 423, +424, 425, 434, 436, 441, 442, 444, 445, 447, 451, 457, 467, 468, 472, 473, 474, +475, 476, 477, 479, 481, 483, 484, 485, 486, 488, 492, 493, 496, 498, 502, 508, +509, 510, 512, 513, 515, 518, 519, 521, 528, 534, 535, 536, 537, 543, 558, 563, +866, 867, 871, 887, 896, 962, 980, 981, 986, 987, 1066. +\:\\{x\_corr}, \[461], 462, 463. +\:\\{x\_height}, 1095. +\:\\{x\_height\_code}, \[1095]. +\:\\{x\_off}, \[332], \[333], \[1165], 1166, 1169, 1172. +\:\\{x\_offset}, \[190], 192, 193, 1165. +\:\9{x\_offset\_}{\&{xoffset} primitive}, \[192]. +\:\\{x\_packet}, \[553], 556, 559, 560. +\:\\{x\_part}, \[189], 893, 909, 910, 939. +\:\9{x\_part\_}{\&{xpart} primitive}, \[893]. +\:\\{x\_part\_loc}, \[230], 830, 873, 899, 903, 907, 915, 929, 942, 944, 946, +947, 948, 956, 957, 959, 967, 970, 973, 977, 978, 982, 984, 1072. +\:\\{x\_part\_sector}, \[188], 230, 232, 235, 237, 238. +\:\\{x\_reflect\_edges}, \[337], 964. +\:\\{x\_scale\_edges}, \[342], 964. +\:\\{x\_scaled}, \[189], 893, 952, 957. +\:\9{x\_scaled\_}{\&{xscaled} primitive}, \[893]. +\:\\{xchr}, \[20], 21, 22, 23, 37, 49, 58, 774. +\:\&{xclause}, 16. +\:\\{xi\_corr}, 306, \[311], 313, 314, 317. +\:\\{xl\_packet}, \[553], 559. +\:\\{xord}, \[20], 23, 30, 52, 53, 778, 780. +\:\\{xp}, \[511], 515, 516, 521, 522. +\:\\{xq}, \[410]. +\:\\{xr\_packet}, \[553], 558, 559. +\:\\{xw}, 362, \[363]. +\:\\{xx}, \[391], 392, \[511], 515, 516, 521, 522. +\:\\{xx\_part}, \[189], 893, 909. +\:\9{xx\_part\_}{\&{xxpart} primitive}, \[893]. +\:\\{xx\_part\_loc}, \[230], 233, 956, 957, 958, 959, 967, 970, 973. +\:\\{xx\_part\_sector}, \[188], 230, 237. +\:\\{xxx1}, 1144, \[1145], 1160. +\:\\{xxx2}, \[1144]. +\:\\{xxx3}, 1144, \[1145], 1160. +\:\\{xxx4}, \[1144]. +\:\\{xx0}, \[311]. +\:\\{xx1}, \[311]. +\:\\{xx2}, \[311]. +\:\\{xx3}, \[311]. +\:\\{xy}, 553, 556, \[557], 558, 559, 560, 561. +\:\\{xy\_corr}, \[461], 462, 468, 512, 513, 515, 516, 518, 519, 521, 522. +\:\\{xy\_part}, \[189], 893, 909. +\:\9{xy\_part\_}{\&{xypart} primitive}, \[893]. +\:\\{xy\_part\_loc}, \[230], 956, 957, 958, 959, 967, 970, 973. +\:\\{xy\_part\_sector}, \[188], 230, 237. +\:\\{xy\_round}, 402, \[433]. +\:\\{xy\_swap\_edges}, \[354], 963. +\:\\{x0}, \[374], 375, 376, \[391], 392, \[495], 496, \[497], 498, 499, 501, +503, 504, 505, \[510]. +\:\\{x0a}, \[495], 504. +\:\\{x1}, \[311], 312, 313, 314, 317, 318, \[374], \[391], 392, \[495], 496, % +\[497], 498, 499, 501, 503, 504, 505, \[510], 541, \[542], 543, 544, 546, 547, +548, 549. +\:\\{x1a}, \[495], 503, 504. +\:\\{x1l}, \[553], 559. +\:\\{x1r}, \[553], 558, 559. +\:\\{x2}, \[311], 312, 313, 314, 317, 318, \[391], 392, \[495], 496, \[497], +498, 499, 501, 503, 504, 505, \[542], 543, 546, 547, 548, 549. +\:\\{x2a}, \[311], 317, 318, \[495], 503. +\:\\{x2l}, \[553], 559. +\:\\{x2r}, \[553], 558, 559. +\:\\{x3}, \[311], 312, 313, 314, 317, 318, 541, \[542], 543, 546, 547, 548, 549. +\:\\{x3a}, \[311], 317, 318. +\:\\{x3l}, \[553], 559. +\:\\{x3r}, \[553], 558, 559. +\:\|{y}, \[100], \[104], \[121], \[132], \[135], \[139], \[145], \[151], % +\[387], \[388], \[390], \[463], \[486], \[488], \[539], \[574], \[868], \[982]. +\:\\{y\_coord}, \[255], 256, 258, 265, 266, 271, 281, 282, 299, 302, 393, 394, +397, 404, 405, 406, 407, 409, 410, 413, 414, 415, 416, 419, 421, 423, 424, 425, +435, 437, 439, 444, 445, 447, 451, 457, 467, 468, 472, 473, 474, 475, 476, 477, +479, 481, 483, 484, 485, 486, 488, 492, 493, 496, 498, 502, 508, 509, 510, 512, +515, 518, 521, 528, 534, 535, 536, 537, 543, 558, 563, 866, 867, 871, 887, 896, +962, 980, 981, 986, 987, 1066. +\:\\{y\_corr}, \[461], 462, 463, 468, 512, 515, 516, 518, 521, 522. +\:\\{y\_off}, \[332], \[1165], 1166, 1167, 1172. +\:\\{y\_offset}, \[190], 192, 193, 1165. +\:\9{y\_offset\_}{\&{yoffset} primitive}, \[192]. +\:\\{y\_packet}, \[553], 556, 559, 560. +\:\\{y\_part}, \[189], 893, 909. +\:\9{y\_part\_}{\&{ypart} primitive}, \[893]. +\:\\{y\_part\_loc}, \[230], 830, 873, 899, 903, 907, 915, 929, 942, 944, 946, +947, 948, 956, 957, 959, 967, 970, 973, 977, 978, 982, 984, 1072. +\:\\{y\_part\_sector}, \[188], 230, 237. +\:\\{y\_reflect\_edges}, \[336], 964. +\:\\{y\_scale\_edges}, \[340], 964. +\:\\{y\_scaled}, \[189], 893, 952, 957. +\:\9{y\_scaled\_}{\&{yscaled} primitive}, \[893]. +\:\\{year}, \[190], 192, 193, 194, 790, 1163, 1200. +\:\9{year\_}{\&{year} primitive}, \[192]. +\:\\{yl\_packet}, \[553], 559. +\:\.{You have to increase POOLSIZE}, 52. +\:\.{You want to edit file x}, 79. +\:\\{yp}, \[511], 515, 516, 521, 522. +\:\\{yq}, \[410]. +\:\\{yr\_packet}, \[553], 558, 559. +\:\\{yt}, \[374]. +\:\\{yx\_part}, \[189], 893, 909. +\:\9{yx\_part\_}{\&{yxpart} primitive}, \[893]. +\:\\{yx\_part\_loc}, \[230], 956, 958, 959, 967, 970, 973. +\:\\{yx\_part\_sector}, \[188], 230, 237. +\:\\{yy}, \[511], 515, 516, 521, 522. +\:\\{yy\_part}, \[189], 893, 909. +\:\9{yy\_part\_}{\&{yypart} primitive}, \[893]. +\:\\{yy\_part\_loc}, \[230], 233, 956, 957, 958, 959, 967, 970, 973. +\:\\{yy\_part\_sector}, \[188], 230, 237. +\:\\{yyy}, 1144, \[1145], 1147, 1166, 1177. +\:\\{yy0}, \[311]. +\:\\{yy1}, \[311]. +\:\\{yy2}, \[311]. +\:\\{yy3}, \[311]. +\:\\{y0}, \[374], 375, 376, \[495], 496, \[497], 498, 499, 501, 503, 504, 505, % +\[510]. +\:\\{y0a}, \[495], 504. +\:\\{y1}, \[311], 312, 313, 314, 317, 318, \[374], 375, 376, \[495], 496, % +\[497], 498, 499, 501, 503, 504, 505, \[510], 541, \[542], 543, 544, 546, 547, +548. +\:\\{y1a}, \[495], 503, 504. +\:\\{y1l}, \[553], 559. +\:\\{y1r}, \[553], 558, 559. +\:\\{y2}, \[311], 312, 313, 314, 317, 318, \[495], 496, \[497], 498, 499, 501, +503, 504, 505, \[542], 543, 546, 547, 548. +\:\\{y2a}, \[311], 317, 318, \[495], 503. +\:\\{y2l}, \[553], 559. +\:\\{y2r}, \[553], 558, 559. +\:\\{y3}, \[311], 312, 313, 314, 317, 318, 541, \[542], 543, 546, 547, 548. +\:\\{y3a}, \[311], 317, 318. +\:\\{y3l}, \[553], 559. +\:\\{y3r}, \[553], 558, 559. +\:\|{z}, \[132], \[135], \[139], \[145]. +\:\\{z\_corr}, \[461], 462, 463. +\:\\{z\_scaled}, \[189], 893, 952, 957. +\:\9{z\_scaled\_}{\&{zscaled} primitive}, \[893]. +\:{Zabala Salelles, Ignacio Andres}, 812. +\:\\{zero\_crossing}, \[391]. +\:\\{zero\_field}, \[326], 328, 329, 332, 336, 337, 340, 342, 352, 364, 365, +366, 370, 374, 377, 378, 577, 1167, 1172. +\:\\{zero\_val}, \[175], 1126, 1127. +\:\\{zero\_w}, \[324], 326, 333, 337, 349, 350, 358, 365, 370, 373, 375, 376, +381, 382, 383, 384, 582, 1169. +\fin +\:\X1060:Abandon edges command because there's no variable\X +\Us1059, 1070, 1071\ETs1074. +\:\X703:Absorb delimited parameters, putting them into lists \|q and \|r\X +\U697. +\:\X704:Absorb parameter tokens for type \\{base}\X +\U703. +\:\X705:Absorb undelimited parameters, putting them into list \|r\X +\U697. +\:\X931:Add a known value to the constant term of $\\{dep\_list}(\|p)$\X +\U930. +\:\X1010:Add dependency list \\{pp} of type \\{tt} to dependency list~\|p of +type~\|t\X +\U1009. +\:\X382:Add edges for fifth or eighth octants, then \&{goto} \\{done}\X +\U378. +\:\X381:Add edges for first or fourth octants, then \&{goto} \\{done}\X +\U378. +\:\X383:Add edges for second or third octants, then \&{goto} \\{done}\X +\U378. +\:\X384:Add edges for sixth or seventh octants, then \&{goto} \\{done}\X +\U378. +\:\X932:Add operand \|p to the dependency list \|v\X +\U930. +\:\X929:Add or subtract the current expression from \|p\X +\U922. +\:\X370:Add the contribution of node \|q to the total weight, and set $\|q\K% +\\{link}(\|q)$\X +\Us369\ET369. +\:\X933:Add the known $\\{value}(\|p)$ to the constant term of \|v\X +\U932. +\:\X1009:Add the right operand to list \|p\X +\U1006. +\:\X936, 940, 941, 948, 951, 952, 975, 983, 988:Additional cases of binary +operators\X +\U922. +\:\X905, 906, 907, 909, 912, 915, 917, 918, 920, 921:Additional cases of unary +operators\X +\U898. +\:\X291:Adjust $\theta_n$ to equal $\theta_0$ and \&{goto} \\{found}\X +\U287. +\:\X731:Adjust the balance for a delimited argument; \&{goto} \\{done} if done\X +\U730. +\:\X732:Adjust the balance for an undelimited argument; \&{goto} \\{done} if +done\X +\U730. +\:\X687:Adjust the balance; \&{goto} \\{done} if it's zero\X +\U685. +\:\X575:Adjust the coordinates $(\\{r0},\\{c0})$ and $(\\{r1},\\{c1})$ so that +they lie in the proper range\X +\U574. +\:\X367:Adjust the data of \|h to account for a difference of offsets\X +\U366. +\:\X364:Adjust the header to reflect the new edges\X +\U354. +\:\X360:Advance pointer \|p to the next vertical edge, after destroying the +previous one\X +\U358. +\:\X359:Advance pointer \|r to the next vertical edge\X +\U358. +\:\X560:Advance to the next pair $(\\{cur\_t},\\{cur\_tt})$\X +\U556. +\:\X492:Advance \|p to node \|q, removing any ``dead'' cubics that might have +been introduced by the splitting process\X +\U491. +\:\X171:Allocate entire node \|p and \&{goto} \\{found}\X +\U169. +\:\X170:Allocate from the top of node \|p and \&{goto} \\{found}\X +\U169. +\:\X1002:Announce that the equation cannot be performed\X +\U1001. +\:\X728:Append the current expression to \\{arg\_list}\X +\Us726\ET733. +\:\X236:Ascend one level, pushing a token onto list \|q and replacing \|p by +its parent\X +\U235. +\:\X999:Assign the current expression to an internal variable\X +\U996. +\:\X1000:Assign the current expression to the variable \\{lhs}\X +\U996. +\:\X698:Attach the replacement text to the tail of node \|p\X +\U697. +\:\X1061:Augment some edges by others\X +\U1059. +\:\X662:Back up an outer symbolic token so that it can be reread\X +\U661. +\:\X57, 58, 59, 60, 62, 63, 64, 103, 104, 187, 195, 197, 773:Basic printing +procedures\X +\U4. +\:\X530:Calculate integers $\alpha$, $\beta$, $\gamma$ for the vertex +coordinates\X +\U528. +\:\X292:Calculate the given value of $\theta_n$ and \&{goto} \\{found}\X +\U284. +\:\X289:Calculate the ratio $\\{ff}=C_k/(C_k+B_k-u_{k-1}A_k)$\X +\U287. +\:\X281:Calculate the turning angles $\psi_k$ and the distances $d_{k,k+1}$; +set $n$ to the length of the path\X +\U278. +\:\X288:Calculate the values $\\{aa}=A_k/B_k$, $\\{bb}=D_k/C_k$, $\\{dd}=(3-% +\alpha_{k-1})d_{k,k+1}$, $\\{ee}=(3-\beta\k)d_{k-1,k}$, and $% +\\{cc}=(B_k-u_{k-1}A_k)/B_k$\X +\U287. +\:\X290:Calculate the values of $v_k$ and $w_k$\X +\U287. +\:\X1020, 1023, 1026, 1030, 1033, 1039, 1058, 1069, 1076, 1081, 1100, +1175:Cases of \\{do\_statement} that invoke particular commands\X +\U992. +\:\X212, 684, 689, 696, 710, 741, 894, 1014, 1019, 1025, 1028, 1038, 1043, +1053, 1080, 1102, 1109, 1180:Cases of \\{print\_cmd\_mod} for symbolic printing +of primitives\X +\U625. +\:\X866:Change node \|q to a path for an elliptical pen\X +\U865. +\:\X563:Change one-point paths into dead cycles\X +\U562. +\:\X81:Change the interaction level and \&{return}\X +\U79. +\:\X1063:Change the tentative pen\X +\U1062. +\:\X701:Change to `\.{a bad variable}'\X +\U700. +\:\X615:Change variable \|x from \\{independent} to \\{dependent} or \\{known}\X +\U610. +\:\X49:Character \|k cannot be printed\X +\U48. +\:\X183:Check flags of unavailable nodes\X +\U180. +\:\X756:Check for the presence of a colon\X +\U755. +\:\X938:Check if unknowns have been equated\X +\U936. +\:\X181:Check single-word \\{avail} list\X +\U180. +\:\X727:Check that the proper right delimiter was present\X +\U726. +\:\X14, 154, 204, 214, 310, 553, 777:Check the ``constant'' values for +consistency\X +\U1204. +\:\X617:Check the list of linear dependencies\X +\U180. +\:\X547:Check the places where $B(y_1,y_2,y_3;t)=0$ to see if $B(x_1,x_2,x_3;t)% +\ge0$\X +\U546. +\:\X53:Check the pool check sum\X +\U52. +\:\X1056:Check the tentative weight\X +\U1054. +\:\X1068:Check the turning number\X +\U1064. +\:\X182:Check variable-size \\{avail} list\X +\U180. +\:\X815:Choose a dependent variable to take the place of the disappearing +independent variable, and change all remaining dependencies accordingly\X +\U812. +\:\X891:Choose control points for the path and put the result into \\{cur\_exp}% +\X +\U869. +\:\X1201:Close the base file\X +\U1186. +\:\X937:Compare the current expression with zero\X +\U936. +\:\X1112:Compile a ligature/kern command\X +\U1107. +\:\X9:Compiler directives\X +\U4. +\:\X478:Complain about a bad pen path\X +\U477. +\:\X1105:Complain about a character tag conflict\X +\U1104. +\:\X1178:Complain about improper special operation\X +\U1177. +\:\X1055:Complain about improper type\X +\U1054. +\:\X1067:Complain about non-cycle and \&{goto} \\{not\_found}\X +\U1064. +\:\X409:Complement the \|x coordinates of the cubic between \|p and~\|q\X +\U407. +\:\X414:Complement the \|y coordinates of the cubic between \\{pp} and~\\{qq}\X +\Us413\ET417. +\:\X1064:Complete the contour filling operation\X +\U1062. +\:\X537:Complete the ellipse by copying the negative of the half already +computed\X +\U527. +\:\X664:Complete the error message, and set \\{cur\_sym} to a token that might +help recover from the error\X +\U663. +\:\X536:Complete the half ellipse by reflecting the quarter already computed\X +\U527. +\:\X503:Complete the offset splitting process\X +\U494. +\:\X115:Compute $f=\lfloor 2^{16}(1+p/q)+{1\over2}\rfloor$\X +\U114. +\:\X108:Compute $f=\lfloor 2^{28}(1+p/q)+{1\over2}\rfloor$\X +\U107. +\:\X113:Compute $p=\lfloor qf/2^{16}+{1\over2}\rfloor-q$\X +\U112. +\:\X111:Compute $p=\lfloor qf/2^{28}+{1\over2}\rfloor-q$\X +\U109. +\:\X1132:Compute a check sum in $(\\{b1},\\{b2},\\{b3},\\{b4})$\X +\U1131. +\:\X443:Compute a compromise \\{pen\_edge}\X +\U442. +\:\X442:Compute a good coordinate at a diagonal transition\X +\U441. +\:\X435:Compute before-and-after \|x values based on the current pen\X +\U434. +\:\X438:Compute before-and-after \|y values based on the current pen\X +\U437. +\:\X498:Compute test coefficients $(\\{t0},\\{t1},\\{t2})$ for $s(t)$ versus +$s_k$ or $s_{k-1}$\X +\Us497\ET503. +\:\X533:Compute the distance \|d from class~0 to the edge of the ellipse in +direction $(\|u,\|v)$, times $\psqrt{u^2+v^2}$, rounded to the nearest integer\X +\U531. +\:\X208:Compute the hash code \|h\X +\U205. +\:\X457:Compute the incoming and outgoing directions\X +\U454. +\:\X1137:Compute the ligature/kern program offset and implant the left boundary +label\X +\U1135. +\:\X365:Compute the magic offset values\X +\U354. +\:\X489:Compute the octant code; skew and rotate the coordinates $(\|x,\|y)$\X +\U488. +\:\X576:Compute the offsets between screen coordinates and actual coordinates\X +\U574. +\:\X11:Constants in the outer block\X +\U4. +\:\X980:Construct a path from \\{pp} to \\{qq} of length $\lceil b\rceil$\X +\U978. +\:\X981:Construct a path from \\{pp} to \\{qq} of length zero\X +\U978. +\:\X481:Construct the offset list for the \|kth octant\X +\U477. +\:\X598:Contribute a term from \|p, plus the corresponding term from \|q\X +\U597. +\:\X595:Contribute a term from \|p, plus \|f times the corresponding term from % +\|q\X +\U594. +\:\X596:Contribute a term from \|q, multiplied by~\|f\X +\U594. +\:\X840:Convert a suffix to a string\X +\U823. +\:\X870:Convert the left operand, \|p, into a partial path ending at~\|q; but % +\&{return} if \|p doesn't have a suitable type\X +\U869. +\:\X885:Convert the right operand, \\{cur\_exp}, into a partial path from % +\\{pp} to~\\{qq}\X +\U869. +\:\X146:Convert $(\|x,\|y)$ to the octant determined by~\|q\X +\U145. +\:\X335:Copy both \\{sorted} and \\{unsorted} lists of \|p to \\{pp}\X +\Us334\ET341. +\:\X857:Copy the big node \|p\X +\U855. +\:\X485:Copy the unskewed and unrotated coordinates of node \\{ww}\X +\U484. +\:\X418:Correct the octant code in segments with decreasing \|y\X +\U413. +\:\X1200:Create the \\{base\_ident}, open the base file, and inform the user +that dumping has begun\X +\U1186. +\:\X349:Cull superfluous edge-weight entries from $\\{sorted}(\|p)$\X +\U348. +\:\X1008:Deal with redundant or inconsistent equation\X +\U1006. +\:\X454:Decide whether or not to go clockwise\X +\U452. +\:\X995, 996, 1015, 1021, 1029, 1031, 1034, 1035, 1036, 1040, 1041, 1044, 1045, +1046, 1049, 1050, 1051, 1054, 1057, 1059, 1070, 1071, 1072, 1073, 1074, 1082, +1103, 1104, 1106, 1177, 1186:Declare action procedures for use by \\{do% +\_statement}\X +\U989. +\:\X594, 600, 602, 603, 604:Declare basic dependency-list subroutines\X +\U246. +\:\X923, 928, 930, 943, 946, 949, 953, 960, 961, 962, 963, 966, 976, 977, 978, +982, 984, 985:Declare binary action procedures\X +\U922. +\:\X1154, 1155, 1157, 1158, 1159, 1160, 1161, 1163, 1165:Declare generic font +output procedures\X +\U989. +\:\X224:Declare miscellaneous procedures that were declared \\{forward}\X +\U1202. +\:\X257, 332, 388, 473, 589, 801, 807:Declare subroutines for printing +expressions\X +\U246. +\:\X968, 971, 972, 974:Declare subroutines needed by \\{big\_trans}\X +\U966. +\:\X856, 858:Declare subroutines needed by \\{make\_exp\_copy}\X +\U855. +\:\X405, 406, 419, 426, 429, 431, 432, 433, 440, 451:Declare subroutines needed +by \\{make\_spec}\X +\U402. +\:\X493, 497:Declare subroutines needed by \\{offset\_prep}\X +\U491. +\:\X296, 299:Declare subroutines needed by \\{solve\_choices}\X +\U284. +\:\X823, 860, 862, 864, 868, 892:Declare the basic parsing subroutines\X +\U1202. +\:\X779:Declare the function called \\{open\_base\_file}\X +\U1187. +\:\X1011:Declare the function called \\{scan\_declared\_variable}\X +\U697. +\:\X1098:Declare the function called \\{tfm\_check}\X +\U1070. +\:\X486:Declare the function called \\{trivial\_knot}\X +\U484. +\:\X1032:Declare the procedure called \\{check\_delimiter}\X +\U697. +\:\X935:Declare the procedure called \\{dep\_finish}\X +\U930. +\:\X518:Declare the procedure called \\{dual\_moves}\X +\U506. +\:\X247:Declare the procedure called \\{flush\_below\_variable}\X +\U246. +\:\X808, 820:Declare the procedure called \\{flush\_cur\_exp}\X +\U246. +\:\X43:Declare the procedure called \\{flush\_string}\X +\U73. +\:\X872:Declare the procedure called \\{known\_pair}\X +\U871. +\:\X720:Declare the procedure called \\{macro\_call}\X +\U706. +\:\X1001:Declare the procedure called \\{make\_eq}\X +\U995. +\:\X855:Declare the procedure called \\{make\_exp\_copy}\X +\U651. +\:\X723:Declare the procedure called \\{print\_arg}\X +\U720. +\:\X625:Declare the procedure called \\{print\_cmd\_mod}\X +\U227. +\:\X805:Declare the procedure called \\{print\_dp}\X +\U801. +\:\X722:Declare the procedure called \\{print\_macro\_name}\X +\U720. +\:\X333:Declare the procedure called \\{print\_weight}\X +\U332. +\:\X665:Declare the procedure called \\{runaway}\X +\U162. +\:\X730:Declare the procedure called \\{scan\_text\_arg}\X +\U720. +\:\X217:Declare the procedure called \\{show\_token\_list}\X +\U162. +\:\X510:Declare the procedure called \\{skew\_line\_edges}\X +\U506. +\:\X284:Declare the procedure called \\{solve\_choices}\X +\U269. +\:\X410:Declare the procedure called \\{split\_cubic}\X +\U406. +\:\X1006:Declare the procedure called \\{try\_eq}\X +\U995. +\:\X268, 385, 487, 620, 809:Declare the recycling subroutines\X +\U246. +\:\X799, 800:Declare the stashing/unstashing routines\X +\U801. +\:\X899, 900, 901, 904, 908, 910, 913, 916, 919:Declare unary action procedures% +\X +\U898. +\:\X743:Decrease the string reference count, if the current token is a string\X +\Us83, 742, 991\ETs1016. +\:\X300:Decrease the velocities, if necessary, to stay inside the bounding +triangle\X +\U299. +\:\X123:Decrease \|k by 1, maintaining the invariant relations between \|x, % +\|y, and~\|q\X +\U121. +\:\X670:Decry the invalid character and \&{goto} \\{restart}\X +\U669. +\:\X672:Decry the missing string delimiter and \&{goto} \\{restart}\X +\U671. +\:\X1113:Define an extensible recipe\X +\U1106. +\:\X353:Delete all the row headers\X +\U352. +\:\X352:Delete empty rows at the top and/or bottom; update the boundary values +in the header\X +\U348. +\:\X83:Delete $\|c-\.{"0"}$ tokens and \&{goto} \\{continue}\X +\U79. +\:\X245:Descend one level for the attribute $\\{info}(\|t)$\X +\U242. +\:\X244:Descend one level for the subscript $\\{value}(\|t)$\X +\U242. +\:\X1012:Descend past a collective subscript\X +\U1011. +\:\X1047:Descend the structure\X +\U1046. +\:\X561:Descend to the previous level and \&{goto} \\{not\_found}\X +\U560. +\:\X1181:Determine if a character has been shipped out\X +\U906. +\:\X445:Determine the before-and-after values of both coordinates\X +\Us444\ET446. +\:\X816:Determine the dependency list \|s to substitute for the independent +variable~\|p\X +\U815. +\:\X508:Determine the envelope's starting and ending lattice points $(\\{m0},% +\\{n0})$ and $(\\{m1},\\{n1})$\X +\U506. +\:\X1164:Determine the file extension, \\{gf\_ext}\X +\U1163. +\:\X724:Determine the number \|n of arguments already supplied, and set % +\\{tail} to the tail of \\{arg\_list}\X +\U720. +\:\X400:Determine the octant boundary \|q that precedes \|f\X +\U398. +\:\X480:Determine the octant code for direction $(\\{dx},\\{dy})$\X +\U479. +\:\X874:Determine the path join parameters; but \&{goto} \\{finish\_path} if +there's only a direction specifier\X +\U869. +\:\X467:Determine the starting and ending lattice points $(\\{m0},\\{n0})$ and +$(\\{m1},\\{n1})$\X +\U465. +\:\X881:Determine the tension and/or control points\X +\U874. +\:\X979:Dispense with the cases $\|a<0$ and/or $\|b>\|l$\X +\U978. +\:\X803:Display a big node\X +\U802. +\:\X221:Display a collective subscript\X +\U218. +\:\X804:Display a complex type\X +\U802. +\:\X220:Display a numeric token\X +\U219. +\:\X222:Display a parameter token\X +\U218. +\:\X1048:Display a variable macro\X +\U1046. +\:\X806:Display a variable that's been declared but not defined\X +\U802. +\:\X750:Display the boolean value of \\{cur\_exp}\X +\U748. +\:\X636:Display the current context\X +\U635. +\:\X613:Display the new dependency\X +\U610. +\:\X578:Display the pixels of edge row \|p in screen row \|r\X +\U577. +\:\X218:Display token \|p and set \|c to its class; but \&{return} if there are +problems\X +\U217. +\:\X219:Display two-word token\X +\U218. +\:\X616:Divide list \|p by $2^n$\X +\U615. +\:\X612:Divide list \|p by $-\|v$, removing node \|q\X +\U610. +\:\X313:Divide the variables by two, to avoid overflow problems\X +\U311. +\:\X992:Do a statement that doesn't begin with an expression\X +\U989. +\:\X994:Do a title\X +\U993. +\:\X993:Do an equation, assignment, title, or `$\langle\,$expression$\,\rangle% +\,$\&{endgroup}'\X +\U989. +\:\X417:Do any special actions needed when \|y is constant; \&{return} or % +\&{goto} \\{continue} if a dead cubic from \|p to \|q is removed\X +\U413. +\:\X646:Do magic computation\X +\U217. +\:\X1005:Do multiple equations and \&{goto} \\{done}\X +\U1003. +\:\X1065:Double the path\X +\U1064. +\:\X1198:Dump a few more things and the closing check word\X +\U1186. +\:\X1190:Dump constants for consistency check\X +\U1186. +\:\X1194:Dump the dynamic memory\X +\U1186. +\:\X1192:Dump the string pool\X +\U1186. +\:\X1196:Dump the table of equivalents and the hash table\X +\U1186. +\:\X845:Either begin an unsuffixed macro call or prepare for a suffixed one\X +\U844. +\:\X1156:Empty the last bytes out of \\{gf\_buf}\X +\U1182. +\:\X969:Ensure that $\\{type}(\|p)=\\{proto\_dependent}$\X +\U968. +\:\X73, 76, 77, 88, 89, 90:Error handling procedures\X +\U4. +\:\X623:Exclaim about a redundant equation\X +\Us622, 1004\ETs1008. +\:\X713:Exit a loop if the proper time has come\X +\U707. +\:\X714:Exit prematurely from an iteration\X +\U713. +\:\X544:Exit to \\{found} if an eastward direction occurs at knot \|p\X +\U541. +\:\X546:Exit to \\{found} if the curve whose derivatives are specified by $% +\\{x1},\\{x2},\\{x3},\\{y1},\\{y2},\\{y3}$ travels eastward at some time~\\{tt}% +\X +\U541. +\:\X549:Exit to \\{found} if the derivative $B(x_1,x_2,x_3;t)$ becomes $\G0$\X +\U548. +\:\X715:Expand the token after the next token\X +\U707. +\:\X736:Feed the arguments and replacement text to the scanner\X +\U720. +\:\X278:Fill in the control information between consecutive breakpoints \|p and +\|q\X +\U273. +\:\X273:Fill in the control points between \|p and the next breakpoint, then +advance \|p to that breakpoint\X +\U269. +\:\X611:Find a node \|q in list \|p whose coefficient \|v is largest\X +\U610. +\:\X850:Find the approximate type \\{tt} and corresponding~\|q\X +\U844. +\:\X272:Find the first breakpoint, \|h, on the path; insert an artificial +breakpoint if the path is an unbroken cycle\X +\U269. +\:\X502:Find the index \|k such that $s_{k-1}\L\\{dy}/\\{dx}<s_k$\X +\U494. +\:\X501:Find the initial slope, $\\{dy}/\\{dx}$\X +\U494. +\:\X1138:Find the minimum \\{lk\_offset} and adjust all remainders\X +\U1137. +\:\X399:Find the starting point, \|f\X +\U398. +\:\X297:Finish choosing angles and assigning control points\X +\U284. +\:\X668:Finish getting the symbolic token in \\{cur\_sym}; \&{goto} \\{restart} +if it is illegal\X +\U667. +\:\X483:Finish linking the offset nodes, and duplicate the borderline offset +nodes if necessary\X +\U481. +\:\X1168:Finish off an entirely blank character\X +\U1167. +\:\X1182:Finish the \.{GF} file\X +\U1206. +\:\X1206:Finish the \.{TFM} and \.{GF} files\X +\U1205. +\:\X1134:Finish the \.{TFM} file\X +\U1206. +\:\X459:Fix up the transition fields and adjust the turning number\X +\U452. +\:\X1016:Flush spurious symbols after the declared variable\X +\U1015. +\:\X991:Flush unparsable junk that was found after the statement\X +\U989. +\:\X957:For each of the eight cases, change the relevant fields of \\{cur\_exp} +and \&{goto} \\{done}; but do nothing if capsule \|p doesn't have the +appropriate type\X +\U955. +\:\X1003:For each type \|t, make an equation and \&{goto} \\{done} unless % +\\{cur\_type} is incompatible with~\|t\X +\U1001. +\:\X678:Get a stored numeric or string or capsule token and \&{return}\X +\U676. +\:\X671:Get a string token and \&{return}\X +\U669. +\:\X878:Get given directions separated by commas\X +\U877. +\:\X886:Get ready to close a cycle\X +\U869. +\:\X1062:Get ready to fill a contour, and fill it\X +\U1059. +\:\X1211:Get the first line of input and prepare to start\X +\U1204. +\:\X674:Get the fraction part \|f of a numeric token\X +\U669. +\:\X673:Get the integer part \|n of a numeric token; set $\|f\K0$ and \&{goto} % +\\{fin\_numeric\_token} if there is no decimal point\X +\U669. +\:\X285:Get the linear equations started; or \&{return} with the control points +in place, if linear equations needn't be solved\X +\U284. +\:\X78:Get user's advice and \&{return}\X +\U77. +\:\X914:Give error messages if \\{bad\_char} or $\|n\G4096$\X +\U913. +\:\X13, 20, 25, 29, 31, 38, 42, 50, 54, 68, 71, 74, 91, 97, 129, 137, 144, 148, +159, 160, 161, 166, 178, 190, 196, 198, 200, 201, 225, 230, 250, 267, 279, 283, +298, 308, 309, 327, 371, 379, 389, 395, 403, 427, 430, 448, 455, 461, 464, 507, +552, 555, 557, 566, 569, 572, 579, 585, 592, 624, 628, 631, 633, 634, 659, 680, +699, 738, 752, 767, 768, 775, 782, 785, 791, 796, 813, 821, 954, 1077, 1084, +1087, 1096, 1119, 1125, 1130, 1149, 1152, 1162, 1183, 1188, 1203:Global +variables\X +\U4. +\:\X168:Grow more variable-size memory and \&{goto} \\{restart}\X +\U167. +\:\X128:Handle erroneous \\{pyth\_sub} and set $\|a\K0$\X +\U126. +\:\X134:Handle non-positive logarithm\X +\U132. +\:\X690:Handle quoted symbols, \.{\#\AT!}, \.{\AT!}, or \.{\AT!\#}\X +\U685. +\:\X122:Handle square root of zero or negative argument\X +\U121. +\:\X505:Handle the special case of infinite slope\X +\U494. +\:\X548:Handle the test for eastward directions when $y_1y_3=y_2^2$; either % +\&{goto} \\{found} or \&{goto} \\{done}\X +\U546. +\:\X140:Handle undefined arg\X +\U139. +\:\X852:Handle unusual cases that masquerade as variables, and \&{goto} % +\\{restart} or \&{goto} \\{done} if appropriate; otherwise make a copy of the +variable and \&{goto} \\{done}\X +\U844. +\:\X271:If consecutive knots are equal, join them explicitly\X +\U269. +\:\X441:If node \|q is a transition point between octants, compute and save its +before-and-after coordinates\X +\U440. +\:\X434:If node \|q is a transition point for \|x coordinates, compute and save +its before-and-after coordinates\X +\U433. +\:\X437:If node \|q is a transition point for \|y coordinates, compute and save +its before-and-after coordinates\X +\U433. +\:\X956:If the current transform is entirely known, stash it in global +variables; otherwise \&{return}\X +\U953. +\:\X322:Increase and decrease $\\{move}[\|k-1]$ and $\\{move}[\|k]$ by $% +\delta_k$\X +\U321. +\:\X133:Increase \|k until \|x can be multiplied by a factor of $2^{-k}$, and +adjust $y$ accordingly\X +\U132. +\:\X143:Increase \|z to the arg of $(x,y)$\X +\U142. +\:\X519:Initialize for dual envelope moves\X +\U518. +\:\X558:Initialize for intersections at level zero\X +\U556. +\:\X513:Initialize for ordinary envelope moves\X +\U512. +\:\X581:Initialize for the display computations\X +\U577. +\:\X176, 193, 203, 229, 324, 475, 587, 702, 759, 911, 1116, 1127, +1185:Initialize table entries (done by \.{INIMF} only)\X +\U1210. +\:\X356:Initialize the array of new edge list heads\X +\U354. +\:\X528:Initialize the ellipse data structure by beginning with directions +$(0,-1)$, $(1,0)$, $(0,1)$\X +\U527. +\:\X657, 660:Initialize the input routines\X +\U1211. +\:\X55, 61, 783, 792:Initialize the output routines\X +\U1204. +\:\X70:Initialize the print \\{selector} based on \\{interaction}\X +\Us1023\ET1211. +\:\X1022:Initialize the random seed to \\{cur\_exp}\X +\U1021. +\:\X711:Initiate or terminate input from a file\X +\U707. +\:\X669:Input from external file; \&{goto} \\{restart} if no input found, or % +\&{return} if a non-symbolic token is found\X +\U667. +\:\X676:Input from token list; \&{goto} \\{restart} if end of list or if a +parameter needs to be expanded, or \&{return} if a non-symbolic token is found\X +\U667. +\:\X986:Insert a fractional node by splitting the cubic\X +\U985. +\:\X521:Insert a line segment dually to approach the correct offset\X +\U518. +\:\X515:Insert a line segment to approach the correct offset\X +\U512. +\:\X535:Insert a new line for direction $(\|u,\|v)$ between \|p and~\|q\X +\U531. +\:\X207:Insert a new symbolic token after \|p, then make \|p point to it and % +\&{goto} \\{found}\X +\U205. +\:\X677:Insert a suffix or text parameter and \&{goto} \\{restart}\X +\U676. +\:\X458:Insert additional boundary nodes, then \&{goto} \\{done}\X +\U452. +\:\X350:Insert an edge-weight for edge \|m, if the new pixel weight has changed% +\X +\U349. +\:\X355:Insert blank rows at the top and bottom, and set \|p to the new top row% +\X +\U354. +\:\X376:Insert downward edges for a line\X +\U374. +\:\X330:Insert exactly $\\{n\_min}(\\{cur\_edges})-\\{nl}$ empty rows at the +bottom\X +\U329. +\:\X331:Insert exactly $\\{nr}-\\{n\_max}(\\{cur\_edges})$ empty rows at the +top\X +\U329. +\:\X362:Insert horizontal edges of weight \|w between \|m and~\\{mm}\X +\U358. +\:\X450:Insert octant boundaries and compute the turning number\X +\U402. +\:\X452:Insert one or more octant boundary nodes just before~\|q\X +\U450. +\:\X358:Insert the horizontal edges defined by adjacent rows $\|p,\|q$, and +destroy row~\|p\X +\U354. +\:\X523:Insert the new envelope moves dually in the pixel data\X +\U518. +\:\X517:Insert the new envelope moves in the pixel data\X +\U512. +\:\X375:Insert upward edges for a line\X +\U374. +\:\X959:Install a complex multiplier, then \&{goto} \\{done}\X +\U957. +\:\X958:Install sines and cosines, then \&{goto} \\{done}\X +\U957. +\:\X531:Interpolate new vertices in the ellipse data structure until +improvement is impossible\X +\U527. +\:\X79:Interpret code \|c and \&{return} if done\X +\U78. +\:\X82:Introduce new material from the terminal and \&{return}\X +\U79. +\:\X887:Join the partial paths and reset \|p and \|q to the head and tail of +the result\X +\U869. +\:\X6:Labels in the outer block\X +\U4. +\:\X1205, 1209, 1210, 1212:Last-minute procedures\X +\U1202. +\:\X241:Link a new attribute node \|r in place of node \|p\X +\U239. +\:\X240:Link a new subscript node \|r in place of node \|p\X +\U239. +\:\X482:Link node \|r to the previous node\X +\U481. +\:\X641:Local variables for formatting calculations\X +\U635. +\:\X19, 130:Local variables for initialization\X +\U4. +\:\X1141:Log the subfile sizes of the \.{TFM} file\X +\U1134. +\:\X896:Make a special knot node for \&{pencircle}\X +\U895. +\:\X1066:Make a trivial one-point path cycle\X +\U1065. +\:\X314:Make moves for current subinterval; if bisection is necessary, push the +second subinterval onto the stack, and \&{goto} \\{continue} in order to handle +the first subinterval\X +\U311. +\:\X317:Make one move of each kind\X +\U314. +\:\X446:Make sure that all the diagonal roundings are safe\X +\U444. +\:\X243:Make sure that both nodes \|p and \\{pp} are of \\{structured} type\X +\U242. +\:\X873:Make sure that both \|x and \|y parts of \|p are known; copy them into % +\\{cur\_x} and \\{cur\_y}\X +\U872. +\:\X883:Make sure that the current expression is a valid tension setting\X +\Us882\ET882. +\:\X1207:Make the dynamic memory into one big available node\X +\U1206. +\:\X512:Make the envelope moves for the current octant and insert them in the +pixel data\X +\U506. +\:\X48:Make the first 256 strings\X +\U47. +\:\X468:Make the moves for the current octant\X +\U465. +\:\X586:Make variable $\|q+\|s$ newly independent\X +\U232. +\:\X1126:Massage the \.{TFM} heights, depths, and italic corrections\X +\U1206. +\:\X1124:Massage the \.{TFM} widths\X +\U1206. +\:\X368:Merge row \\{pp} into row \|p\X +\U366. +\:\X347:Merge the \\{temp\_head} list into $\\{sorted}(\|h)$\X +\U346. +\:\X319:Move right then up\X +\Us317\ET317. +\:\X947:Move the dependent variable \|p into both parts of the pair node \|r\X +\U946. +\:\X679:Move to next line of file, or \&{goto} \\{restart} if there is no next +line\X +\U669. +\:\X377:Move to row \\{n0}, pointed to by \|p\X +\Us375, 376, 381, 382, 383\ETs384. +\:\X532:Move to the next remaining triple $(\|p,\|q,\|r)$, removing and +skipping past zero-length lines that might be present; \&{goto} \\{done} if all +triples have been processed\X +\U531. +\:\X316:Move to the right \|m steps\X +\U314. +\:\X320:Move up then right\X +\Us317\ET317. +\:\X315:Move upward \|n steps\X +\U314. +\:\X942:Multiply when at least one operand is known\X +\U941. +\:\X136:Multiply \|y by $\exp(-z/2^{27})$\X +\U135. +\:\X903:Negate the current expression\X +\U898. +\:\X540:Normalize the given direction for better accuracy; but \&{return} with +zero result if it's zero\X +\U539. +\:\X1213:Numbered cases for \\{debug\_help}\X +\U1212. +\:\X580:Other local variables for \\{disp\_edges}\X +\U577. +\:\X511:Other local variables for \\{fill\_envelope}\X +\Us506\ET518. +\:\X542:Other local variables for \\{find\_direction\_time}\X +\U539. +\:\X280:Other local variables for \\{make\_choices}\X +\U269. +\:\X453:Other local variables for \\{make\_spec}\X +\U402. +\:\X495:Other local variables for \\{offset\_prep}\X +\U491. +\:\X831, 836, 843:Other local variables for \\{scan\_primary}\X +\U823. +\:\X286:Other local variables for \\{solve\_choices}\X +\U284. +\:\X357, 363:Other local variables for \\{xy\_swap\_edges}\X +\U354. +\:\X1208:Output statistics about this job\X +\U1205. +\:\X934:Output the answer, \|v (which might have become \\{known})\X +\U932. +\:\X1136:Output the character information bytes, then output the dimensions +themselves\X +\U1134. +\:\X1167:Output the character represented in \\{cur\_edges}\X +\U1165. +\:\X1140:Output the extensible character recipes and the font metric parameters% +\X +\U1134. +\:\X1139:Output the ligature/kern program\X +\U1134. +\:\X1169:Output the pixels of edge row \|p to font row \|n\X +\U1167. +\:\X1135:Output the subfile sizes and header bytes\X +\U1134. +\:\X675:Pack the numeric and fraction parts of a numeric token and \&{return}\X +\U669. +\:\X889:Plug an opening in $\\{right\_type}(\\{pp})$, if possible\X +\U887. +\:\X888:Plug an opening in $\\{right\_type}(\|q)$, if possible\X +\U887. +\:\X745:Pop the condition stack\X +\Us748, 749\ETs751. +\:\X237:Preface the output with a part specifier; \&{return} in the case of a +capsule\X +\U235. +\:\X380:Prepare for and switch to the appropriate case, based on \\{octant}\X +\U378. +\:\X496:Prepare for derivative computations; \&{goto} \\{not\_found} if the +current cubic is dead\X +\U494. +\:\X765:Prepare for step-until construction and \&{goto} \\{done}\X +\U764. +\:\X717:Pretend we're reading a new one-line file\X +\U716. +\:\X509:Print a line of diagnostic info to introduce this octant\X +\U508. +\:\X802:Print an abbreviated value of \|v with format depending on \|t\X +\U801. +\:\X261:Print control points between \|p and \|q, then \&{goto} \\{done1}\X +\U258. +\:\X263:Print information for a curve that begins \\{curl} or \\{given}\X +\U258. +\:\X262:Print information for a curve that begins \\{open}\X +\U258. +\:\X258:Print information for adjacent knots \|p and \|q\X +\U257. +\:\X637:Print location of current line\X +\U636. +\:\X184:Print newly busy locations\X +\U180. +\:\X1086:Print string \\{cur\_exp} as an error message\X +\U1082. +\:\X223:Print string \|r as a symbolic token and set \|c to its class\X +\U218. +\:\X260:Print tension between \|p and \|q\X +\U258. +\:\X790:Print the banner line, including the date and time\X +\U788. +\:\X590:Print the coefficient, unless it's $\pm1.0$\X +\U589. +\:\X397:Print the cubic between \|p and \|q\X +\U394. +\:\X639:Print the current loop value\X +\U638. +\:\X84:Print the help information and \&{goto} \\{continue}\X +\U79. +\:\X80:Print the menu of available options\X +\U79. +\:\X640:Print the name of a \&{vardef}'d macro\X +\U638. +\:\X85:Print the string \\{err\_help}, possibly on several lines\X +\Us84\ET86. +\:\X401:Print the turns, if any, that start at \|q, and advance \|q\X +\Us398\ET398. +\:\X474:Print the unskewed and unrotated coordinates of node \\{ww}\X +\U473. +\:\X259:Print two dots, followed by \\{given} or \\{curl} if present\X +\U257. +\:\X643:Print two lines using the tricky pseudoprinted information\X +\U636. +\:\X638:Print type of token list\X +\U636. +\:\X1110:Process a \\{skip\_to} command and \&{goto} \\{done}\X +\U1107. +\:\X838:Protest division by zero\X +\U837. +\:\X644:Pseudoprint the line\X +\U636. +\:\X645:Pseudoprint the token list\X +\U636. +\:\X744:Push the condition stack\X +\U748. +\:\X716:Put a string into the input buffer\X +\U707. +\:\X192, 211, 683, 688, 695, 709, 740, 893, 1013, 1018, 1024, 1027, 1037, 1052, +1079, 1101, 1108, 1176:Put each of \MF's primitives into the hash table\X +\U1210. +\:\X86:Put help message on the transcript file\X +\U77. +\:\X955:Put the current transform into \\{cur\_exp}\X +\U953. +\:\X795:Put the desired file name in $(\\{cur\_name},\\{cur\_ext},\\{cur% +\_area})$\X +\U793. +\:\X847:Put the left bracket and the expression back to be rescanned\X +\Us846\ET859. +\:\X345:Put the list $\\{sorted}(\|p)$ back into sort\X +\U344. +\:\X880:Put the post-join direction information into \|x and \|t\X +\U874. +\:\X879:Put the pre-join direction information into node \|q\X +\U874. +\:\X897:Read a string from the terminal\X +\U895. +\:\X681:Read next line of file into \\{buffer}, or \&{goto} \\{restart} if the +file has ended\X +\U679. +\:\X52:Read one string, but return \\{false} if the string memory space is +getting too tight for comfort\X +\U51. +\:\X794:Read the first line of the new file\X +\U793. +\:\X51:Read the other strings from the \.{MF.POOL} file and return \\{true}, or +give an error message and return \\{false}\X +\U47. +\:\X1111:Record a label in a lig/kern subprogram and \&{goto} \\{continue}\X +\U1107. +\:\X522:Record a line segment from $(\\{xx},\\{yy})$ to $(\\{xp},\\{yp})$ +dually in \\{env\_move}\X +\U521. +\:\X516:Record a line segment from $(\\{xx},\\{yy})$ to $(\\{xp},\\{yp})$ in % +\\{env\_move}\X +\U515. +\:\X814:Record a new maximum coefficient of type \|t\X +\U812. +\:\X583:Record a possible transition in column \|m\X +\U582. +\:\X810:Recycle a big node\X +\U809. +\:\X811:Recycle a dependency list\X +\U809. +\:\X812:Recycle an independent variable\X +\U809. +\:\X925:Recycle any sidestepped \\{independent} capsules\X +\U922. +\:\X939:Reduce comparison of big nodes to comparison of scalars\X +\U936. +\:\X302:Reduce to simple case of straight line and \&{return}\X +\U285. +\:\X301:Reduce to simple case of two givens and \&{return}\X +\U285. +\:\X118:Reduce to the case that $\|a,\|c\G0$, $\|b,\|d>0$\X +\U117. +\:\X110:Reduce to the case that $\|f\G0$ and $\|q>0$\X +\Us109\ET112. +\:\X339:Reflect the edge-and-weight data in $\\{sorted}(\|p)$\X +\U337. +\:\X338:Reflect the edge-and-weight data in $\\{unsorted}(\|p)$\X +\U337. +\:\X312:Remove a subproblem for \\{make\_moves} from the stack\X +\U311. +\:\X447:Remove dead cubics\X +\U402. +\:\X1007:Remove the left operand from its container, negate it, and put it into +dependency list~\|p with constant term~\|q\X +\U1006. +\:\X534:Remove the line from \|p to \|q, and adjust vertex~\|q to introduce a +new line\X +\U531. +\:\X282:Remove \\{open} types at the breakpoints\X +\U278. +\:\X712:Repeat a loop\X +\U707. +\:\X1122:Replace an interval of values by its midpoint\X +\U1121. +\:\X125:Replace \|a by an approximation to $\psqrt{a^2+b^2}$\X +\U124. +\:\X127:Replace \|a by an approximation to $\psqrt{a^2-b^2}$\X +\U126. +\:\X341:Replicate every row exactly $s$ times\X +\U340. +\:\X270:Report an unexpected problem during the choice-making\X +\U269. +\:\X34:Report overflow of the input buffer, and abort\X +\U30. +\:\X1004:Report redundant or inconsistent equation and \&{goto} \\{done}\X +\U1003. +\:\X141:Return an appropriate answer based on \|z and \\{octant}\X +\U139. +\:\X529:Revise the values of $\alpha$, $\beta$, $\gamma$, if necessary, so that +degenerate lines of length zero will not be obtained\X +\U528. +\:\X541:Rotate the cubic between \|p and \|q; then \&{goto} \\{found} if the +rotated cubic travels due east at some time \\{tt}; but \&{goto} \\{not\_found} +if an entire cyclic path has been traversed\X +\U539. +\:\X605:Run through the dependency list for variable \|t, fixing all nodes, and +ending with final link~\|q\X +\U604. +\:\X1083:Save string \\{cur\_exp} as the \\{err\_help}\X +\U1082. +\:\X343:Scale the $x$~coordinates of each row by $s$\X +\U342. +\:\X964:Scale the edges, shift them, and \&{return}\X +\U963. +\:\X408:Scale up \\{del1}, \\{del2}, and \\{del3} for greater accuracy; also +set \\{del} to the first nonzero element of $(\\{del1},\\{del2},\\{del3})$\X +\Us407, 413\ETs420. +\:\X839:Scan a binary operation with `\&{of}' between its operands\X +\U823. +\:\X861:Scan a bracketed subscript and set $\\{cur\_cmd}\K\\{numeric\_token}$\X +\U860. +\:\X876:Scan a curl specification\X +\U875. +\:\X826:Scan a delimited primary\X +\U823. +\:\X877:Scan a given direction\X +\U875. +\:\X832:Scan a grouped primary\X +\U823. +\:\X859:Scan a mediation construction\X +\U823. +\:\X834:Scan a nullary operation\X +\U823. +\:\X869:Scan a path construction operation; but \&{return} if \|p has the wrong +type\X +\U868. +\:\X837:Scan a primary that starts with a numeric token\X +\U823. +\:\X833:Scan a string constant\X +\U823. +\:\X735:Scan a suffix with optional delimiters\X +\U733. +\:\X835:Scan a unary operation\X +\U823. +\:\X844:Scan a variable primary; \&{goto} \\{restart} if it turns out to be a +macro\X +\U823. +\:\X734:Scan an expression followed by `\&{of} $\langle$primary$\rangle$'\X +\U733. +\:\X841:Scan an internal numeric quantity\X +\U823. +\:\X787:Scan file name in the buffer\X +\U786. +\:\X846:Scan for a subscript; replace \\{cur\_cmd} by \\{numeric\_token} if +found\X +\U844. +\:\X729:Scan the argument represented by $\\{info}(\|r)$\X +\U726. +\:\X726:Scan the delimited argument represented by $\\{info}(\|r)$\X +\U725. +\:\X758:Scan the loop text and put it on the loop control stack\X +\U755. +\:\X725:Scan the remaining arguments, if any; set \|r to the first token of the +replacement text\X +\U720. +\:\X830:Scan the second of a pair of numerics\X +\U826. +\:\X700:Scan the token or variable to be defined; set \|n, \\{scanner\_status}, +and \\{warning\_info}\X +\U697. +\:\X764:Scan the values to be used in the loop\X +\U755. +\:\X733:Scan undelimited argument(s)\X +\U725. +\:\X708:Scold the user for having an extra \&{endfor}\X +\U707. +\:\X209:Search \\{eqtb} for equivalents equal to \|p\X +\U185. +\:\X1166:Send nonzero offsets to the output file\X +\U1165. +\:\X1179:Send the current expression as a title to the output file\X +\U994. +\:\X884:Set explicit control points\X +\U881. +\:\X882:Set explicit tensions\X +\U881. +\:\X21, 22, 23, 69, 72, 75, 92, 98, 131, 138, 179, 191, 199, 202, 231, 251, +396, 428, 449, 456, 462, 570, 573, 593, 739, 753, 776, 797, 822, 1078, 1085, +1097, 1150, 1153, 1184:Set initial values of key variables\X +\U4. +\:\X543:Set local variables $\\{x1},\\{x2},\\{x3}$ and $\\{y1},\\{y2},\\{y3}$ +to multiples of the control points of the rotated derivatives\X +\U541. +\:\X987:Set the current expression to the desired path coordinates\X +\U985. +\:\X295:Set up equation for a curl at $\theta_n$ and \&{goto} \\{found}\X +\U284. +\:\X287:Set up equation to match mock curvatures at $z_k$; then \&{goto} % +\\{found} with $\theta_n$ adjusted to equal $\theta_0$, if a cycle has ended\X +\U284. +\:\X854:Set up suffixed macro call and \&{goto} \\{restart}\X +\U852. +\:\X1075:Set up the culling weights, or \&{goto} \\{not\_found} if the +thresholds are bad\X +\U1074. +\:\X294:Set up the equation for a curl at $\theta_0$\X +\U285. +\:\X293:Set up the equation for a given value of $\theta_0$\X +\U285. +\:\X582:Set up the parameters needed for \\{paint\_row}; but \&{goto} \\{done} +if no painting is needed after all\X +\U578. +\:\X421:Set up the variables $(\\{del1},\\{del2},\\{del3})$ to represent +$x'-y'$\X +\U420. +\:\X853:Set up unsuffixed macro call and \&{goto} \\{restart}\X +\U845. +\:\X466:Set variable \|q to the node at the end of the current octant\X +\Us465, 506\ETs506. +\:\X142:Set variable \|z to the arg of $(x,y)$\X +\U139. +\:\X867:Shift the coordinates of path \|q\X +\U866. +\:\X965:Shift the edges by $(\\{tx},\\{ty})$, rounded\X +\U964. +\:\X1042:Show a numeric or string or capsule token\X +\U1041. +\:\X721:Show the text of the macro being expanded, and the existing arguments\X +\U720. +\:\X817:Show the transformed dependency\X +\U816. +\:\X926:Sidestep \\{independent} cases in capsule \|p\X +\U922. +\:\X927:Sidestep \\{independent} cases in the current expression\X +\U922. +\:\X614:Simplify all existing dependencies by substituting for \|x\X +\U610. +\:\X1174:Skip down $\\{prev\_n}-\|n$ rows\X +\U1172. +\:\X749:Skip to \&{elseif} or \&{else} or \&{fi}, then \&{goto} \\{done}\X +\U748. +\:\X1173:Skip to column $m$ in the next row and \&{goto} \\{done}, or skip zero +rows\X +\U1172. +\:\X174:Sort \|p into the list starting at \\{rover} and advance \|p to $% +\\{rlink}(\|p)$\X +\U173. +\:\X890:Splice independent paths together\X +\U887. +\:\X504:Split off another \\{rising} cubic for \\{fin\_offset\_prep}\X +\U503. +\:\X499:Split the cubic at $t$, and split off another cubic if the derivative +crosses back\X +\U497. +\:\X494:Split the cubic between \|p and \|q, if necessary, into cubics +associated with single offsets, after which \|q should point to the end of the +final such cubic\X +\U491. +\:\X950:Squeal about division by zero\X +\U948. +\:\X479:Stamp all nodes with an octant code, compute the maximum offset, and +set \\{hh} to the node that begins the first octant; \&{goto} \\{not\_found} if +there's a problem\X +\U477. +\:\X1172:Start a new row at $(m,n)$\X +\U1170. +\:\X1170:Start black at $(m,n)$\X +\U1169. +\:\X829:Stash an independent \\{cur\_exp} into a big node\X +\U827. +\:\X1171:Stop black at $(m,n)$\X +\U1169. +\:\X1115:Store a list of font dimensions\X +\U1106. +\:\X1114:Store a list of header bytes\X +\U1106. +\:\X1107:Store a list of ligature/kern steps\X +\U1106. +\:\X1099:Store the width information for character code~\|c\X +\U1070. +\:\X413:Subdivide all cubics between \|p and \|q so that the results travel +toward the first quadrant; but \&{return} or \&{goto} \\{continue} if the cubic +from \|p to \|q was dead\X +\U406. +\:\X559:Subdivide for a new level of intersection\X +\U556. +\:\X412:Subdivide the cubic a second time with respect to $x'$\X +\U411. +\:\X425:Subdivide the cubic a second time with respect to $x'-y'$\X +\U424. +\:\X416:Subdivide the cubic a second time with respect to $y'$\X +\U415. +\:\X420:Subdivide the cubic between \|p and \|q so that the results travel +toward the first octant\X +\U419. +\:\X407:Subdivide the cubic between \|p and \|q so that the results travel +toward the right halfplane\X +\U406. +\:\X411:Subdivide the cubic with respect to $x'$, possibly twice\X +\U407. +\:\X424:Subdivide the cubic with respect to $x'-y'$, possibly twice\X +\U420. +\:\X415:Subdivide the cubic with respect to $y'$, possibly twice\X +\U413. +\:\X686:Substitute for \\{cur\_sym}, if it's on the \\{subst\_list}\X +\U685. +\:\X818:Substitute new dependencies in place of \|p\X +\U815. +\:\X819:Substitute new proto-dependencies in place of \|p\X +\U815. +\:\X147:Subtract angle \|z from $(\|x,\|y)$\X +\U145. +\:\X825:Supply diagnostic information, if requested\X +\U823. +\:\X423:Swap the \|x and \|y coordinates of the cubic between \|p and~\|q\X +\U420. +\:\X318:Switch to the right subinterval\X +\U317. +\:\X663:Tell the user what has run away and try to recover\X +\U661. +\:\X751:Terminate the current conditional and skip to \&{fi}\X +\U707. +\:\X761:The arithmetic progression has ended\X +\U760. +\:\X998:Trace the current assignment\X +\U996. +\:\X924:Trace the current binary operation\X +\U922. +\:\X997:Trace the current equation\X +\U995. +\:\X902:Trace the current unary operation\X +\U898. +\:\X945:Trace the fraction multiplication\X +\U944. +\:\X762:Trace the start of a loop\X +\U760. +\:\X520:Transfer moves dually from the \\{move} array to \\{env\_move}\X +\U518. +\:\X514:Transfer moves from the \\{move} array to \\{env\_move}\X +\U512. +\:\X970:Transform a known big node\X +\U966. +\:\X967:Transform an unknown big node and \&{return}\X +\U966. +\:\X973:Transform known by known\X +\U970. +\:\X444:Transform the skewed coordinates\X +\U440. +\:\X436:Transform the \|x coordinates\X +\U433. +\:\X439:Transform the \|y coordinates\X +\U433. +\:\X206:Treat special case of length 1 and \&{goto} \\{found}\X +\U205. +\:\X404:Truncate the values of all coordinates that exceed \\{max\_allowed}, +and stamp segment numbers in each \\{left\_type} field\X +\U402. +\:\X169:Try to allocate within node \|p and its physical successors, and % +\&{goto} \\{found} if allocation was possible\X +\U167. +\:\X789:Try to get a different log file name\X +\U788. +\:\X18, 24, 37, 101, 105, 106, 156, 186, 565, 571, 627, 1151:Types in the outer +block\X +\U4. +\:\X1199:Undump a few more things and the closing check word\X +\U1187. +\:\X1191:Undump constants for consistency check\X +\U1187. +\:\X1195:Undump the dynamic memory\X +\U1187. +\:\X1193:Undump the string pool\X +\U1187. +\:\X1197:Undump the table of equivalents and the hash table\X +\U1187. +\:\X351:Update the max/min amounts\X +\U349. +\:\X392:Use bisection to find the crossing point, if one exists\X +\U391. +\:\X584:Wind up the \\{paint\_row} parameter calculation by inserting the final +transition; \&{goto} \\{done} if no painting is needed\X +\U582. +\:\X990:Worry about bad statement\X +\U989. +\con |