Created
August 13, 2019 19:21
-
-
Save texdraft/c72fd78491439abd7d9d323fec3ec043 to your computer and use it in GitHub Desktop.
diff oldtex.web tex.web
This file has been truncated, but you can view the full file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2,4c2,3 | |
< \def\glob{13} % this should be the section number of "<Globals...>" | |
< \def\gglob{20, 26} % this should be the next two sections of "<Globals...>" | |
< This is \TeX, a document compiler intended to produce high-quality typesetting. | |
--- | |
> This is \TeX, a document compiler intended to produce typesetting of high | |
> quality. | |
9c8 | |
< will be obtainable on a great variety of different computers. | |
--- | |
> will be obtainable on a great variety of computers. | |
34c33 | |
< the \TeX\ user's manual. | |
--- | |
> {\sl The \TeX book}. | |
35a35 | |
> @:TeXbook}{\sl The \TeX book@> | |
38c38 | |
< of@@1977, when Michael@@F. Plass and Frank@@M. Liang designed and coded | |
--- | |
> of~1977, when Michael~F. Plass and Frank~M. Liang designed and coded | |
43c43 | |
< based on some specifications that the author had made in April of that year. | |
--- | |
> based on some specifications that the author had made in May of that year. | |
54c54,55 | |
< somewhat like the present ``web'' were developed by Luis Trabb@@Pardo and | |
--- | |
> somewhat like the present ``web'' were developed by Luis Trabb~Pardo and | |
> @^Trabb Pardo, Luis Isidoro@> | |
56c57 | |
< created by Ignacio@@A. Zabala in 1979 and 1980. The \TeX82 program, which | |
--- | |
> created by Ignacio~A. Zabala in 1979 and 1980. The \TeX82 program, which | |
67c68,76 | |
< has been substantially improved. | |
--- | |
> has been substantially improved. After the appearance of ``Version 0'' in | |
> September 1982, this program benefited greatly from the comments of | |
> many other people, notably David~R. Fuchs and Howard~W. Trickey. | |
> A final revision in September 1989 extended the input character set to | |
> eight-bit codes and introduced the ability to hyphenate words from | |
> different languages, based on some ideas of Michael~J. Ferguson. | |
> @^Fuchs, David Raymond@> | |
> @^Trickey, Howard Wellington@> | |
> @^Ferguson, Michael John@> | |
69c78 | |
< No doubt there still is plenty of room for enhancements, but the author | |
--- | |
> No doubt there still is plenty of room for improvement, but the author | |
71c80 | |
< and reliabil\-ity are to be its main virtues. | |
--- | |
> and reliability are to be its main virtues. | |
79a89 | |
> @^system dependencies@> | |
81c91,99 | |
< @d banner=='This is TeX, Version -0.25' {printed when \TeX\ starts} | |
--- | |
> If this program is changed, the resulting system should not be called | |
> `\TeX'; the official name `\TeX' by itself is reserved | |
> for software systems that are fully compatible with each other. | |
> A special test suite called the ``\.{TRIP} test'' is available for | |
> helping to determine whether a particular implementation deserves to be | |
> known as `\TeX' [cf.~Stanford Computer Science report CS1027, | |
> November 1984]. | |
> | |
> @d banner=='This is TeX, Version 3.14159265' {printed when \TeX\ starts} | |
84d101 | |
< \def\ph{{\mc PASCAL-H}} | |
87c104 | |
< available to the author in 1982. The methods used here to work with | |
--- | |
> available to the author in 1982. Constructions that apply to | |
89,90c106,107 | |
< reader to see how to make an appropriate interface for other systems | |
< if necessary. (\ph\ is Charles Hedrick's mod\-ifi\-ca\-tion of a compiler | |
--- | |
> reader see how to make an appropriate interface for other systems | |
> if necessary. (\ph\ is Charles Hedrick's modification of a compiler | |
98,99c115,120 | |
< \PASCAL\ itself, so that most of the code can be mechanically translated | |
< into other high-level languages.) | |
--- | |
> \PASCAL\ itself, so that most of the code can be translated mechanically | |
> into other high-level languages. For example, the `\&{with}' and `\\{new}' | |
> features are not used, nor are pointer types, set types, or enumerated | |
> scalar types; there are no `\&{var}' parameters, except in the case of files; | |
> there are no tag fields on variant records; there are no assignments | |
> |real:=integer|; no procedures are declared local to other procedures.) | |
110a132,136 | |
> Incidentally, \PASCAL's standard |round| function can be problematical, | |
> because it disagrees with the IEEE floating-point standard. | |
> Many implementors have | |
> therefore chosen to substitute their own home-grown rounding procedure. | |
> | |
114,115c140,141 | |
< For example, the portion of the program called `\X\glob:Globals in the outer | |
< block\X' here will be replaced by a sequence of variable declarations | |
--- | |
> For example, the portion of the program called `\X\glob:Global | |
> variables\X' below will be replaced by a sequence of variable declarations | |
120c146 | |
< sections \gglob, $\ldots$,'' also make it possible to look at the set of | |
--- | |
> sections \gglob, \dots,'' also make it possible to look at the set of | |
126a153 | |
> @:PASCAL H}{\ph@> | |
138c165 | |
< var@?@<Globals in the outer block@>@/ | |
--- | |
> var @<Global variables@>@/ | |
141,143c168,170 | |
< var@?@<Local variables for initialization@>@/ | |
< begin @<Initialize whatever \TeX\ might access@>@; | |
< end;@# | |
--- | |
> var @<Local variables for initialization@>@/ | |
> begin @<Initialize whatever \TeX\ might access@>@; | |
> end;@# | |
150c177 | |
< comment `@!|start_here|'. If you want to skip down to the | |
--- | |
> comment `|start_here|'. If you want to skip down to the | |
167c194 | |
< {key control points} | |
--- | |
> {key control points} | |
173,177c200,207 | |
< delimited by the codewords `$|debug|\ldotsm|gubed|$', with apologies | |
< to people who wish to preserve the purity of English. Similarly, there | |
< is some conditional code delimited by `$|stat|\ldotsm|tats|$' | |
< that is intended only for use when statistics | |
< are to be kept about \TeX's memory usage. | |
--- | |
> delimited by the codewords `$|debug|\ldots|gubed|$', with apologies | |
> to people who wish to preserve the purity of English. | |
> | |
> Similarly, there is some conditional code delimited by | |
> `$|stat|\ldots|tats|$' that is intended for use when statistics are to be | |
> kept about \TeX's memory usage. The |stat| $\ldots$ |tats| code also | |
> implements diagnostic information for \.{\\tracingparagraphs} and | |
> \.{\\tracingpages}. | |
180,181c210,211 | |
< @d debug==@{ {change this to `$\\{debug}\eqv\null$' when debugging} | |
< @d gubed==@} {change this to `$\\{gubed}\eqv\null$' when debugging} | |
--- | |
> @d debug==@{ {change this to `$\\{debug}\equiv\null$' when debugging} | |
> @d gubed==@t@>@} {change this to `$\\{gubed}\equiv\null$' when debugging} | |
185,188c215,218 | |
< @d stat==@{ {change this to `$\\{stat}\eqv\null$' when gathering | |
< usage statistics} | |
< @d tats==@} {change this to `$\\{tats}\eqv\null$' when gathering | |
< usage statistics} | |
--- | |
> @d stat==@{ {change this to `$\\{stat}\equiv\null$' when gathering | |
> usage statistics} | |
> @d tats==@t@>@} {change this to `$\\{tats}\equiv\null$' when gathering | |
> usage statistics} | |
193c223 | |
< version called \.{INITEX}, which does the extra calculations need to | |
--- | |
> version called \.{INITEX}, which does the extra calculations needed to | |
195c225 | |
< initialize \TeX's internal tables; and (2)@@there is a shorter and faster | |
--- | |
> initialize \TeX's internal tables; and (2)~there is a shorter and faster | |
198c228 | |
< the codewords `$|init|\ldotsm|tini|$'. | |
--- | |
> the codewords `$|init|\ldots|tini|$'. | |
200,201c230,231 | |
< @d init== {change this to `$\\{init}\eqv\.{@@\{}$' in the production version} | |
< @d tini== {change this to `$\\{tini}\eqv\.{@@\}}$' in the production version} | |
--- | |
> @d init== {change this to `$\\{init}\equiv\.{@@\{}$' in the production version} | |
> @d tini== {change this to `$\\{tini}\equiv\.{@@\}}$' in the production version} | |
207c237 | |
< init @<Initialize table entries (done by \.{INITEX} only)@>@;@+tini | |
--- | |
> @!init @<Initialize table entries (done by \.{INITEX} only)@>@;@+tini | |
210d239 | |
< @^system dependencies@> | |
217c246,248 | |
< @^Overflow in arithmetic@> | |
--- | |
> @:PASCAL H}{\ph@> | |
> @^system dependencies@> | |
> @^overflow in arithmetic@> | |
221c252 | |
< debug @{@&$C+,D+@}@+ gubed {but turn everything on when debugging} | |
--- | |
> @!debug @{@&$C+,D+@}@+ gubed {but turn everything on when debugging} | |
223c254 | |
< @ This \TeX\ implementation conforms to the rules of the {\sl PASCAL User | |
--- | |
> @ This \TeX\ implementation conforms to the rules of the {\sl Pascal User | |
234c265 | |
< $$\vbox{\halign{\!#\hfil\cr | |
--- | |
> $$\vbox{\halign{\ignorespaces#\hfil\cr | |
238c269 | |
< |othercases| $\langle\,$code for |x≠1| and |x≠3|$\,\rangle$\cr | |
--- | |
> |othercases| $\langle\,$code for |x<>1| and |x<>3|$\,\rangle$\cr | |
243,248c274,279 | |
< syntaxes like `\!|else|\unskip' or `\\{otherwise}' or `\\{otherwise}:', | |
< etc. The definitions of |othercases| and |endcases| should be changed to | |
< agree with local conventions. Note that no semicolon appears before | |
< |endcases| in this program, so the definition of |endcases| should include | |
< a semicolon if the compiler wants one. (Of course, if no default mechanism | |
< is available, the |case| statements of \TeX\ will have to be laboriously | |
--- | |
> syntaxes like `\&{else}' or `\&{otherwise}' or `\\{otherwise}:', etc. The | |
> definitions of |othercases| and |endcases| should be changed to agree with | |
> local conventions. Note that no semicolon appears before |endcases| in | |
> this program, so the definition of |endcases| should include a semicolon | |
> if the compiler wants one. (Of course, if no default mechanism is | |
> available, the |case| statements of \TeX\ will have to be laboriously | |
250c281,282 | |
< \PASCAL s have in fact done this, successfully but not happily!) | |
--- | |
> \PASCAL s have, in fact, done this, successfully but not happily!) | |
> @:PASCAL H}{\ph@> | |
264,265c296,301 | |
< @!mem_max=30000; {greatest index in \TeX's internal |mem| array, | |
< must be strictly less than |max_halfword|} | |
--- | |
> @!mem_max=30000; {greatest index in \TeX's internal |mem| array; | |
> must be strictly less than |max_halfword|; | |
> must be equal to |mem_top| in \.{INITEX}, otherwise |>=mem_top|} | |
> @!mem_min=0; {smallest index in \TeX's internal |mem| array; | |
> must be |min_halfword| or more; | |
> must be equal to |mem_bot| in \.{INITEX}, otherwise |<=mem_bot|} | |
267,272c303,309 | |
< current lines of open files; must not exceed |max_halfword|} | |
< @!error_line=64; {width of context lines on terminal error messages} | |
< @!half_error_line=32; {width of first lines of contexts in terminal | |
< error messages, should be between 30 and |error_line-15|} | |
< @!max_print_line=72; {width of longest text lines output, should be at least 60} | |
< @!stack_size=80; {maximum number of simultaneous input sources} | |
--- | |
> current lines of open files and in control sequences between | |
> \.{\\csname} and \.{\\endcsname}; must not exceed |max_halfword|} | |
> @!error_line=72; {width of context lines on terminal error messages} | |
> @!half_error_line=42; {width of first lines of contexts in terminal | |
> error messages; should be between 30 and |error_line-15|} | |
> @!max_print_line=79; {width of longest text lines output; should be at least 60} | |
> @!stack_size=200; {maximum number of simultaneous input sources} | |
274,278c311,315 | |
< can be going on simultaneously} | |
< @!font_max=75; {maximum internal font number, must not exceed |max_quarterword|} | |
< @!bad_font_code=300; {user font codes must be less than this} | |
< @!font_mem_size=15000; {number of words of |font_info| for all fonts} | |
< @!param_size=30; {maximum number of simultaneous macro parameters} | |
--- | |
> can be going on simultaneously} | |
> @!font_max=75; {maximum internal font number; must not exceed |max_quarterword| | |
> and must be at most |font_base+256|} | |
> @!font_mem_size=20000; {number of words of |font_info| for all fonts} | |
> @!param_size=60; {maximum number of simultaneous macro parameters} | |
282,292c319,330 | |
< available for the user's control sequences and font names, | |
< after \TeX's own error messages are stored} | |
< @!pool_size=30000; {maximum number of characters in strings, including all | |
< error messages and help texts, and the names of all fonts and | |
< control sequences; must be at least 22000 more than |string_vacancies|} | |
< @!align_size=4; {maximum number of simultaneous alignments} | |
< @!save_size=300; {space for saving values outside of current group, must be | |
< at most |max_halfword|} | |
< @!trie_size=7000; {space for hyphenation patterns, should be larger for | |
< \.{INITEX} than it is in production versions of \TeX} | |
< @!dvi_buf_size=800; {size of the output buffer, must be a multiple of 8} | |
--- | |
> available for the user's control sequences and font names, | |
> after \TeX's own error messages are stored} | |
> @!pool_size=32000; {maximum number of characters in strings, including all | |
> error messages and help texts, and the names of all fonts and | |
> control sequences; must exceed |string_vacancies| by the total | |
> length of \TeX's own strings, which is currently about 23000} | |
> @!save_size=600; {space for saving values outside of current group; must be | |
> at most |max_halfword|} | |
> @!trie_size=8000; {space for hyphenation patterns; should be larger for | |
> \.{INITEX} than it is in production versions of \TeX} | |
> @!trie_op_size=500; {space for ``opcodes'' in the hyphenation patterns} | |
> @!dvi_buf_size=800; {size of the output buffer; must be a multiple of 8} | |
294,296c332,334 | |
< @!pool_name='<TeX.sources>TEX.POOL '; | |
< {string of length |file_name_size|, tells where string pool appears} | |
< @^system dependencies@> | |
--- | |
> @!pool_name='TeXformats:TEX.POOL '; | |
> {string of length |file_name_size|; tells where the string pool appears} | |
> @.TeXformats@> | |
309,314c347,353 | |
< @d mem_base=0 {smallest index in the |mem| array, must not be less | |
< than |min_halfword|} | |
< @d hi_mem_base=12000 {smallest index in the single-word area of |mem|, | |
< must be substantially larger than |mem_base| and smaller than |mem_max|} | |
< @d font_base=0 {smallest internal font number, must not be less | |
< than |min_quarterword|} | |
--- | |
> @d mem_bot=0 {smallest index in the |mem| array dumped by \.{INITEX}; | |
> must not be less than |mem_min|} | |
> @d mem_top==30000 {largest index in the |mem| array dumped by \.{INITEX}; | |
> must be substantially larger than |mem_bot| | |
> and not greater than |mem_max|} | |
> @d font_base=0 {smallest internal font number; must not be less | |
> than |min_quarterword|} | |
316,317c355,356 | |
< about |(mem_max-hi_mem_base)/6|, but 2100 is already quite generous} | |
< @d hash_prime=1777 {a prime number equal to about 85\%\ of |hash_size|} | |
--- | |
> about |(mem_max-mem_min)/10|} | |
> @d hash_prime=1777 {a prime number equal to about 85\pct! of |hash_size|} | |
330,331c369,370 | |
< @ Later on we will say `\!|if mem_max≥max_halfword then bad←10|', or | |
< something similar. (We can't do that until |max_halfword| has been defined.) | |
--- | |
> @ Later on we will say `\ignorespaces|if mem_max>=max_halfword then bad:=14|', | |
> or something similar. (We can't do that until |max_halfword| has been defined.) | |
334,339c373,380 | |
< bad←0; | |
< if (half_error_line<30)∨(half_error_line>error_line-15) then bad←1; | |
< if max_print_line<60 then bad←2; | |
< if dvi_buf_size mod 8≠0 then bad←3; | |
< if (hi_mem_base<mem_base+100)∨(hi_mem_base+100>mem_max) then bad←4; | |
< if hash_prime>hash_size then bad←5; | |
--- | |
> bad:=0; | |
> if (half_error_line<30)or(half_error_line>error_line-15) then bad:=1; | |
> if max_print_line<60 then bad:=2; | |
> if dvi_buf_size mod 8<>0 then bad:=3; | |
> if mem_bot+1100>mem_top then bad:=4; | |
> if hash_prime>hash_size then bad:=5; | |
> if max_in_open>=128 then bad:=6; | |
> if mem_top<256+11 then bad:=7; {we will want |null_list>255|} | |
342,354c383,394 | |
< occasional |goto| statements will be meaningful. We insert | |
< the label `|exit|:' just before the `\!|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|'. | |
< | |
--- | |
> 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|'. | |
378,379c418,420 | |
< @d incr(#) == #←#+1 {increase a variable by unity} | |
< @d decr(#) == #←#-1 {decrease a variable by unity} | |
--- | |
> @d incr(#) == #:=#+1 {increase a variable by unity} | |
> @d decr(#) == #:=#-1 {decrease a variable by unity} | |
> @d negate(#) == #:=-# {change the sign of a variable} | |
381c422,423 | |
< @f loop == xclause {\.{WEB}'s |xclause| acts like `\!|while true do|\unskip'} | |
--- | |
> @f loop == xclause | |
> {\.{WEB}'s |xclause| acts like `\ignorespaces|while true do|\unskip'} | |
384a427,428 | |
> @d empty=0 {symbolic name for a null constant} | |
> | |
386,388c430,432 | |
< In order to make \TeX\ readily portable between a wide variety of | |
< computers, all of its input text is converted to an internal seven-bit | |
< code that is essentially standard ascii, the ``American Standard Code for | |
--- | |
> In order to make \TeX\ readily portable to a wide variety of | |
> computers, all of its input text is converted to an internal eight-bit | |
> code that includes standard ASCII, the ``American Standard Code for | |
390c434 | |
< character is read in. Conversely, characters are converted from ascii to | |
--- | |
> character is read in. Conversely, characters are converted from ASCII to | |
392c436 | |
< text file. | |
--- | |
> text file. | |
396c440 | |
< character `\.A' has ascii code $65=@'101$, and when \TeX\ typesets | |
--- | |
> character `\.A' has ASCII code $65=@'101$, and when \TeX\ typesets | |
400c444 | |
< \TeX's device-independent files is responsible for converting from ascii to | |
--- | |
> \TeX's device-independent files is responsible for converting from ASCII to | |
402c446 | |
< @^ascii code@> | |
--- | |
> @^ASCII code@> | |
404c448 | |
< \TeX's internal code is relevant also with respect to constants | |
--- | |
> \TeX's internal code also defines the value of constants | |
406c450 | |
< \.{\\chcode}, \.{\\mathcode}, \.{\\uccode}, \.{\\lccode}, and \.{\\delcode} | |
--- | |
> \.{\\catcode}, \.{\\mathcode}, \.{\\uccode}, \.{\\lccode}, and \.{\\delcode} | |
409,410c453,454 | |
< @ Characters of text that have been converted to \TeX's internal form | |
< are said to be of type |ascii_code|, which is a subrange of the integers. | |
--- | |
> @ Characters of text that have been converted to \TeX's internal form | |
> are said to be of type |ASCII_code|, which is a subrange of the integers. | |
413c457 | |
< @!ascii_code=0..127; {seven-bit numbers} | |
--- | |
> @!ASCII_code=0..255; {eight-bit numbers} | |
416,418c460,462 | |
< character sets were common, so it did not make provision for lower case | |
< letters. Nowadays, of course, we need to deal with both upper and lower case | |
< alphabets in a convenient way, especially in a program for typesetting; | |
--- | |
> character sets were common, so it did not make provision for lowercase | |
> letters. Nowadays, of course, we need to deal with both capital and small | |
> letters in a convenient way, especially in a program for typesetting; | |
423c467 | |
< with ascii codes @'40 through @'176; all of these characters are now | |
--- | |
> with ASCII codes @'40 through @'176; all of these characters are now | |
435c479 | |
< from |ascii_code| when they are input and output. We shall also assume | |
--- | |
> from |ASCII_code| when they are input and output. We shall also assume | |
437c481 | |
< |chr(last_text_char)|, in\-clu\-sive. The following definitions should be | |
--- | |
> |chr(last_text_char)|, inclusive. The following definitions should be | |
443c487 | |
< @d last_text_char=127 {ordinal number of the largest element of |text_char|} | |
--- | |
> @d last_text_char=255 {ordinal number of the largest element of |text_char|} | |
446c490 | |
< i:0..last_text_char; | |
--- | |
> @!i:integer; | |
448c492 | |
< @ The \TeX\ processor converts between ascii code and | |
--- | |
> @ The \TeX\ processor converts between ASCII code and | |
452,462c496,509 | |
< @<Globals...@>= | |
< @!xord: array [text_char] of ascii_code; | |
< {specifies conversion of input characters} | |
< @!xchr: array [ascii_code] of text_char; | |
< {specifies conversion of output characters} | |
< | |
< @ Since we are assuming that our \PASCAL\ system is able to read and write the | |
< visible characters of standard ascii (although not necessarily using the | |
< ascii codes to represent them), the following assignment statements initialize | |
< most of the |xchr| array properly, without needing any system-dependent | |
< changes. | |
--- | |
> @<Glob...@>= | |
> @!xord: array [text_char] of ASCII_code; | |
> {specifies conversion of input characters} | |
> @!xchr: array [ASCII_code] of text_char; | |
> {specifies conversion of output characters} | |
> | |
> @ Since we are assuming that our \PASCAL\ system is able to read and | |
> write the visible characters of standard ASCII (although not | |
> necessarily using the ASCII codes to represent them), the following | |
> assignment statements initialize the standard part of the |xchr| array | |
> properly, without needing any system-dependent changes. On the other | |
> hand, it is possible to implement \TeX\ with less complete character | |
> sets, and in such cases it will be necessary to change something here. | |
> @^system dependencies@> | |
465,561c512,606 | |
< xchr[@'40]←' '; | |
< xchr[@'41]←'!'; | |
< xchr[@'42]←'"'; | |
< xchr[@'43]←'#'; | |
< xchr[@'44]←'$'; | |
< xchr[@'45]←'%'; | |
< xchr[@'46]←'&'; | |
< xchr[@'47]←'''';@/ | |
< xchr[@'50]←'('; | |
< xchr[@'51]←')'; | |
< xchr[@'52]←'*'; | |
< xchr[@'53]←'+'; | |
< xchr[@'54]←','; | |
< xchr[@'55]←'-'; | |
< xchr[@'56]←'.'; | |
< xchr[@'57]←'/';@/ | |
< xchr[@'60]←'0'; | |
< xchr[@'61]←'1'; | |
< xchr[@'62]←'2'; | |
< xchr[@'63]←'3'; | |
< xchr[@'64]←'4'; | |
< xchr[@'65]←'5'; | |
< xchr[@'66]←'6'; | |
< xchr[@'67]←'7';@/ | |
< xchr[@'70]←'8'; | |
< xchr[@'71]←'9'; | |
< xchr[@'72]←':'; | |
< xchr[@'73]←';'; | |
< xchr[@'74]←'<'; | |
< xchr[@'75]←'='; | |
< xchr[@'76]←'>'; | |
< xchr[@'77]←'?';@/ | |
< xchr[@'100]←'@@'; | |
< xchr[@'101]←'A'; | |
< xchr[@'102]←'B'; | |
< xchr[@'103]←'C'; | |
< xchr[@'104]←'D'; | |
< xchr[@'105]←'E'; | |
< xchr[@'106]←'F'; | |
< xchr[@'107]←'G';@/ | |
< xchr[@'110]←'H'; | |
< xchr[@'111]←'I'; | |
< xchr[@'112]←'J'; | |
< xchr[@'113]←'K'; | |
< xchr[@'114]←'L'; | |
< xchr[@'115]←'M'; | |
< xchr[@'116]←'N'; | |
< xchr[@'117]←'O';@/ | |
< xchr[@'120]←'P'; | |
< xchr[@'121]←'Q'; | |
< xchr[@'122]←'R'; | |
< xchr[@'123]←'S'; | |
< xchr[@'124]←'T'; | |
< xchr[@'125]←'U'; | |
< xchr[@'126]←'V'; | |
< xchr[@'127]←'W';@/ | |
< xchr[@'130]←'X'; | |
< xchr[@'131]←'Y'; | |
< xchr[@'132]←'Z'; | |
< xchr[@'133]←'['; | |
< xchr[@'134]←'\'; | |
< xchr[@'135]←']'; | |
< xchr[@'136]←'^'; | |
< xchr[@'137]←'_';@/ | |
< xchr[@'140]←'`'; | |
< xchr[@'141]←'a'; | |
< xchr[@'142]←'b'; | |
< xchr[@'143]←'c'; | |
< xchr[@'144]←'d'; | |
< xchr[@'145]←'e'; | |
< xchr[@'146]←'f'; | |
< xchr[@'147]←'g';@/ | |
< xchr[@'150]←'h'; | |
< xchr[@'151]←'i'; | |
< xchr[@'152]←'j'; | |
< xchr[@'153]←'k'; | |
< xchr[@'154]←'l'; | |
< xchr[@'155]←'m'; | |
< xchr[@'156]←'n'; | |
< xchr[@'157]←'o';@/ | |
< xchr[@'160]←'p'; | |
< xchr[@'161]←'q'; | |
< xchr[@'162]←'r'; | |
< xchr[@'163]←'s'; | |
< xchr[@'164]←'t'; | |
< xchr[@'165]←'u'; | |
< xchr[@'166]←'v'; | |
< xchr[@'167]←'w';@/ | |
< xchr[@'170]←'x'; | |
< xchr[@'171]←'y'; | |
< xchr[@'172]←'z'; | |
< xchr[@'173]←'{'; | |
< xchr[@'174]←'|'; | |
< xchr[@'175]←'}'; | |
< xchr[@'176]←'~';@/ | |
< xchr[0]←' '; xchr[@'177]←' '; | |
< {ascii codes 0 and |@'177| do not appear in text} | |
--- | |
> xchr[@'40]:=' '; | |
> xchr[@'41]:='!'; | |
> xchr[@'42]:='"'; | |
> xchr[@'43]:='#'; | |
> xchr[@'44]:='$'; | |
> xchr[@'45]:='%'; | |
> xchr[@'46]:='&'; | |
> xchr[@'47]:='''';@/ | |
> xchr[@'50]:='('; | |
> xchr[@'51]:=')'; | |
> xchr[@'52]:='*'; | |
> xchr[@'53]:='+'; | |
> xchr[@'54]:=','; | |
> xchr[@'55]:='-'; | |
> xchr[@'56]:='.'; | |
> xchr[@'57]:='/';@/ | |
> xchr[@'60]:='0'; | |
> xchr[@'61]:='1'; | |
> xchr[@'62]:='2'; | |
> xchr[@'63]:='3'; | |
> xchr[@'64]:='4'; | |
> xchr[@'65]:='5'; | |
> xchr[@'66]:='6'; | |
> xchr[@'67]:='7';@/ | |
> xchr[@'70]:='8'; | |
> xchr[@'71]:='9'; | |
> xchr[@'72]:=':'; | |
> xchr[@'73]:=';'; | |
> xchr[@'74]:='<'; | |
> xchr[@'75]:='='; | |
> xchr[@'76]:='>'; | |
> xchr[@'77]:='?';@/ | |
> xchr[@'100]:='@@'; | |
> xchr[@'101]:='A'; | |
> xchr[@'102]:='B'; | |
> xchr[@'103]:='C'; | |
> xchr[@'104]:='D'; | |
> xchr[@'105]:='E'; | |
> xchr[@'106]:='F'; | |
> xchr[@'107]:='G';@/ | |
> xchr[@'110]:='H'; | |
> xchr[@'111]:='I'; | |
> xchr[@'112]:='J'; | |
> xchr[@'113]:='K'; | |
> xchr[@'114]:='L'; | |
> xchr[@'115]:='M'; | |
> xchr[@'116]:='N'; | |
> xchr[@'117]:='O';@/ | |
> xchr[@'120]:='P'; | |
> xchr[@'121]:='Q'; | |
> xchr[@'122]:='R'; | |
> xchr[@'123]:='S'; | |
> xchr[@'124]:='T'; | |
> xchr[@'125]:='U'; | |
> xchr[@'126]:='V'; | |
> xchr[@'127]:='W';@/ | |
> xchr[@'130]:='X'; | |
> xchr[@'131]:='Y'; | |
> xchr[@'132]:='Z'; | |
> xchr[@'133]:='['; | |
> xchr[@'134]:='\'; | |
> xchr[@'135]:=']'; | |
> xchr[@'136]:='^'; | |
> xchr[@'137]:='_';@/ | |
> xchr[@'140]:='`'; | |
> xchr[@'141]:='a'; | |
> xchr[@'142]:='b'; | |
> xchr[@'143]:='c'; | |
> xchr[@'144]:='d'; | |
> xchr[@'145]:='e'; | |
> xchr[@'146]:='f'; | |
> xchr[@'147]:='g';@/ | |
> xchr[@'150]:='h'; | |
> xchr[@'151]:='i'; | |
> xchr[@'152]:='j'; | |
> xchr[@'153]:='k'; | |
> xchr[@'154]:='l'; | |
> xchr[@'155]:='m'; | |
> xchr[@'156]:='n'; | |
> xchr[@'157]:='o';@/ | |
> xchr[@'160]:='p'; | |
> xchr[@'161]:='q'; | |
> xchr[@'162]:='r'; | |
> xchr[@'163]:='s'; | |
> xchr[@'164]:='t'; | |
> xchr[@'165]:='u'; | |
> xchr[@'166]:='v'; | |
> xchr[@'167]:='w';@/ | |
> xchr[@'170]:='x'; | |
> xchr[@'171]:='y'; | |
> xchr[@'172]:='z'; | |
> xchr[@'173]:='{'; | |
> xchr[@'174]:='|'; | |
> xchr[@'175]:='}'; | |
> xchr[@'176]:='~';@/ | |
563c608 | |
< @ Some of the ascii codes without visible characters have been given symbolic | |
--- | |
> @ Some of the ASCII codes without visible characters have been given symbolic | |
566,568c611,613 | |
< @d null_code=@'0 {ascii code that might disappear} | |
< @d carriage_return=@'15 {ascii code used at end of line} | |
< @d invalid_code=@'177 {ascii code that should not appear} | |
--- | |
> @d null_code=@'0 {ASCII code that might disappear} | |
> @d carriage_return=@'15 {ASCII code used at end of line} | |
> @d invalid_code=@'177 {ASCII code that many systems prohibit in text files} | |
570c615 | |
< @ The ascii code is ``standard'' only to a certain extent, since many | |
--- | |
> @ The ASCII code is ``standard'' only to a certain extent, since many | |
572c617 | |
< to more than 94 printing characters. Appendix@@C of the \TeX\ manual | |
--- | |
> to more than 94 printing characters. Appendix~C of {\sl The \TeX book\/} | |
574a620 | |
> @:TeXbook}{\sl The \TeX book@> | |
577c623 | |
< on a garden-variety \PASCAL\ for which only standard ascii | |
--- | |
> on a garden-variety \PASCAL\ for which only standard ASCII | |
579c625 | |
< what codes are specified in |xchr[1..@'37]|, but the safest policy is to | |
--- | |
> what codes are specified in |xchr[0..@'37]|, but the safest policy is to | |
584,588c630 | |
< like `\.\NE' instead of `\.{\\ne}'. At MIT, for example, it would be more | |
< appropriate to substitute the code | |
< $$\hbox{|for i←1 to @'37 do xchr[i]←chr(i);|}$$ | |
< \TeX's character set is essentially the same as MIT's, even with respect to | |
< characters less than@@@'40. People with extended character sets can | |
--- | |
> like `\.^^Z' instead of `\.{\\ne}'. People with extended character sets can | |
590,596c632,638 | |
< characters the users of \TeX\ are allowed to have in their input files, | |
< provided that unsuitable characters do not correspond to the special | |
< codes like |carriage_return| that are listed above. It is best | |
< to make the codes correspond to the intended interpretations as shown | |
< in Appendix@@C whenever possible; but this is not necessary. For example, | |
< in countries with an alphabet of more than 26 letters, it is usually best | |
< to map the additional letters into codes less than@@@'40. | |
--- | |
> characters the users of \TeX\ are allowed to have in their input files. | |
> It is best to make the codes correspond to the intended interpretations as | |
> shown in Appendix~C whenever possible; but this is not necessary. For | |
> example, in countries with an alphabet of more than 26 letters, it is | |
> usually best to map the additional letters into codes less than~@'40. | |
> To get the most ``permissive'' character set, change |' '| on the | |
> right of these assignment statements to |chr(i)|. | |
601c643,644 | |
< for i←1 to @'37 do xchr[i]←' '; | |
--- | |
> for i:=0 to @'37 do xchr[i]:=' '; | |
> for i:=@'177 to @'377 do xchr[i]:=' '; | |
606c649 | |
< |j| or more; hence, standard ascii code numbers will be used instead of | |
--- | |
> |j| or more; hence, standard ASCII code numbers will be used instead of | |
610,611c653,656 | |
< for i←first_text_char to last_text_char do xord[chr(i)]←invalid_code; | |
< for i←1 to @'176 do xord[xchr[i]]←i; | |
--- | |
> for i:=first_text_char to last_text_char do xord[chr(i)]:=invalid_code; | |
> for i:=@'200 to @'377 do xord[xchr[i]]:=i; | |
> for i:=0 to @'176 do xord[xchr[i]]:=i; | |
> | |
616c661 | |
< that input and output are not a part of ``real'' programming. Well, it is true | |
--- | |
> that input and output are not part of ``real'' programming. Well, it is true | |
621,622c666,667 | |
< two choices: whether to attack I/O now and get it over with, or to postpone | |
< it until near the end. Neither prospect is very attractive, so let's | |
--- | |
> 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 | |
625,627c670,672 | |
< 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 | |
--- | |
> 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 | |
629c674 | |
< output from a specified file; (4)@@testing whether the end of an input | |
--- | |
> output from a specified file; (4)~testing whether the end of an input | |
632c677 | |
< Note that \TeX\ needs to deal with only two kinds of files. | |
--- | |
> \TeX\ needs to deal with two kinds of files. | |
641,644c686,689 | |
< \TeX\ actually makes use also of a third kind of file, called a |word_file|, | |
< when dumping and reloading format information for its own initialization. | |
< We shall define a word file later; but it will be possible for us to | |
< do a few simple things with them in this section before they are defined. | |
--- | |
> 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. | |
664,667c709,712 | |
< @!name_of_file:packed array[1..file_name_size] of char; | |
< {on some systems this may be a \&{record} variable} | |
< @!name_length:0..file_name_size; {this many characters are actually | |
< relevant in |name_of_file| (the rest are blank)} | |
--- | |
> @!name_of_file:packed array[1..file_name_size] of char;@;@/ | |
> {on some systems this may be a \&{record} variable} | |
> @!name_length:0..file_name_size;@/{this many characters are actually | |
> relevant in |name_of_file| (the rest are blank)} | |
669,670c714,715 | |
< @ The \ph\ compiler with which the present version of \TeX\ was pre\-pared has | |
< extended the rules of \PASCAL\ in a very convenient way. To open file@@|f|, | |
--- | |
> @ The \ph\ compiler with which the present version of \TeX\ was prepared has | |
> extended the rules of \PASCAL\ in a very convenient way. To open file~|f|, | |
672,677c717,722 | |
< $$\vbox{\halign{#\hfil\qquadⓧ#\hfil\cr | |
< |reset(f,@t\\{name}@>,'/O')|ⓧfor input;\cr | |
< |rewrite(f,@t\\{name}@>,'/O')|ⓧfor output.\cr}}$$ | |
< The `\\{name}' parameter, which is of type `\!|packed | |
< array[@t\<\\{any}>@>] of text_char|', stands for the name of | |
< the external file that is being opened for input or output. | |
--- | |
> $$\vbox{\halign{#\hfil\qquad&#\hfil\cr | |
> |reset(f,@t\\{name}@>,'/O')|&for input;\cr | |
> |rewrite(f,@t\\{name}@>,'/O')|&for output.\cr}}$$ | |
> The `\\{name}' parameter, which is of type `{\bf packed array | |
> $[\langle\\{any}\rangle]$ of \\{char}}', stands for the name of | |
> the external file that is being opened for input or output. | |
683,685c728,730 | |
< (e.g., it might already be in use), we will have |eof(f)=true| after an | |
< unsuccessful |reset|, and |eof(f)=false| after an unsuccessful |rewrite|. | |
< This allows \TeX\ to undertake appropriate corrective action. | |
--- | |
> (e.g., someone may already be trying to write the same file), we will have | |
> |@!erstat(f)<>0| after an unsuccessful |reset| or |rewrite|. This allows | |
> \TeX\ to undertake appropriate corrective action. | |
686a732 | |
> @^system dependencies@> | |
688,690c734,735 | |
< We can now implement the file-opening procedures in the following simple way, | |
< where the functions return |false| if no file identified by |name_of_file| | |
< could be opened: | |
--- | |
> \TeX's file-opening procedures return |false| if no file identified by | |
> |name_of_file| could be opened. | |
691a737,738 | |
> @d reset_OK(#)==erstat(#)=0 | |
> @d rewrite_OK(#)==erstat(#)=0 | |
694,695c741,742 | |
< {open a text file for input} | |
< begin reset(f,name_of_file,'/O'); a_open_in←not eof(f); | |
--- | |
> {open a text file for input} | |
> begin reset(f,name_of_file,'/O'); a_open_in:=reset_OK(f); | |
699,700c746,747 | |
< {open a text file for output} | |
< begin rewrite(f,name_of_file,'/O'); a_open_out←eof(f); | |
--- | |
> {open a text file for output} | |
> begin rewrite(f,name_of_file,'/O'); a_open_out:=rewrite_OK(f); | |
704,705c751,752 | |
< {open a binary file for input} | |
< begin reset(f,name_of_file,'/O'); b_open_in←not eof(f); | |
--- | |
> {open a binary file for input} | |
> begin reset(f,name_of_file,'/O'); b_open_in:=reset_OK(f); | |
709,710c756,757 | |
< {open a binary file for output} | |
< begin rewrite(f,name_of_file,'/O'); b_open_out←eof(f); | |
--- | |
> {open a binary file for output} | |
> begin rewrite(f,name_of_file,'/O'); b_open_out:=rewrite_OK(f); | |
714,715c761,762 | |
< {open a word file for input} | |
< begin reset(f,name_of_file,'/O'); w_open_in←not eof(f); | |
--- | |
> {open a word file for input} | |
> begin reset(f,name_of_file,'/O'); w_open_in:=reset_OK(f); | |
719,720c766,767 | |
< {open a word file for output} | |
< begin rewrite(f,name_of_file,'/O'); w_open_out←eof(f); | |
--- | |
> {open a word file for output} | |
> begin rewrite(f,name_of_file,'/O'); w_open_out:=rewrite_OK(f); | |
723a771 | |
> @:PASCAL H}{\ph@> | |
729a778,780 | |
> These procedures should not generate error messages if a file is | |
> being closed before it has been successfully opened. | |
> | |
744c795 | |
< binary@@I/O. Text output is also easy to do with standard \PASCAL\ routines. | |
--- | |
> binary~I/O. Text output is also easy to do with standard \PASCAL\ routines. | |
746,747c797,798 | |
< of the necessary translation to |ascii_code| values, and because | |
< \TeX's conventions should be efficient and they should | |
--- | |
> of the necessary translation to |ASCII_code| values. | |
> \TeX's conventions should be efficient, and they should | |
753c804 | |
< now, it suffices for us to know that |buffer| is an array of |ascii_code| | |
--- | |
> now, it suffices for us to know that |buffer| is an array of |ASCII_code| | |
758c809 | |
< @!buffer:array[0..buf_size] of ascii_code; {lines of characters being read} | |
--- | |
> @!buffer:array[0..buf_size] of ASCII_code; {lines of characters being read} | |
764,769c815,822 | |
< 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 does nothing else). The |ascii_code| numbers that represent | |
< the next line of the file are input into |buffer[first]|, |buffer[first+1]|, | |
< $\ldotss$, |buffer[last-1]|; and the global variable |last| is set equal | |
< to |first| plus the length of the line. | |
--- | |
> file into available positions of the buffer array and returns the value | |
> |true|, unless the file has already been entirely read, in which case it | |
> returns |false| and sets |last:=first|. In general, the |ASCII_code| | |
> numbers that represent the next line of the file are input into | |
> |buffer[first]|, |buffer[first+1]|, \dots, |buffer[last-1]|; and the | |
> global variable |last| is set equal to |first| plus the length of the | |
> line. Trailing blanks are removed from the line; thus, either |last=first| | |
> (in which case the line was entirely blank) or |buffer[last-1]<>" "|. | |
772c825 | |
< would make |last≥buf_size|; this is done so that other parts of \TeX\ | |
--- | |
> would make |last>=buf_size|; this is done so that other parts of \TeX\ | |
775,776c828,829 | |
< |first<buf_size| will always hold, so there is always room for an ``empty'' | |
< line. | |
--- | |
> |first<buf_size| will always hold, so that there is always room for an | |
> ``empty'' line. | |
782,786c835,844 | |
< This procedure does a |get| before looking at the first character of the | |
< line, and it 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. Other parts of \TeX\ take care of inputting | |
< the first line of a file, so that the first character is not lost. | |
--- | |
> If the |bypass_eoln| parameter is |true|, |input_ln| will do a |get| | |
> before looking at the first character of the line; this skips over | |
> an |eoln| that was in |f^|. The procedure does not do a |get| when it | |
> reaches the end of the line; therefore it can be used to acquire input | |
> from the user's terminal as well as from ordinary text files. | |
> | |
> Standard \PASCAL\ says that a file should have |eoln| immediately | |
> before |eof|, but \TeX\ needs only a weaker restriction: If |eof| | |
> occurs in the middle of a line, the system function |eoln| should return | |
> a |true| result (even though |f^| will be undefined). | |
796,810c854,872 | |
< @p function input_ln(var f:alpha_file):boolean; {inputs the next line | |
< or returns |false|} | |
< begin get(f); {input the first character of the line into |f^|} | |
< if eof(f) then input_ln←false | |
< else begin last←first; {cf.\ Matthew 19:30} | |
< while not eoln(f) do | |
< begin if last≥max_buf_stack then | |
< begin max_buf_stack←last+1; | |
< if max_buf_stack=buf_size then | |
< overflow("buffer size",buf_size); | |
< end; | |
< buffer[last]←xord[f^]; get(f); incr(last); | |
< end; | |
< input_ln←true; | |
< end; | |
--- | |
> @p function input_ln(var f:alpha_file;@!bypass_eoln:boolean):boolean; | |
> {inputs the next line or returns |false|} | |
> var last_nonblank:0..buf_size; {|last| with trailing blanks removed} | |
> begin if bypass_eoln then if not eof(f) then get(f); | |
> {input the first character of the line into |f^|} | |
> last:=first; {cf.\ Matthew 19\thinspace:\thinspace30} | |
> if eof(f) then input_ln:=false | |
> else begin last_nonblank:=first; | |
> while not eoln(f) do | |
> begin if last>=max_buf_stack then | |
> begin max_buf_stack:=last+1; | |
> if max_buf_stack=buf_size then | |
> @<Report overflow of the input buffer, and abort@>; | |
> end; | |
> buffer[last]:=xord[f^]; get(f); incr(last); | |
> if buffer[last-1]<>" " then last_nonblank:=last; | |
> end; | |
> last:=last_nonblank; input_ln:=true; | |
> end; | |
823c885,887 | |
< @ Here is how to open the terminal files in \ph: | |
--- | |
> @ Here is how to open the terminal files | |
> in \ph. The `\.{/I}' switch suppresses the first |get|. | |
> @:PASCAL H}{\ph@> | |
826c890 | |
< @d t_open_in==reset(term_in,'TTY:','/O') {open the terminal for text input} | |
--- | |
> @d t_open_in==reset(term_in,'TTY:','/O/I') {open the terminal for text input} | |
830c894,895 | |
< happens on the user's terminal, and two procedures are used for this | |
--- | |
> happens on the user's terminal, and three system-dependent | |
> procedures are used for this | |
834c899 | |
< The other, |clear_terminal|, is called when we wish to cancel any | |
--- | |
> The second, |clear_terminal|, is called when we wish to cancel any | |
836,837c901,905 | |
< issue an unexpected error message). The following macros show how these | |
< two operations can be specified in \ph: | |
--- | |
> issue an unexpected error message). The third, |wake_up_terminal|, | |
> is supposed to revive the terminal if the user has disabled it by | |
> some instruction to the operating system. The following macros show how | |
> these operations can be specified in \ph: | |
> @:PASCAL H}{\ph@> | |
841a910 | |
> @d wake_up_terminal == do_nothing {cancel the user's cancellation of output} | |
844,845c913,914 | |
< the user's terminal. This line is special because it is read before we | |
< have opened the error transcript file; there is sort of a ``chicken and | |
--- | |
> 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 | |
848c917 | |
< the transcript file will be named `\.{paper.err}'; but if no \.{\\input} | |
--- | |
> the transcript file will be named `\.{paper.log}'; but if no \.{\\input} | |
850c919 | |
< file will acquire its default name `\.{texput.err}'. (The transcript file | |
--- | |
> file will acquire its default name `\.{texput.log}'. (The transcript file | |
852a922 | |
> @.texput@> | |
862,863c932,951 | |
< @ Different systems have different ways to get started, but regardless of | |
< what conventions are adopted the routine that initializes the terminal | |
--- | |
> The first line is special also because it may be read before \TeX\ has | |
> input a format file. In such cases, normal error messages cannot yet | |
> be given. The following code uses concepts that will be explained later. | |
> (If the \PASCAL\ compiler does not support non-local |@!goto|\unskip, the | |
> @^system dependencies@> | |
> statement `|goto final_end|' should be replaced by something that | |
> quietly terminates the program.) | |
> | |
> @<Report overflow of the input buffer, and abort@>= | |
> if format_ident=0 then | |
> begin write_ln(term_out,'Buffer size exceeded!'); goto final_end; | |
> @.Buffer size exceeded@> | |
> end | |
> else begin cur_input.loc_field:=first; cur_input.limit_field:=last-1; | |
> overflow("buffer size",buf_size); | |
> @:TeX capacity exceeded buffer size}{\quad buffer size@> | |
> end | |
> | |
> @ Different systems have different ways to get started. But regardless of | |
> what conventions are adopted, the routine that initializes the terminal | |
867,868c955,956 | |
< terminal. (The file |term_out| will already be open for output to the | |
< terminal.) | |
--- | |
> terminal. (The file |term_out| will already be open for output to the | |
> terminal.) | |
871,873c959,961 | |
< 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. | |
--- | |
> 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. | |
876,877c964,965 | |
< command line, should appear in locations 0 to |last-1| of the | |
< |buffer| array. | |
--- | |
> command line, should appear in locations |first| to |last-1| of the | |
> |buffer| array. | |
880,881c968,969 | |
< character that \TeX\ reads next is in |buffer[loc]|. This | |
< character should not be blank, and we should have |loc<last|. | |
--- | |
> character to be read next by \TeX\ is in |buffer[loc]|. This | |
> character should not be blank, and we should have |loc<last|. | |
884,886c972,974 | |
< 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 `\.\#'.) | |
--- | |
> 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~`\.{**}'.) | |
891c979 | |
< with\-out retrieving a possible command line. | |
--- | |
> without retrieving a possible command line. | |
899,913c987,1002 | |
< loop@+begin write(term_out,'**'); update_terminal; | |
< if not input_ln(term_in) then {this shouldn't happen} | |
< begin write_ln(term_out); | |
< write(term_out,'! End of file on the terminal... why?'); | |
< @.End of file on the terminal...@> | |
< init_terminal←false; return; | |
< end; | |
< loc←first; | |
< while (loc<last)∧(buffer[loc]=" ") do incr(loc); | |
< if loc<last then | |
< begin init_terminal←true; | |
< return; {return unless the line was all blank} | |
< end; | |
< write_ln(term_out,'Please type the name of your input file.'); | |
< end; | |
--- | |
> loop@+begin wake_up_terminal; write(term_out,'**'); update_terminal; | |
> @.**@> | |
> if not input_ln(term_in,true) then {this shouldn't happen} | |
> begin write_ln(term_out); | |
> write(term_out,'! End of file on the terminal... why?'); | |
> @.End of file on the terminal@> | |
> init_terminal:=false; return; | |
> end; | |
> loc:=first; | |
> while (loc<last)and(buffer[loc]=" ") do incr(loc); | |
> if loc<last then | |
> begin init_terminal:=true; | |
> return; {return unless the line was all blank} | |
> end; | |
> write_ln(term_out,'Please type the name of your input file.'); | |
> end; | |
914a1004 | |
> | |
917c1007 | |
< of seven-bit characters. Since \PASCAL\ does not have a well-developed string | |
--- | |
> of eight-bit characters. Since \PASCAL\ does not have a well-developed string | |
922c1012 | |
< The array |str_pool| contains all of the (seven-bit) ascii codes in all | |
--- | |
> The array |str_pool| contains all of the (eight-bit) ASCII codes in all | |
925,926c1015,1016 | |
< string number |s| comprises the characters |str_pool[j]| for | |
< |str_start[s]≤j<str_start[s+1]|. Additional integer variables | |
--- | |
> string number |s| comprises the characters |str_pool[j]| for | |
> |str_start[s]<=j<str_start[s+1]|. Additional integer variables | |
932,933c1022,1023 | |
< String numbers 0 to 127 are reserved for strings that correspond to single | |
< ascii characters. This is in accordance with the conventions of \.{WEB}, | |
--- | |
> String numbers 0 to 255 are reserved for strings that correspond to single | |
> ASCII characters. This is in accordance with the conventions of \.{WEB}, | |
935c1025 | |
< which converts single-character strings into the ascii code number of the | |
--- | |
> which converts single-character strings into the ASCII code number of the | |
939,941c1029,1031 | |
< ascii code for a period, while \.{WEB} will convert a string like \.{"hello"} | |
< into some integer greater than@@127. String number 46 will presumably be the | |
< single character `\..'; but some ascii codes have no standard visible | |
--- | |
> ASCII code for a period, while \.{WEB} will convert a string like \.{"hello"} | |
> into some integer greater than~255. String number 46 will presumably be the | |
> single character `\..'; but some ASCII codes have no standard visible | |
943,944c1033,1044 | |
< ascii character, so the first 128 strings are used to specify exactly what | |
< should be printed for each of the 128 possibilities. | |
--- | |
> ASCII character, so the first 256 strings are used to specify exactly what | |
> should be printed for each of the 256 possibilities. | |
> | |
> Elements of the |str_pool| array must be ASCII codes that can actually | |
> be printed; i.e., they must have an |xchr| equivalent in the local | |
> character set. (This restriction applies only to preloaded strings, | |
> not to those generated dynamically by the user.) | |
> | |
> Some \PASCAL\ compilers won't pack integers into a single byte unless the | |
> integers lie in the range |-128..127|. To accommodate such systems | |
> we access the string pool only via macros that can easily be redefined. | |
> @^system dependencies@> | |
946,948c1046,1047 | |
< 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. | |
--- | |
> @d si(#) == # {convert from |ASCII_code| to |packed_ASCII_code|} | |
> @d so(#) == # {convert from |packed_ASCII_code| to |ASCII_code|} | |
952a1052 | |
> @!packed_ASCII_code = 0..255; {elements of |str_pool| array} | |
954,955c1054,1055 | |
< @ @<Globals...@>= | |
< @!str_pool:packed array[pool_pointer] of ascii_code; {the characters} | |
--- | |
> @ @<Glob...@>= | |
> @!str_pool:packed array[pool_pointer] of packed_ASCII_code; {the characters} | |
958c1058,1060 | |
< @!str_ptr : str_number; {start of the current string being created} | |
--- | |
> @!str_ptr : str_number; {number of the current string being created} | |
> @!init_pool_ptr : pool_pointer; {the starting value of |pool_ptr|} | |
> @!init_str_ptr : str_number; {the starting value of |str_ptr|} | |
961c1063 | |
< macros instead of using \PASCAL\ procedures, because many of the | |
--- | |
> macros instead of \PASCAL\ procedures, because many of the | |
968c1070 | |
< in string number \#} | |
--- | |
> in string number \#} | |
975c1077 | |
< The macro called |append_char|, defined here, does not check to see if the | |
--- | |
> The |append_char| macro, defined here, does not check to see if the | |
984,985c1086,1087 | |
< @d append_char(#) == {put |ascii_code| \#\ at the end of |str_pool|} | |
< begin str_pool[pool_ptr]←#; incr(pool_ptr); | |
--- | |
> @d append_char(#) == {put |ASCII_code| \# at the end of |str_pool|} | |
> begin str_pool[pool_ptr]:=si(#); incr(pool_ptr); | |
988,990c1090,1094 | |
< @d str_room(#) == begin if pool_ptr+# > pool_size then | |
< overflow("pool size",pool_size); | |
< end | |
--- | |
> @d str_room(#) == {make sure that the pool hasn't overflowed} | |
> begin if pool_ptr+# > pool_size then | |
> overflow("pool size",pool_size-init_pool_ptr); | |
> @:TeX capacity exceeded pool size}{\quad pool size@> | |
> end | |
999,1001c1103,1106 | |
< overflow("number of strings",max_strings); | |
< incr(str_ptr); str_start[str_ptr]←pool_ptr; | |
< make_string←str_ptr-1; | |
--- | |
> overflow("number of strings",max_strings-init_str_ptr); | |
> @:TeX capacity exceeded number of strings}{\quad number of strings@> | |
> incr(str_ptr); str_start[str_ptr]:=pool_ptr; | |
> make_string:=str_ptr-1; | |
1006,1007c1111,1112 | |
< @d flush_string==begin decr(str_ptr); pool_ptr←str_start[str_ptr]; | |
< end | |
--- | |
> @d flush_string==begin decr(str_ptr); pool_ptr:=str_start[str_ptr]; | |
> end | |
1011a1117,1118 | |
> Empirical tests indicate that |str_eq_buf| is used in such a way that | |
> it tends to return |true| about 80 percent of the time. | |
1014c1121 | |
< {test equality of strings} | |
--- | |
> {test equality of strings} | |
1018c1125 | |
< begin j←str_start[s]; result←false; | |
--- | |
> begin j:=str_start[s]; | |
1020,1024c1127,1133 | |
< begin if str_pool[j]≠buffer[k] then goto not_found; | |
< incr(j); incr(k); | |
< end; | |
< result←true; | |
< not_found: str_eq_buf←result; | |
--- | |
> begin if so(str_pool[j])<>buffer[k] then | |
> begin result:=false; goto not_found; | |
> end; | |
> incr(j); incr(k); | |
> end; | |
> result:=true; | |
> not_found: str_eq_buf:=result; | |
1031c1140 | |
< {test equality of strings} | |
--- | |
> {test equality of strings} | |
1035,1037c1144,1146 | |
< begin result←false; | |
< if length(s)≠length(t) then goto not_found; | |
< j←str_start[s]; k←str_start[t]; | |
--- | |
> begin result:=false; | |
> if length(s)<>length(t) then goto not_found; | |
> j:=str_start[s]; k:=str_start[t]; | |
1039,1043c1148,1152 | |
< begin if str_pool[j]≠str_pool[k] then goto not_found; | |
< incr(j); incr(k); | |
< end; | |
< result←true; | |
< not_found: str_eq_str←result; | |
--- | |
> begin if str_pool[j]<>str_pool[k] then goto not_found; | |
> incr(j); incr(k); | |
> end; | |
> result:=true; | |
> not_found: str_eq_str:=result; | |
1052,1053c1161,1162 | |
< @p init function init_strings:boolean; {initializes the string pool, but | |
< returns |false| if something goes wrong} | |
--- | |
> @p @!init function get_strings_started:boolean; {initializes the string pool, | |
> but returns |false| if something goes wrong} | |
1055c1164 | |
< var k,@!l:0..127; {small indices or counters} | |
--- | |
> var k,@!l:0..255; {small indices or counters} | |
1059,1061c1168,1170 | |
< @!c:boolean; {check sum has checked} | |
< begin pool_ptr←0; str_ptr←0; | |
< @<Make the first 128 strings@>; | |
--- | |
> @!c:boolean; {check sum has been checked} | |
> begin pool_ptr:=0; str_ptr:=0; str_start[0]:=0; | |
> @<Make the first 256 strings@>; | |
1063c1172 | |
< or give an error message and return |false|@>; | |
--- | |
> or give an error message and return |false|@>; | |
1067,1079c1176,1190 | |
< @ @<Make the first 128...@>= | |
< for k←0 to 127 do | |
< begin if (k<" ")∧(@<Character |k| cannot be printed@>) then | |
< begin append_char("^"); append_char("^"); | |
< append_char(k+@'100); | |
< end | |
< else if k=127 then | |
< begin append_char("^"); append_char("^"); | |
< append_char("?"); | |
< end | |
< else append_char(k); | |
< g←make_string; | |
< end | |
--- | |
> @ @d app_lc_hex(#)==l:=#; | |
> if l<10 then append_char(l+"0")@+else append_char(l-10+"a") | |
> | |
> @<Make the first 256...@>= | |
> for k:=0 to 255 do | |
> begin if (@<Character |k| cannot be printed@>) then | |
> begin append_char("^"); append_char("^"); | |
> if k<@'100 then append_char(k+@'100) | |
> else if k<@'200 then append_char(k-@'100) | |
> else begin app_lc_hex(k div 16); app_lc_hex(k mod 16); | |
> end; | |
> end | |
> else append_char(k); | |
> g:=make_string; | |
> end | |
1081c1192 | |
< @ The first 128 strings will contain 95 standard ascii characters, and the | |
--- | |
> @ The first 128 strings will contain 95 standard ASCII characters, and the | |
1084c1195 | |
< an extended character set, where for example |xchr[@'32]=@t\.{\'\NE\'}@>|, | |
--- | |
> an extended character set, where for example |xchr[@'32]=@t\.{\'^^Z\'}@>|, | |
1092,1096c1203,1215 | |
< The boolean expression defined here should be |true| unless \TeX\ internal code | |
< number@@$k$ corresponds to a non-troublesome visible symbol in the local | |
< char\-ac\-ter set, given that |k<@'40|. | |
< At MIT, for example, the appropriate formula would be | |
< `|k in [0,@'10..@'12,@'14,@'15,@'33]|'. | |
--- | |
> Unprintable characters of codes 128--255 are, similarly, rendered | |
> \.{\^\^80}--\.{\^\^ff}. | |
> | |
> The boolean expression defined here should be |true| unless \TeX\ | |
> internal code number~|k| corresponds to a non-troublesome visible | |
> symbol in the local character set. An appropriate formula for the | |
> extended character set recommended in {\sl The \TeX book\/} would, for | |
> example, be `|k in [0,@'10..@'12,@'14,@'15,@'33,@'177..@'377]|'. | |
> If character |k| cannot be printed, and |k<@'200|, then character |k+@'100| or | |
> |k-@'100| must be printable; moreover, ASCII codes |[@'41..@'46, | |
> @'60..@'71, @'136, @'141..@'146, @'160..@'171]| must be printable. | |
> Thus, at least 81 printable characters are needed. | |
> @:TeXbook}{\sl The \TeX book@> | |
1101c1220 | |
< true | |
--- | |
> (k<" ")or(k>"~") | |
1104c1223 | |
< de\-scription that you are now reading, it outputs the \PASCAL\ program | |
--- | |
> description that you are now reading, it outputs the \PASCAL\ program | |
1112c1231,1232 | |
< @!pool_file:alpha_file; {the string-pool file output by \.{TANGLE}} | |
--- | |
> @!init @!pool_file:alpha_file; {the string-pool file output by \.{TANGLE}} | |
> tini | |
1114,1115c1234,1236 | |
< @ @d bad_pool(#)==begin write_ln(term_out,#); init_strings←false; return; | |
< end | |
--- | |
> @ @d bad_pool(#)==begin wake_up_terminal; write_ln(term_out,#); | |
> a_close(pool_file); get_strings_started:=false; return; | |
> end | |
1117c1238 | |
< name_of_file←pool_name; {we needn't set |name_length|} | |
--- | |
> name_of_file:=pool_name; {we needn't set |name_length|} | |
1119,1125c1240,1246 | |
< begin c←false; | |
< repeat @<Read one string, but return |false| if the | |
< string memory space is getting too tight for comfort@>; | |
< until c; | |
< init_strings←true; | |
< end | |
< else bad_pool('! I can''t read TEX.POOL.') | |
--- | |
> begin c:=false; | |
> repeat @<Read one string, but return |false| if the | |
> string memory space is getting too tight for comfort@>; | |
> until c; | |
> a_close(pool_file); get_strings_started:=true; | |
> end | |
> else bad_pool('! I can''t read TEX.POOL.') | |
1133,1135c1254,1256 | |
< else begin if (xord[m]<"0")∨(xord[m]>"9")∨@| | |
< (xord[n]<"0")∨(xord[n]>"9") then | |
< bad_pool('! TEX.POOL line doesn''t begin with two digits.'); | |
--- | |
> else begin if (xord[m]<"0")or(xord[m]>"9")or@| | |
> (xord[n]<"0")or(xord[n]>"9") then | |
> bad_pool('! TEX.POOL line doesn''t begin with two digits.'); | |
1137,1139c1258,1260 | |
< l←xord[m]*10+xord[n]-"0"*11; {compute the length} | |
< if pool_ptr+l+string_vacancies>pool_size then | |
< bad_pool('! You have to increase POOLSIZE.'); | |
--- | |
> l:=xord[m]*10+xord[n]-"0"*11; {compute the length} | |
> if pool_ptr+l+string_vacancies>pool_size then | |
> bad_pool('! You have to increase POOLSIZE.'); | |
1141,1147c1262,1267 | |
< for k←1 to l do | |
< begin if eoln(pool_file) then bad_pool('! TEX.POOL line too short.'); | |
< @.TEX.POOL line too short@> | |
< read(pool_file,m); append_char(xord[m]); | |
< end; | |
< read_ln(pool_file); g←make_string; | |
< end; | |
--- | |
> for k:=1 to l do | |
> begin if eoln(pool_file) then m:=' '@+else read(pool_file,m); | |
> append_char(xord[m]); | |
> end; | |
> read_ln(pool_file); g:=make_string; | |
> end; | |
1150c1270 | |
< @ The \.{WEB} operation \.{\at\$} denotes the value that should be at the | |
--- | |
> @ The \.{WEB} operation \.{@@\$} denotes the value that should be at the | |
1156,1158c1276,1278 | |
< begin a←0; k←1; | |
< loop@+ begin if (xord[n]<"0")∨(xord[n]>"9") then | |
< bad_pool('! TEX.POOL check sum doesn''t have nine digits.'); | |
--- | |
> begin a:=0; k:=1; | |
> loop@+ begin if (xord[n]<"0")or(xord[n]>"9") then | |
> bad_pool('! TEX.POOL check sum doesn''t have nine digits.'); | |
1160,1164c1280,1284 | |
< a←10*a+xord[n]-"0"; | |
< if k=9 then goto done; | |
< incr(k); read(pool_file,n); | |
< end; | |
< done: if a≠@$ then bad_pool('! TEX.POOL doesn''t match; TANGLE me again.'); | |
--- | |
> a:=10*a+xord[n]-"0"; | |
> if k=9 then goto done; | |
> incr(k); read(pool_file,n); | |
> end; | |
> done: if a<>@$ then bad_pool('! TEX.POOL doesn''t match; TANGLE me again.'); | |
1166c1286 | |
< c←true; | |
--- | |
> c:=true; | |
1167a1288 | |
> | |
1169c1290 | |
< Messages that are sent to a user's terminal and to the error-transcript file | |
--- | |
> Messages that are sent to a user's terminal and to the transcript-log file | |
1176,1177c1297,1298 | |
< \hang |term_and_err|, the normal setting, prints on the terminal and on the | |
< error-transcript file. | |
--- | |
> \hang |term_and_log|, the normal setting, prints on the terminal and on the | |
> transcript file. | |
1179c1300 | |
< \hang |err_only|, prints only on the error-transcript file. | |
--- | |
> \hang |log_only|, prints only on the transcript file. | |
1184c1305 | |
< before the error-transcript file is open. | |
--- | |
> before the transcript file is open. | |
1186,1188c1307,1309 | |
< \hang |pseudo|, puts output into a cyclic buffer that is used | |
< by the |show_context| routine; see that routine for the | |
< reasoning behind this curious mode. | |
--- | |
> \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. | |
1191c1312 | |
< string pool. | |
--- | |
> string pool. | |
1193c1314 | |
< \hang 0 to 15, prints on one of the sixteen files for \.{\\send} output. | |
--- | |
> \hang 0 to 15, prints on one of the sixteen files for \.{\\write} output. | |
1196c1317 | |
< \noindent The symbolic names `|term_and_err|', etc., have been assigned | |
--- | |
> \noindent The symbolic names `|term_and_log|', etc., have been assigned | |
1198c1319 | |
< |no_print+2=err_only|, |term_only+2=err_only+1=term_and_err|. | |
--- | |
> |no_print+2=log_only|, |term_only+2=log_only+1=term_and_log|. | |
1200,1205c1321,1327 | |
< Two additional global variables, |tally| and |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; |offset|, on the other | |
< hand, keeps track of how many characters have appeared so far on the current | |
< line of text output. | |
--- | |
> 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. | |
1209,1210c1331,1332 | |
< @d err_only=18 {printing is destined for the transcript file only} | |
< @d term_and_err=19 {normal |selector| setting} | |
--- | |
> @d log_only=18 {printing is destined for the transcript file only} | |
> @d term_and_log=19 {normal |selector| setting} | |
1215,1216c1337,1338 | |
< @<Globals...@>= | |
< @!err_file : alpha_file; {transcript of \TeX\ session} | |
--- | |
> @<Glob...@>= | |
> @!log_file : alpha_file; {transcript of \TeX\ session} | |
1218c1340 | |
< @!dig : array[0..22] of 0..9; {digits in a number being output} | |
--- | |
> @!dig : array[0..22] of 0..15; {digits in a number being output} | |
1220,1222c1342,1347 | |
< @!offset : 0..max_print_line; {the number of characters on the current line} | |
< @!trick_buf:array[0..error_line] of ascii_code; {circular buffer for | |
< pseudoprinting} | |
--- | |
> @!term_offset : 0..max_print_line; | |
> {the number of characters on the current terminal line} | |
> @!file_offset : 0..max_print_line; | |
> {the number of characters on the current file line} | |
> @!trick_buf:array[0..error_line] of ASCII_code; {circular buffer for | |
> pseudoprinting} | |
1227c1352,1365 | |
< selector←term_only; tally←0; offset←0; | |
--- | |
> selector:=term_only; tally:=0; term_offset:=0; file_offset:=0; | |
> | |
> @ Macro abbreviations for output to the terminal and to the log file are | |
> defined here for convenience. Some systems need special conventions | |
> for terminal output, and it is possible to adhere to those conventions | |
> by changing |wterm|, |wterm_ln|, and |wterm_cr| in this section. | |
> @^system dependencies@> | |
> | |
> @d wterm(#)==write(term_out,#) | |
> @d wterm_ln(#)==write_ln(term_out,#) | |
> @d wterm_cr==write_ln(term_out) | |
> @d wlog(#)==write(log_file,#) | |
> @d wlog_ln(#)==write_ln(log_file,#) | |
> @d wlog_cr==write_ln(log_file) | |
1233d1370 | |
< label exit; | |
1235,1241c1372,1380 | |
< term_and_err: begin write_ln(term_out); write_ln(err_file); | |
< end; | |
< err_only: write_ln(err_file); | |
< term_only: write_ln(term_out); | |
< no_print: do_nothing; | |
< pseudo,new_string: return; | |
< othercases write_ln(send_file[selector]) | |
--- | |
> term_and_log: begin wterm_cr; wlog_cr; | |
> term_offset:=0; file_offset:=0; | |
> end; | |
> log_only: begin wlog_cr; file_offset:=0; | |
> end; | |
> term_only: begin wterm_cr; term_offset:=0; | |
> end; | |
> no_print,pseudo,new_string: do_nothing; | |
> othercases write_ln(write_file[selector]) | |
1243,1244c1382 | |
< offset←0; {|tally| is not affected} | |
< exit:end; | |
--- | |
> end; {|tally| is not affected} | |
1250,1251d1387 | |
< @d preserve_offset=90 {go here when |offset| is not to be changed} | |
< | |
1253,1258c1389,1410 | |
< procedure print_char(@!c:ascii_code); {prints a single character} | |
< label preserve_offset; | |
< begin case selector of | |
< term_and_err: begin write(term_out,xchr[c]); write(err_file,xchr[c]); end; | |
< err_only: write(err_file,xchr[c]); | |
< term_only: write(term_out,xchr[c]); | |
--- | |
> procedure print_char(@!s:ASCII_code); {prints a single character} | |
> label exit; | |
> begin if @<Character |s| is the current new-line character@> then | |
> if selector<pseudo then | |
> begin print_ln; return; | |
> end; | |
> case selector of | |
> term_and_log: begin wterm(xchr[s]); wlog(xchr[s]); | |
> incr(term_offset); incr(file_offset); | |
> if term_offset=max_print_line then | |
> begin wterm_cr; term_offset:=0; | |
> end; | |
> if file_offset=max_print_line then | |
> begin wlog_cr; file_offset:=0; | |
> end; | |
> end; | |
> log_only: begin wlog(xchr[s]); incr(file_offset); | |
> if file_offset=max_print_line then print_ln; | |
> end; | |
> term_only: begin wterm(xchr[s]); incr(term_offset); | |
> if term_offset=max_print_line then print_ln; | |
> end; | |
1260,1268c1412,1415 | |
< pseudo: begin if tally<trick_count then | |
< trick_buf[tally mod error_line]←c; | |
< goto preserve_offset; | |
< end; | |
< new_string: begin if pool_ptr<pool_size then append_char(c); | |
< goto preserve_offset; {drop characters if the string space is full} | |
< end; | |
< othercases begin write(send_file[selector],xchr[c]); goto preserve_offset; | |
< end | |
--- | |
> pseudo: if tally<trick_count then trick_buf[tally mod error_line]:=s; | |
> new_string: begin if pool_ptr<pool_size then append_char(s); | |
> end; {we drop characters if the string space is full} | |
> othercases write(write_file[selector],xchr[s]) | |
1270,1273c1417,1418 | |
< incr(offset); | |
< if offset=max_print_line then print_ln; | |
< preserve_offset:incr(tally); | |
< end; | |
--- | |
> incr(tally); | |
> exit:end; | |
1276c1421 | |
< the single standard ascii character \.c, we could call |print("c")|, since | |
--- | |
> the single standard ASCII character \.c, we could call |print("c")|, since | |
1279c1424,1426 | |
< routine when it knows that this is safe. | |
--- | |
> routine when it knows that this is safe. (The present implementation | |
> assumes that it is always safe to print a visible ASCII character.) | |
> @^system dependencies@> | |
1282a1430 | |
> label exit; | |
1284,1285c1432,1452 | |
< begin if (s<0)∨(s≥str_ptr) then s←0; {this can't happen} | |
< j←str_start[s]; | |
--- | |
> @!nl:integer; {new-line character to restore} | |
> begin if s>=str_ptr then s:="???" {this can't happen} | |
> @.???@> | |
> else if s<256 then | |
> if s<0 then s:="???" {can't happen} | |
> else begin if selector>pseudo then | |
> begin print_char(s); return; {internal strings are not expanded} | |
> end; | |
> if (@<Character |s| is the current new-line character@>) then | |
> if selector<pseudo then | |
> begin print_ln; return; | |
> end; | |
> nl:=new_line_char; new_line_char:=-1; | |
> {temporarily disable new-line character} | |
> j:=str_start[s]; | |
> while j<str_start[s+1] do | |
> begin print_char(so(str_pool[j])); incr(j); | |
> end; | |
> new_line_char:=nl; return; | |
> end; | |
> j:=str_start[s]; | |
1287,1288c1454,1470 | |
< begin print_char(str_pool[j]); incr(j); | |
< end; | |
--- | |
> begin print_char(so(str_pool[j])); incr(j); | |
> end; | |
> exit:end; | |
> | |
> @ Control sequence names, file names, and strings constructed with | |
> \.{\\string} might contain |ASCII_code| values that can't | |
> be printed using |print_char|. Therefore we use |slow_print| for them: | |
> | |
> @<Basic print...@>= | |
> procedure slow_print(@!s:integer); {prints string |s|} | |
> var j:pool_pointer; {current character code position} | |
> begin if (s>=str_ptr) or (s<256) then print(s) | |
> else begin j:=str_start[s]; | |
> while j<str_start[s+1] do | |
> begin print(so(str_pool[j])); incr(j); | |
> end; | |
> end; | |
1292c1474 | |
< the version number and format package. The |offset| variable is temporarily | |
--- | |
> the version number and format package. The |term_offset| variable is temporarily | |
1298,1301c1480,1484 | |
< write(term_out,banner); | |
< if format_ident=0 then write_ln(term_out,' (no format preloaded)') | |
< else begin print(format_ident); print_ln; | |
< end; | |
--- | |
> wterm(banner); | |
> if format_ident=0 then wterm_ln(' (no format preloaded)') | |
> else begin slow_print(format_ident); print_ln; | |
> end; | |
> update_terminal; | |
1308c1491,1492 | |
< begin if offset>0 then print_ln; | |
--- | |
> begin if ((term_offset>0)and(odd(selector)))or@| | |
> ((file_offset>0)and(selector>=log_only)) then print_ln; | |
1313c1497 | |
< a backslash. | |
--- | |
> the user's escape character (which is usually a backslash). | |
1317c1501,1504 | |
< begin print_char("\"); print(s); | |
--- | |
> var c:integer; {the escape character code} | |
> begin @<Set variable |c| to the current escape character@>; | |
> if c>=0 then if c<256 then print(c); | |
> slow_print(s); | |
1320c1507 | |
< @ An array of digits is printed by |print_digs|. | |
--- | |
> @ An array of digits in the range |0..15| is printed by |print_the_digs|. | |
1323c1510,1511 | |
< procedure print_digs(@!k:eight_bits); {prints |dig[k-1]|$\ldotsm$|dig[0]|} | |
--- | |
> procedure print_the_digs(@!k:eight_bits); | |
> {prints |dig[k-1]|$\,\ldots\,$|dig[0]|} | |
1325,1326c1513,1516 | |
< begin decr(k); print_char("0"+dig[k]); | |
< end; | |
--- | |
> begin decr(k); | |
> if dig[k]<10 then print_char("0"+dig[k]) | |
> else print_char("A"-10+dig[k]); | |
> end; | |
1337,1339c1527,1529 | |
< var k:0..20; {index to current digit; we assume that $|n|<10^{20}$} | |
< @!m:nonnegative_integer; {used to negate |n| in possibly dangerous cases} | |
< begin k←0; | |
--- | |
> var k:0..23; {index to current digit; we assume that $|n|<10^{23}$} | |
> @!m:integer; {used to negate |n| in possibly dangerous cases} | |
> begin k:=0; | |
1341,1349c1531,1539 | |
< begin print_char("-"); | |
< if n>-100000000 then n←-n | |
< else begin m←-1-n; n←m div 10; m←(m mod 10)+1; k←1; | |
< if m<10 then dig[0]←m | |
< else begin dig[0]←0; n←n+1; | |
< end; | |
< end; | |
< end; | |
< repeat dig[k]←n mod 10; n←n div 10; incr(k); | |
--- | |
> begin print_char("-"); | |
> if n>-100000000 then negate(n) | |
> else begin m:=-1-n; n:=m div 10; m:=(m mod 10)+1; k:=1; | |
> if m<10 then dig[0]:=m | |
> else begin dig[0]:=0; incr(n); | |
> end; | |
> end; | |
> end; | |
> repeat dig[k]:=n mod 10; n:=n div 10; incr(k); | |
1351c1541 | |
< print_digs(k); | |
--- | |
> print_the_digs(k); | |
1354c1544,1545 | |
< @ Octal printing of nonnegative integers is accomplished by |print_octal|. | |
--- | |
> @ Here is a trivial procedure to print two digits; it is usually called with | |
> a parameter in the range |0<=n<=99|. | |
1356,1361c1547,1549 | |
< @p procedure print_octal(@!n:integer); {prints a positive integer in octal form} | |
< var k:0..22; {index to current digit; we assume that $0\L n<8^{22}$} | |
< begin k←0; print_char("'"); | |
< repeat dig[k]←n mod 8; n←n div 8; incr(k); | |
< until n=0; | |
< print_digs(k); | |
--- | |
> @p procedure print_two(@!n:integer); {prints two least significant digits} | |
> begin n:=abs(n) mod 100; print_char("0"+(n div 10)); | |
> print_char("0"+(n mod 10)); | |
1364,1365c1552 | |
< @ In certain situations, \TeX\ prints either a standard visible ascii | |
< character or its octal ascii code. | |
--- | |
> @ Hexadecimal printing of nonnegative integers is accomplished by |print_hex|. | |
1367,1371c1554,1560 | |
< @p procedure print_ascii(@!c:integer); {prints a character or its code} | |
< begin if (c>" ") and (c≤"~") then print_char(c) | |
< else begin if c<0 then print_char("-"); | |
< print_octal(abs(c)); print_char(" "); | |
< end; | |
--- | |
> @p procedure print_hex(@!n:integer); | |
> {prints a positive integer in hexadecimal form} | |
> var k:0..22; {index to current digit; we assume that $0\L n<16^{22}$} | |
> begin k:=0; print_char(""""); | |
> repeat dig[k]:=n mod 16; n:=n div 16; incr(k); | |
> until n=0; | |
> print_the_digs(k); | |
1374,1377c1563,1572 | |
< @ Roman numerals are produced by the |print_roman_int| routine, whose | |
< argument should be a positive integer. Readers who like puzzles might enjoy | |
< trying to figure out how this tricky code works; therefore no explanation | |
< will be given. | |
--- | |
> @ Old versions of \TeX\ needed a procedure called |print_ASCII| whose function | |
> is now subsumed by |print|. We retain the old name here as a possible aid to | |
> future software arch\ae ologists. | |
> | |
> @d print_ASCII == print | |
> | |
> @ Roman numerals are produced by the |print_roman_int| routine. Readers | |
> who like puzzles might enjoy trying to figure out how this tricky code | |
> works; therefore no explanation will be given. Notice that 1990 yields | |
> \.{mcmxc}, not \.{mxm}. | |
1379c1574 | |
< @p procedure print_roman_int(@!n:nonnegative_integer); | |
--- | |
> @p procedure print_roman_int(@!n:integer); | |
1383,1397c1578,1592 | |
< begin j←str_start["m2d5c2l5x2v5i"]; v←1000; | |
< loop@+ begin while n≥v do | |
< begin print_char(str_pool[j]); n←n-v; | |
< end; | |
< if n=0 then return; | |
< k←j+2; u←v div (str_pool[k-1]-"0"); | |
< if str_pool[k-1]="2" then | |
< begin k←k+2; u←u div (str_pool[k-1]-"0"); | |
< end; | |
< if n+u≥v then | |
< begin print_char(str_pool[k]); n←n+u; | |
< end | |
< else begin j←j+2; v←v div (str_pool[j-1]-"0"); | |
< end; | |
< end; | |
--- | |
> begin j:=str_start["m2d5c2l5x2v5i"]; v:=1000; | |
> loop@+ begin while n>=v do | |
> begin print_char(so(str_pool[j])); n:=n-v; | |
> end; | |
> if n<=0 then return; {nonpositive input produces no output} | |
> k:=j+2; u:=v div (so(str_pool[k-1])-"0"); | |
> if str_pool[k-1]=si("2") then | |
> begin k:=k+2; u:=u div (so(str_pool[k-1])-"0"); | |
> end; | |
> if n+u>=v then | |
> begin print_char(so(str_pool[k])); n:=n+u; | |
> end | |
> else begin j:=j+2; v:=v div (so(str_pool[j-1])-"0"); | |
> end; | |
> end; | |
1405c1600 | |
< begin j←str_start[str_ptr]; | |
--- | |
> begin j:=str_start[str_ptr]; | |
1407,1408c1602,1603 | |
< begin print_char(str_pool[j]); incr(j); | |
< end; | |
--- | |
> begin print_char(so(str_pool[j])); incr(j); | |
> end; | |
1412c1607 | |
< assuming that the |selector| setting is either |term_only| or |term_and_err|. | |
--- | |
> assuming that the |selector| setting is either |term_only| or |term_and_log|. | |
1418,1419c1613,1614 | |
< @d prompt_input(#)==begin print(#); term_input; | |
< end {prints a string and gets a line of input} | |
--- | |
> @d prompt_input(#)==begin wake_up_terminal; print(#); term_input; | |
> end {prints a string and gets a line of input} | |
1423,1425c1618,1621 | |
< begin update_terminal; {Now the user sees the prompt for sure} | |
< if not input_ln(term_in) then fatal_error("! End of file on the terminal"); | |
< @.End of file on the terminal...@> | |
--- | |
> begin update_terminal; {now the user sees the prompt for sure} | |
> if not input_ln(term_in,true) then fatal_error("End of file on the terminal!"); | |
> @.End of file on the terminal@> | |
> term_offset:=0; {the user's line ended with \<\rm return>} | |
1427,1428c1623,1624 | |
< if last≠first then for k←first to last-1 do print(buffer[k]); | |
< print_ln; incr(selector); {restore previous status, with |offset=0|} | |
--- | |
> if last<>first then for k:=first to last-1 do print(buffer[k]); | |
> print_ln; incr(selector); {restore previous status} | |
1429a1626 | |
> | |
1433c1630 | |
< |print_nl("! Something anomalous has been detected");|\cr | |
--- | |
> |print_err("Something anomalous has been detected");|\cr | |
1440c1637 | |
< official error message that was printed. (Outside of the U.S.A., the help | |
--- | |
> official error message that was printed. (Outside the U.S.A., the help | |
1444a1642,1643 | |
> 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. | |
1457a1657,1659 | |
> @d print_err(#)==begin if interaction=error_stop_mode then wake_up_terminal; | |
> print_nl("! "); print(#); | |
> end | |
1462c1664 | |
< @ @<Set init...@>=interaction←error_stop_mode; | |
--- | |
> @ @<Set init...@>=interaction:=error_stop_mode; | |
1469c1671 | |
< and |err_file| not yet open); | |
--- | |
> and |log_file| not yet open); | |
1471c1673 | |
< \hang|term_only| (when |interaction>batch_mode| and |err_file| not yet open); | |
--- | |
> \hang|term_only| (when |interaction>batch_mode| and |log_file| not yet open); | |
1473c1675 | |
< \hang|err_only| (when |interaction=batch_mode| and |err_file| is open); | |
--- | |
> \hang|log_only| (when |interaction=batch_mode| and |log_file| is open); | |
1475c1677 | |
< \hang|term_and_err| (when |interaction>batch_mode| and |err_file| is open). | |
--- | |
> \hang|term_and_log| (when |interaction>batch_mode| and |log_file| is open). | |
1478c1680 | |
< if interaction=batch_mode then selector←no_print@+else selector←term_only | |
--- | |
> if interaction=batch_mode then selector:=no_print@+else selector:=term_only | |
1482a1685 | |
> A similar interlock is provided by |set_box_allowed|. | |
1485,1486c1688,1690 | |
< The global variable |spotless| is set to false when the first error | |
< has been detected. | |
--- | |
> 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|. | |
1492a1697,1701 | |
> @d spotless=0 {|history| value when nothing has been amiss yet} | |
> @d warning_issued=1 {|history| value when |begin_diagnostic| has been called} | |
> @d error_message_issued=2 {|history| value when |error| has been called} | |
> @d fatal_error_stop=3 {|history| value when termination was premature} | |
> | |
1495c1704,1705 | |
< @!spotless:boolean; {has the source input been clean so far?} | |
--- | |
> @!set_box_allowed:boolean; {is it safe to do a \.{\\setbox} assignment?} | |
> @!history:spotless..fatal_error_stop; {has the source input been clean so far?} | |
1497c1707 | |
< last paragraph ended} | |
--- | |
> last paragraph ended} | |
1499,1500c1709,1714 | |
< @ @<Set init...@>= | |
< deletions_allowed←true; spotless←true; error_count←0; | |
--- | |
> @ The value of |history| is initially |fatal_error_stop|, but it will | |
> be changed to |spotless| if \TeX\ survives the initialization process. | |
> | |
> @<Set init...@>= | |
> deletions_allowed:=true; set_box_allowed:=true; | |
> error_count:=0; {|history| is initialized elsewhere} | |
1508c1722 | |
< when |get_token| is being used to delete a token, or if some fatal error | |
--- | |
> when |get_token| is being used to delete a token, and/or if some fatal error | |
1511c1725 | |
< is never more than one level deep. | |
--- | |
> is never more than two levels deep. | |
1513a1728 | |
> procedure@?normalize_selector; forward;@t\2@>@/ | |
1517a1733 | |
> procedure@?open_log_file; forward;@t\2@>@/ | |
1520c1736,1738 | |
< @t\4@>@;@+debug@+procedure@?debug_help; forward;@;@+gubed | |
--- | |
> procedure@?give_err_help; forward;@t\2@>@/ | |
> @t\4\hskip-\fontdimen2\font@>@;@+@!debug@+procedure@?debug_help; | |
> forward;@;@+gubed | |
1524c1742 | |
< in reverse order, i.e., with |help_line[0]| last. | |
--- | |
> in reverse order, i.e., with |help_line[0]| appearing last. | |
1526,1538c1744,1756 | |
< @d hlp1(#)==help_line[0]←#;@+end | |
< @d hlp2(#)==help_line[1]←#; hlp1 | |
< @d hlp3(#)==help_line[2]←#; hlp2 | |
< @d hlp4(#)==help_line[3]←#; hlp3 | |
< @d hlp5(#)==help_line[4]←#; hlp4 | |
< @d hlp6(#)==help_line[5]←#; hlp5 | |
< @d help0==help_ptr←0 {sometimes there might be no help} | |
< @d help1==@+begin help_ptr←1; hlp1 {use this with one help line} | |
< @d help2==@+begin help_ptr←2; hlp2 {use this with two help lines} | |
< @d help3==@+begin help_ptr←3; hlp3 {use this with three help lines} | |
< @d help4==@+begin help_ptr←4; hlp4 {use this with four help lines} | |
< @d help5==@+begin help_ptr←5; hlp5 {use this with five help lines} | |
< @d help6==@+begin help_ptr←6; hlp6 {use this with six help lines} | |
--- | |
> @d hlp1(#)==help_line[0]:=#;@+end | |
> @d hlp2(#)==help_line[1]:=#; hlp1 | |
> @d hlp3(#)==help_line[2]:=#; hlp2 | |
> @d hlp4(#)==help_line[3]:=#; hlp3 | |
> @d hlp5(#)==help_line[4]:=#; hlp4 | |
> @d hlp6(#)==help_line[5]:=#; hlp5 | |
> @d help0==help_ptr:=0 {sometimes there might be no help} | |
> @d help1==@+begin help_ptr:=1; hlp1 {use this with one help line} | |
> @d help2==@+begin help_ptr:=2; hlp2 {use this with two help lines} | |
> @d help3==@+begin help_ptr:=3; hlp3 {use this with three help lines} | |
> @d help4==@+begin help_ptr:=4; hlp4 {use this with four help lines} | |
> @d help5==@+begin help_ptr:=5; hlp5 {use this with five help lines} | |
> @d help6==@+begin help_ptr:=6; hlp6 {use this with six help lines} | |
1542a1761,1764 | |
> @!use_err_help:boolean; {should the |err_help| list be shown?} | |
> | |
> @ @<Set init...@>= | |
> help_ptr:=0; use_err_help:=false; | |
1544,1545c1766,1767 | |
< @ The |quit| procedure just cuts across all active procedure levels and jumps | |
< out to |end_of_TEX|. This is the only nonlocal |@!goto| statement in the | |
--- | |
> @ The |jump_out| procedure just cuts across all active procedure levels and | |
> goes to |end_of_TEX|. This is the only nontrivial |@!goto| statement in the | |
1550,1551c1772,1774 | |
< In such cases the body of |quit| should simply be `|close_files_and_terminate|;' | |
< followed by a call on some system procedure that quietly terminates the program. | |
--- | |
> 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. | |
1554c1777 | |
< procedure quit; | |
--- | |
> procedure jump_out; | |
1562,1565c1785,1790 | |
< label continue, exit; | |
< var c:ascii_code; {what the user types} | |
< @!s1,@!s2,@!s3:integer; {used to save global variables when deleting tokens} | |
< begin print_char("."); show_context; | |
--- | |
> label continue,exit; | |
> var c:ASCII_code; {what the user types} | |
> @!s1,@!s2,@!s3,@!s4:integer; | |
> {used to save global variables when deleting tokens} | |
> begin if history<error_message_issued then history:=error_message_issued; | |
> print_char("."); show_context; | |
1569c1794 | |
< begin print_nl("(That makes 100 errors; please try again.)"); | |
--- | |
> begin print_nl("(That makes 100 errors; please try again.)"); | |
1571,1572c1796,1797 | |
< quit; | |
< end; | |
--- | |
> history:=fatal_error_stop; jump_out; | |
> end; | |
1578,1582c1803,1808 | |
< if last=first then return; | |
< c←buffer[first]; | |
< if c≥"a" then c←c+"A"-"a"; {convert to upper case} | |
< @<Interpret code |c| and |return| if done@>; | |
< end | |
--- | |
> @.?\relax@> | |
> if last=first then return; | |
> c:=buffer[first]; | |
> if c>="a" then c:=c+"A"-"a"; {convert to uppercase} | |
> @<Interpret code |c| and |return| if done@>; | |
> end | |
1587,1591c1813,1815 | |
< wizardry, so it is not standard in \TeX\ and not included here except | |
< as a recommendation. (The name of the file to edit, if an `\.E' option is | |
< added, is |input_stack[base_ptr].name_field|, provided that |base_ptr>0|; | |
< the value of |base_ptr| has been set by |show_context|. | |
< No input files are open when |base_ptr=0|.) | |
--- | |
> wizardry, so the present implementation simply types out the name of the | |
> file that should be | |
> edited and the relevant line number. | |
1594,1595c1818,1819 | |
< There is a secret `\.D' option available when the debugging routines have | |
< not been commented out. | |
--- | |
> There is a secret `\.D' option available when the debugging routines haven't | |
> been commented~out. | |
1600,1603c1824,1834 | |
< "1","2","3","4","5","6","7","8","9": if deletions_allowed then | |
< @<Delete |c-"0"| tokens, |goto continue|@>; | |
< @t\4\4@>@;@+debug "D": begin debug_help; goto continue;@+end;@+gubed@/ | |
< "H": @<Print the help information, |goto continue|@>; | |
--- | |
> "0","1","2","3","4","5","6","7","8","9": if deletions_allowed then | |
> @<Delete \(c)|c-"0"| tokens and |goto continue|@>; | |
> @t\4\4@>@;@+@!debug "D": begin debug_help; goto continue;@+end;@+gubed@/ | |
> "E": if base_ptr>0 then | |
> begin print_nl("You want to edit file "); | |
> @.You want to edit file x@> | |
> slow_print(input_stack[base_ptr].name_field); | |
> print(" at line "); print_int(line); | |
> interaction:=scroll_mode; jump_out; | |
> end; | |
> "H": @<Print the help information and |goto continue|@>; | |
1606,1610c1837,1838 | |
< "X":begin prompt_input("Type X again to exit:"); | |
< if (last>first)∧((buffer[first]="x")∨(buffer[first]="X")) then | |
< begin interaction←scroll_mode; quit; | |
< end; | |
< end; | |
--- | |
> "X":begin interaction:=scroll_mode; jump_out; | |
> end; | |
1615,1620c1843,1845 | |
< @ The `\.E' option in the following menu | |
< should be taken out of braces if it is implemented. | |
< @^system dependencies@> | |
< | |
< @<Print the menu...@>= | |
< print("Type <return> to proceed, S to scroll future error messages,");@/ | |
--- | |
> @ @<Print the menu...@>= | |
> begin print("Type <return> to proceed, S to scroll future error messages,");@/ | |
> @.Type <return> to proceed...@> | |
1622,1623c1847,1848 | |
< print_nl("I to insert something, ");@/ | |
< @{@,@,@+if base_ptr>0 then print("E to edit your file,");@;@+@}@/ | |
--- | |
> print_nl("I to insert something, "); | |
> if base_ptr>0 then print("E to edit your file,"); | |
1625,1626c1850,1852 | |
< print_nl("1 or ... or 9 to ignore the next 1 to 9 tokens of input,"); | |
< print_nl("H for help, X to quit.") | |
--- | |
> print_nl("1 or ... or 9 to ignore the next 1 to 9 tokens of input,"); | |
> print_nl("H for help, X to quit."); | |
> end | |
1634,1636c1860,1868 | |
< begin error_count←0; interaction←batch_mode+c-"Q"; | |
< if c="Q" then decr(selector); | |
< print_ln; return; | |
--- | |
> begin error_count:=0; interaction:=batch_mode+c-"Q"; | |
> print("OK, entering "); | |
> case c of | |
> "Q":begin print_esc("batchmode"); decr(selector); | |
> end; | |
> "R":print_esc("nonstopmode"); | |
> "S":print_esc("scrollmode"); | |
> end; {there are no other cases} | |
> print("..."); print_ln; update_terminal; return; | |
1639,1642c1871,1874 | |
< @ When the following code is executed, the material inserted by the user | |
< may appear in |buffer[(first+1)..(last-1)]|; otherwise another prompt | |
< will be given. In order to fully understand this part of the program, | |
< you need to be familiar with \TeX's input stacks. | |
--- | |
> @ When the following code is executed, |buffer[(first+1)..(last-1)]| may | |
> contain the material inserted by the user; otherwise another prompt will | |
> be given. In order to understand this part of the program fully, you need | |
> to be familiar with \TeX's input stacks. | |
1646c1878 | |
< {now |state←mid_line|, so an initial blank space will count as a blank} | |
--- | |
> {now |state=mid_line|, so an initial blank space will count as a blank} | |
1648,1653c1880,1886 | |
< begin loc←first+1; buffer[first]←" "; | |
< end | |
< else begin prompt_input("**"); loc←first; | |
< end; | |
< first←last; | |
< cur_input.limit_field←last-1; {no |carriage_return| ends this line} | |
--- | |
> begin loc:=first+1; buffer[first]:=" "; | |
> end | |
> else begin prompt_input("insert>"); loc:=first; | |
> @.insert>@> | |
> end; | |
> first:=last; | |
> cur_input.limit_field:=last-1; {no |end_line_char| ends this line} | |
1659,1663c1892,1897 | |
< @<Delete |c-"0"| tokens...@>= | |
< begin s1←cur_tok; s2←cur_cmd; s3←cur_chr; OK_to_interrupt←false; | |
< if (last>first+1) and (buffer[first+1]≥"0")∧(buffer[first+1]≤"9") then | |
< c←c*10+buffer[first+1]-"0"*11 | |
< else c←c-"0"; | |
--- | |
> @<Delete \(c)|c-"0"| tokens...@>= | |
> begin s1:=cur_tok; s2:=cur_cmd; s3:=cur_chr; s4:=align_state; | |
> align_state:=1000000; OK_to_interrupt:=false; | |
> if (last>first+1) and (buffer[first+1]>="0")and(buffer[first+1]<="9") then | |
> c:=c*10+buffer[first+1]-"0"*11 | |
> else c:=c-"0"; | |
1665,1668c1899,1902 | |
< begin get_token; {one-level recursive call of |error| is possible} | |
< decr(c); | |
< end; | |
< cur_tok←s1; cur_cmd←s2; cur_chr←s3; OK_to_interrupt←true; | |
--- | |
> begin get_token; {one-level recursive call of |error| is possible} | |
> decr(c); | |
> end; | |
> cur_tok:=s1; cur_cmd:=s2; cur_chr:=s3; align_state:=s4; OK_to_interrupt:=true; | |
1675,1679c1909,1917 | |
< begin if help_ptr=0 then | |
< help2("Sorry, I don't know how to help in this situation.")@/ | |
< ("Maybe you should try asking a human?"); | |
< repeat decr(help_ptr); print(help_line[help_ptr]); print_ln; | |
< until help_ptr=0; | |
--- | |
> begin if use_err_help then | |
> begin give_err_help; use_err_help:=false; | |
> end | |
> else begin if help_ptr=0 then | |
> help2("Sorry, I don't know how to help in this situation.")@/ | |
> @t\kern1em@>("Maybe you should try asking a human?"); | |
> repeat decr(help_ptr); print(help_line[help_ptr]); print_ln; | |
> until help_ptr=0; | |
> end; | |
1681,1683c1919,1921 | |
< ("Maybe you should try asking a human?")@/ | |
< ("An error might have occurred before I noticed any problems.")@/ | |
< ("``If all else fails, read the instructions.''"); | |
--- | |
> ("Maybe you should try asking a human?")@/ | |
> ("An error might have occurred before I noticed any problems.")@/ | |
> ("``If all else fails, read the instructions.''");@/ | |
1689,1691c1927,1932 | |
< while help_ptr>0 do | |
< begin decr(help_ptr); print_nl(help_line[help_ptr]); | |
< end; | |
--- | |
> if use_err_help then | |
> begin print_ln; give_err_help; | |
> end | |
> else while help_ptr>0 do | |
> begin decr(help_ptr); print_nl(help_line[help_ptr]); | |
> end; | |
1693c1934 | |
< if interaction>batch_mode then incr(selector); {enable terminal output} | |
--- | |
> if interaction>batch_mode then incr(selector); {re-enable terminal output} | |
1702a1944,1954 | |
> @ In anomalous cases, the print selector might be in an unknown state; | |
> the following subroutine is called to fix things just enough to keep | |
> running a bit longer. | |
> | |
> @p procedure normalize_selector; | |
> begin if log_opened then selector:=term_and_log | |
> else selector:=term_only; | |
> if job_name=0 then open_log_file; | |
> if interaction=batch_mode then decr(selector); | |
> end; | |
> | |
1706,1708c1958,1962 | |
< interaction←scroll_mode; {no more interaction} | |
< error; quit; {irrecoverable error} | |
< end | |
--- | |
> interaction:=scroll_mode; {no more interaction} | |
> if log_opened then error; | |
> @!debug if interaction>batch_mode then debug_help;@+gubed@;@/ | |
> history:=fatal_error_stop; jump_out; {irrecoverable error} | |
> end | |
1712c1966,1967 | |
< begin print_nl("! Emergency stop"); help1(s); succumb; | |
--- | |
> begin normalize_selector;@/ | |
> print_err("Emergency stop"); help1(s); succumb; | |
1720,1722c1975,1978 | |
< begin print_nl("! TeX capacity exceeded, sorry ["); | |
< @.TeX capacity exceeded...@> | |
< print(s); print_char("="); print_int(n); print_char("]"); | |
--- | |
> begin normalize_selector; | |
> print_err("TeX capacity exceeded, sorry ["); | |
> @.TeX capacity exceeded ...@> | |
> print(s); print_char("="); print_int(n); print_char("]"); | |
1724c1980 | |
< ("you can ask a wizard to enlarge me."); | |
--- | |
> ("you can ask a wizard to enlarge me."); | |
1728,1730c1984,1989 | |
< @ The program might sometime run completely amok and print out the | |
< following message, which is really intended for the \TeX\ maintenance | |
< person instead of the user. | |
--- | |
> @ The program might sometime run completely amok, at which point there is | |
> no choice but to stop. If no previous error has been detected, that's bad | |
> news; a message is printed that is really intended for the \TeX\ | |
> maintenance person instead of the user (unless the user has been | |
> particularly diabolical). The index entries for `this can't happen' may | |
> help to pinpoint the problem. | |
1735,1737c1994,1997 | |
< {consistency check violated; |s| tells where} | |
< begin if spotless then | |
< begin print_nl("! This can't happen ("); print(s); print_char(")"); | |
--- | |
> {consistency check violated; |s| tells where} | |
> begin normalize_selector; | |
> if history<error_message_issued then | |
> begin print_err("This can't happen ("); print(s); print_char(")"); | |
1739,1741c1999,2001 | |
< help1("I'm broken. Please show this to someone who can fix can fix"); | |
< end | |
< else begin print_nl("! I can't go on meeting you like this"); | |
--- | |
> help1("I'm broken. Please show this to someone who can fix can fix"); | |
> end | |
> else begin print_err("I can't go on meeting you like this"); | |
1743,1745c2003,2005 | |
< help2("One of your earlier faux pas has wounded me deeply,")@/ | |
< ("so I'm barely conscious. Please fix it and try again."); | |
< end; | |
--- | |
> help2("One of your faux pas seems to have wounded me deeply...")@/ | |
> ("in fact, I'm barely conscious. Please fix it and try again."); | |
> end; | |
1757,1758c2017,2018 | |
< @d check_interrupt==begin if interrupt≠0 then pause_for_instructions; | |
< end | |
--- | |
> @d check_interrupt==begin if interrupt<>0 then pause_for_instructions; | |
> end | |
1761c2021 | |
< @!interrupt:integer; {should \TeX\ pause for instruction?} | |
--- | |
> @!interrupt:integer; {should \TeX\ pause for instructions?} | |
1765c2025 | |
< interrupt←0; OK_to_interrupt←true; | |
--- | |
> interrupt:=0; OK_to_interrupt:=true; | |
1767,1768c2027,2028 | |
< @ When an interrupt has been detected, the program comes goes into its | |
< highest interaction level and lets the user have the full flexibility of | |
--- | |
> @ When an interrupt has been detected, the program goes into its | |
> highest interaction level and lets the user have nearly the full flexibility of | |
1774,1777c2034,2037 | |
< begin interaction←error_stop_mode; | |
< if (selector=err_only)∨(selector=no_print) then | |
< incr(selector); | |
< print_nl("! Interruption"); | |
--- | |
> begin interaction:=error_stop_mode; | |
> if (selector=log_only)or(selector=no_print) then | |
> incr(selector); | |
> print_err("Interruption"); | |
1779,1784c2039,2044 | |
< help3("You rang?")@/ | |
< ("Try to insert some instructions for me (e.g.,`I\showlists'),")@/ | |
< ("unless you just want to quit by typing `X'."); | |
< deletions_allowed←false; error; deletions_allowed←true; | |
< interrupt←0; | |
< end; | |
--- | |
> help3("You rang?")@/ | |
> ("Try to insert some instructions for me (e.g.,`I\showlists'),")@/ | |
> ("unless you just want to quit by typing `X'."); | |
> deletions_allowed:=false; error; deletions_allowed:=true; | |
> interrupt:=0; | |
> end; | |
1785a2046 | |
> | |
1802c2063,2066 | |
< numerator. These are harmless; see |div| in the index.) | |
--- | |
> numerator. These are harmless; see |div| in the index. Also if the user | |
> sets the \.{\\time} or the \.{\\year} to a negative value, some diagnostic | |
> information will involve negative-numerator division. The same remarks | |
> apply for |mod| as well as for |div|.) | |
1808,1809c2072,2073 | |
< begin if odd(x) then half←(x+1) div 2 | |
< else half←x @!div 2; | |
--- | |
> begin if odd(x) then half:=(x+1) div 2 | |
> else half:=x @!div 2; | |
1824,1825c2088,2089 | |
< @ The following function is used to create a scaled integer from a decimal | |
< fraction $(.d↓0d↓1\ldotsm d↓{k-1})$, where |0≤k≤16|. The digit $d↓i$ is | |
--- | |
> @ The following function is used to create a scaled integer from a given decimal | |
> fraction $(.d_0d_1\ldots d_{k-1})$, where |0<=k<=17|. The digit $d_i$ is | |
1829c2093 | |
< {converts a decimal fraction} | |
--- | |
> {converts a decimal fraction} | |
1831c2095 | |
< begin a←0; | |
--- | |
> begin a:=0; | |
1833,1835c2097,2099 | |
< begin decr(k); a←(a+dig[k]*two) div 10; | |
< end; | |
< round_decimals←(a+1) div 2; | |
--- | |
> begin decr(k); a:=(a+dig[k]*two) div 10; | |
> end; | |
> round_decimals:=(a+1) div 2; | |
1841,1844c2105,2112 | |
< be reproduced exactly. [{\sl Proof:\/} If round$(x)=\lfloor | |
< x+{1\over2}\rfloor$ and if $\alpha<1$, it is not difficult to verify that | |
< round$(\alpha\,\hbox{round}( \alpha^{-1}n))=n$ for all integers $n$. In | |
< our case $\alpha=2^{16}/10^5$.] | |
--- | |
> be reproduced exactly; the ``simplest'' such decimal number is output, | |
> but there is always at least one digit following the decimal point. | |
> | |
> The invariant relation in the \&{repeat} loop is that a sequence of | |
> decimal digits yet to be printed will yield the original number if and only if | |
> they form a fraction~$f$ in the range $s-\delta\L10\cdot2^{16}f<s$. | |
> We can stop if and only if $f=0$ satisfies this condition; the loop will | |
> terminate before $s$ can possibly become zero. | |
1847,1848c2115,2116 | |
< digits} | |
< var k:0..4; {index to current digit of the fraction part} | |
--- | |
> digits} | |
> var delta:scaled; {amount of allowable inaccuracy} | |
1850,1851c2118,2119 | |
< begin print_char("-"); s←-s; {print the sign, if negative} | |
< end; | |
--- | |
> begin print_char("-"); negate(s); {print the sign, if negative} | |
> end; | |
1853,1854d2120 | |
< s←((s mod unity) * 3125 + 1024) div 2048; | |
< {now |0≤s<100000| is the fraction part} | |
1856,1857c2122,2125 | |
< repeat print_char("0"+(s div 10000)); s←10*(s mod 10000); | |
< until s=0; | |
--- | |
> s:=10*(s mod unity)+5; delta:=10; | |
> repeat if delta>unity then s:=s+@'100000-50000; {round the last digit} | |
> print_char("0"+(s div unity)); s:=10*(s mod unity); delta:=delta*10; | |
> until s<=delta; | |
1871c2139 | |
< @^Overflow in arithmetic@> | |
--- | |
> @^overflow in arithmetic@> | |
1873c2141 | |
< few dozen tests of the form `\!|if x≥@'10000000000 then | |
--- | |
> few dozen tests of the form `\ignorespaces|if x>=@'10000000000 then | |
1890c2158,2159 | |
< and@@|y| are |scaled| and |n| is an integer. | |
--- | |
> and~|y| are |scaled| and |n| is an integer. We will also use it to | |
> multiply integers. | |
1892c2161,2164 | |
< @p function nx_plus_y(@!n:integer;@!x,@!y:scaled):scaled; | |
--- | |
> @d nx_plus_y(#)==mult_and_add(#,@'7777777777) | |
> @d mult_integers(#)==mult_and_add(#,0,@'17777777777) | |
> | |
> @p function mult_and_add(@!n:integer;@!x,@!y,@!max_answer:scaled):scaled; | |
1894,1900c2166,2172 | |
< begin x←-x; n←-n; | |
< end; | |
< if n=0 then nx_plus_y←y | |
< else if ((x≤(@'7777777777-y) div n)∧(-x≤(@'7777777777+y) div n)) then | |
< nx_plus_y←n*x+y | |
< else begin arith_error←true; nx_plus_y←0; | |
< end; | |
--- | |
> begin negate(x); negate(n); | |
> end; | |
> if n=0 then mult_and_add:=y | |
> else if ((x<=(max_answer-y) div n)and(-x<=(max_answer+y) div n)) then | |
> mult_and_add:=n*x+y | |
> else begin arith_error:=true; mult_and_add:=0; | |
> end; | |
1906,1907c2178,2179 | |
< var negate:boolean; {should |remainder| be negated?} | |
< begin negate←false; | |
--- | |
> var negative:boolean; {should |remainder| be negated?} | |
> begin negative:=false; | |
1909,1920c2181,2192 | |
< begin arith_error←true; x_over_n←0; remainder←x; | |
< end | |
< else begin if n<0 then | |
< begin x←-x; n←-n; negate←true; | |
< end; | |
< if x≥0 then | |
< begin x_over_n←x div n; remainder←x mod n; | |
< end | |
< else begin x_over_n←-((-x) div n); remainder←-((-x) mod n); | |
< end; | |
< end; | |
< if negate then remainder←-remainder; | |
--- | |
> begin arith_error:=true; x_over_n:=0; remainder:=x; | |
> end | |
> else begin if n<0 then | |
> begin negate(x); negate(n); negative:=true; | |
> end; | |
> if x>=0 then | |
> begin x_over_n:=x div n; remainder:=x mod n; | |
> end | |
> else begin x_over_n:=-((-x) div n); remainder:=-((-x) mod n); | |
> end; | |
> end; | |
> if negative then negate(remainder); | |
1924,1926c2196,2198 | |
< where |n| and |d| are nonnegative integers |≤@t$2^{16}$@>| and |d| is | |
< positive. It would be too dangerous to multiply by@@|n| and then divide | |
< by@@|d|, in separate operations, since overflow might well occur; and it | |
--- | |
> where |n| and |d| are nonnegative integers |<=@t$2^{16}$@>| and |d| is | |
> positive. It would be too dangerous to multiply by~|n| and then divide | |
> by~|d|, in separate operations, since overflow might well occur; and it | |
1931c2203 | |
< var positive:boolean; {was |x≥0|?} | |
--- | |
> var positive:boolean; {was |x>=0|?} | |
1933,1940c2205,2212 | |
< begin if x≥0 then positive←true | |
< else begin x←-x; positive←false; | |
< end; | |
< t←(x mod @'100000)*n; | |
< u←(x div @'100000)*n+(t div @'100000); | |
< v←(u mod d)*@'100000 + (t mod @'100000); | |
< if u div d≥@'100000 then arith_error←true | |
< else u←@'100000*(u div d) + (v div d); | |
--- | |
> begin if x>=0 then positive:=true | |
> else begin negate(x); positive:=false; | |
> end; | |
> t:=(x mod @'100000)*n; | |
> u:=(x div @'100000)*n+(t div @'100000); | |
> v:=(u mod d)*@'100000 + (t mod @'100000); | |
> if u div d>=@'100000 then arith_error:=true | |
> else u:=@'100000*(u div d) + (v div d); | |
1942,1945c2214,2217 | |
< begin xn_over_d←u; remainder←v mod d; | |
< end | |
< else begin xn_over_d←-u; remainder←-(v mod d); | |
< end; | |
--- | |
> begin xn_over_d:=u; remainder:=v mod d; | |
> end | |
> else begin xn_over_d:=-u; remainder:=-(v mod d); | |
> end; | |
1949,1950c2221,2222 | |
< total@@|t| is supposed to be made from amounts that sum to@@|s|. According | |
< to the \TeX\ manual, the badness of this situation is $100(t/s)^3$; | |
--- | |
> total~|t| is supposed to be made from amounts that sum to~|s|. According | |
> to {\sl The \TeX book}, the badness of this situation is $100(t/s)^3$; | |
1953a2226 | |
> @:TeXbook}{\sl The \TeX book@> | |
1961,1962c2234,2235 | |
< It is not difficult to prove that $$\hbox{|badness(t+1,s)≥badness(t,s) | |
< ≥badness(t,s+1)|}$$. The badness function defined here is capable of | |
--- | |
> It is not difficult to prove that $$\hbox{|badness(t+1,s)>=badness(t,s) | |
> >=badness(t,s+1)|}.$$ The badness function defined here is capable of | |
1967c2240 | |
< @p function badness(@!t,@!s:scaled):halfword; {compute badness, given |t≥0|} | |
--- | |
> @p function badness(@!t,@!s:scaled):halfword; {compute badness, given |t>=0|} | |
1969,1977c2242,2250 | |
< 100\cdot2^{18}$} | |
< begin if t=0 then badness←0 | |
< else if s≤0 then badness←inf_bad | |
< else begin if t≤7230584 then r←(t*297) div s {$297^3=99.94\times2^{18}$} | |
< else if s≥1663497 then r←t div (s div 297) | |
< else r←t; | |
< if r>1290 then badness←inf_bad {$1290^3<2^{31}<1291^3$} | |
< else badness←(r*r*r+@'400000) div @'1000000; | |
< end; {that was $r^3/2^{18}$, rounded to the nearest integer} | |
--- | |
> 100\cdot2^{18}$} | |
> begin if t=0 then badness:=0 | |
> else if s<=0 then badness:=inf_bad | |
> else begin if t<=7230584 then r:=(t*297) div s {$297^3=99.94\times2^{18}$} | |
> else if s>=1663497 then r:=t div (s div 297) | |
> else r:=t; | |
> if r>1290 then badness:=inf_bad {$1290^3<2^{31}<1291^3$} | |
> else badness:=(r*r*r+@'400000) div @'1000000; | |
> end; {that was $r^3/2^{18}$, rounded to the nearest integer} | |
1987c2260 | |
< An unsigned glue ratio should take the same amount of memory as an | |
--- | |
> A glue ratio should take the same amount of memory as an | |
1990c2263 | |
< |short_real| in some implementations of \PASCAL. Alter\-natively, | |
--- | |
> |short_real| in some implementations of \PASCAL. Alternatively, | |
1992c2265,2266 | |
< arithmetic; see {\sl TUGboat \bf3} (1982), 10--27. | |
--- | |
> arithmetic; see {\sl TUGboat \bf3},1 (March 1982), 10--27. (But the | |
> routines cited there must be modified to allow negative glue ratios.) | |
1994a2269,2274 | |
> @d set_glue_ratio_zero(#) == #:=0.0 {store the representation of zero ratio} | |
> @d set_glue_ratio_one(#) == #:=1.0 {store the representation of unit ratio} | |
> @d float(#) == # {convert from |glue_ratio| to type |real|} | |
> @d unfloat(#) == # {convert from |real| to type |glue_ratio|} | |
> @d float_constant(#) == #.0 {convert |integer| constant to |real|} | |
> | |
1996a2277 | |
> | |
2000c2281 | |
< possibly scaled, or an (unsigned) |glue_ratio|, or a small number of | |
--- | |
> possibly scaled, or a (signed) |glue_ratio|, or a small number of | |
2012c2293 | |
< field)\cr | |
--- | |
> field)\cr | |
2014c2295 | |
< &\qquad\qquad\qquad(four quarterword fields)\cr}}$$ | |
--- | |
> &\qquad\qquad\qquad(four quarterword fields)\cr}}$$ | |
2039c2320 | |
< so it makes rather general assumptions. If integers having the subrange | |
--- | |
> so it makes few assumptions. If integers having the subrange | |
2057,2064c2338,2350 | |
< if (min_quarterword>0)∨(max_quarterword<127) then bad←11; | |
< if (min_halfword>0)∨(max_halfword<32767) then bad←12; | |
< if (min_quarterword<min_halfword)∨@| | |
< (max_quarterword>max_halfword) then bad←13; | |
< if (mem_base<min_halfword)∨(mem_max≥max_halfword) then bad←14; | |
< if (font_base<min_quarterword)∨(font_max>max_quarterword) then bad←15; | |
< if (save_size>max_halfword)∨(max_strings>max_halfword) then bad←16; | |
< if (buf_size>max_halfword) then bad←17; | |
--- | |
> init if (mem_min<>mem_bot)or(mem_max<>mem_top) then bad:=10;@+tini@;@/ | |
> if (mem_min>mem_bot)or(mem_max<mem_top) then bad:=10; | |
> if (min_quarterword>0)or(max_quarterword<127) then bad:=11; | |
> if (min_halfword>0)or(max_halfword<32767) then bad:=12; | |
> if (min_quarterword<min_halfword)or@| | |
> (max_quarterword>max_halfword) then bad:=13; | |
> if (mem_min<min_halfword)or(mem_max>=max_halfword)or@| | |
> (mem_bot-mem_min>max_halfword+1) then bad:=14; | |
> if (font_base<min_quarterword)or(font_max>max_quarterword) then bad:=15; | |
> if font_max>font_base+256 then bad:=16; | |
> if (save_size>max_halfword)or(max_strings>max_halfword) then bad:=17; | |
> if buf_size>max_halfword then bad:=18; | |
> if max_quarterword-min_quarterword<255 then bad:=19; | |
2074c2360 | |
< @^inner loop@> | |
--- | |
> @^inner loop@>@^system dependencies@> | |
2076,2079c2362,2369 | |
< @d qi(#)==(#+min_quarterword) | |
< {to put an |eight_bits| item into a quarterword} | |
< @d qo(#)==(#-min_quarterword) | |
< {to take an |eight_bits| item out of a quarterword} | |
--- | |
> @d qi(#)==#+min_quarterword | |
> {to put an |eight_bits| item into a quarterword} | |
> @d qo(#)==#-min_quarterword | |
> {to take an |eight_bits| item out of a quarterword} | |
> @d hi(#)==#+min_halfword | |
> {to put a sixteen-bit item into a halfword} | |
> @d ho(#)==#-min_halfword | |
> {to take a sixteen-bit item from a halfword} | |
2092,2096c2382,2386 | |
< @!rh:halfword; | |
< case two_choices of | |
< 1: (@!lh:halfword); | |
< 2: (@!b0:quarterword; @!b1:quarterword); | |
< end; | |
--- | |
> @!rh:halfword; | |
> case two_choices of | |
> 1: (@!lh:halfword); | |
> 2: (@!b0:quarterword; @!b1:quarterword); | |
> end; | |
2098,2109c2388,2399 | |
< @!b0:quarterword; | |
< @!b1:quarterword; | |
< @!b2:quarterword; | |
< @!b3:quarterword; | |
< end; | |
< @!memory_word = packed record@;@/ | |
< case four_choices of | |
< 1: (@!int:integer); | |
< 2: (@!gr:glue_ratio); | |
< 3: (@!hh:two_halves); | |
< 4: (@!qqqq:four_quarters); | |
< end; | |
--- | |
> @!b0:quarterword; | |
> @!b1:quarterword; | |
> @!b2:quarterword; | |
> @!b3:quarterword; | |
> end; | |
> @!memory_word = record@;@/ | |
> case four_choices of | |
> 1: (@!int:integer); | |
> 2: (@!gr:glue_ratio); | |
> 3: (@!hh:two_halves); | |
> 4: (@!qqqq:four_quarters); | |
> end; | |
2116c2406,2407 | |
< @p debug procedure print_memory_word(@!w:memory_word); {prints |w| in all ways} | |
--- | |
> @p @!debug procedure print_word(@!w:memory_word); | |
> {prints |w| in all ways} | |
2119c2410,2411 | |
< print_scaled(round(unity*w.gr)); print_ln;@/ | |
--- | |
> print_scaled(round(unity*float(w.gr))); print_ln;@/ | |
> @^real multiplication@> | |
2125a2418 | |
> | |
2127c2420 | |
< The \TeX\ system does nearly all of its own mem\-ory allocation, so that it | |
--- | |
> The \TeX\ system does nearly all of its own memory allocation, so that it | |
2135c2428 | |
< called |eqtb| that will be explained below. A pointer variable might | |
--- | |
> called |eqtb| that will be explained later. A pointer variable might | |
2138c2431 | |
< value represents a null pointer. | |
--- | |
> value represents a null pointer. \TeX\ does not assume that |mem[null]| exists. | |
2146,2147c2439,2442 | |
< @ The |mem| array is divided once and for all into two regions that are | |
< allocated separately. Locations less than |hi_mem_base| are used for storing | |
--- | |
> @ 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 | |
2151,2162c2446,2466 | |
< appears in the allocated nodes: the program is responsible for knowing the | |
< relevant size when a node is freed. The remaining region of |mem| is | |
< allocated in single words using a conventional \.{AVAIL} stack. | |
< | |
< Incidentally, it would be feasible to construct implementations of \TeX\ that | |
< are based on 16-bit words instead of 32-bit words, for machines having | |
< comparatively small memories. In such cases it would be desirable to have | |
< two parallel arrays for the upper part of memory, called say \\{mem\_link}|[p]| | |
< and \\{mem\_info}|[p]|, | |
< since the single-word region in the present implementation | |
< consists entirely of |memory_word| items of type |two_halves|. | |
< @^small computers@> | |
--- | |
> appears in the allocated nodes; the program is responsible for knowing the | |
> relevant size when a node is freed. Locations greater than or equal to | |
> |hi_mem_min| are used for storing one-word records; a conventional | |
> \.{AVAIL} stack is used for allocation in this region. | |
> | |
> Locations of |mem| between |mem_bot| and |mem_top| may be dumped as part | |
> of preloaded format files, by the \.{INITEX} preprocessor. | |
> @.INITEX@> | |
> Production versions of \TeX\ may extend the memory at both ends in order to | |
> provide more space; locations between |mem_min| and |mem_bot| are always | |
> used for variable-size nodes, and locations between |mem_top| and |mem_max| | |
> are always used for single-word nodes. | |
> | |
> The key pointers that govern |mem| allocation have a prescribed order: | |
> $$\advance\thickmuskip-2mu | |
> \hbox{|null<=mem_min<=mem_bot<lo_mem_max< | |
> hi_mem_min<mem_top<=mem_end<=mem_max|.}$$ | |
> | |
> Empirical tests show that the present implementation of \TeX\ tends to | |
> spend about 9\pct! of its running time allocating nodes, and about 6\pct! | |
> deallocating them after their use. | |
2164,2165c2468,2471 | |
< @<Globals...@>= | |
< @!mem : array[mem_base..mem_max] of memory_word; {the big dynamic storage area} | |
--- | |
> @<Glob...@>= | |
> @!mem : array[mem_min..mem_max] of memory_word; {the big dynamic storage area} | |
> @!lo_mem_max : pointer; {the largest location of variable-size memory in use} | |
> @!hi_mem_min : pointer; {the smallest location of one-word memory in use} | |
2169c2475 | |
< maximum memory usage. When code between the delimiters |stat| $\ldots$ | |
--- | |
> maximum memory usage. When code between the delimiters |@!stat| $\ldots$ | |
2171,2172c2477 | |
< report these statistics whenever a page is output and |tracing_stats| is | |
< nonzero. | |
--- | |
> report these statistics when |tracing_stats| is sufficiently large. | |
2174c2479 | |
< @<Globals...@>= | |
--- | |
> @<Glob...@>= | |
2176d2480 | |
< @!max_var_used : integer; {how much memory was in use} | |
2181c2485 | |
< occur between |hi_mem_base| and |mem_end|, inclusive, are of type | |
--- | |
> occur between |hi_mem_min| and |mem_end|, inclusive, are of type | |
2191c2495 | |
< @<Globals...@>= | |
--- | |
> @<Glob...@>= | |
2195c2499 | |
< @ If one-word memory is exhausted, it might mean that the user has forgotten | |
--- | |
> @ If memory is exhausted, it might mean that the user has forgotten | |
2203a2508,2513 | |
> @^inner loop@> | |
> | |
> If the available-space list is empty, i.e., if |avail=null|, | |
> we try first to increase |mem_end|. If that cannot be done, i.e., if | |
> |mem_end=mem_max|, we try to decrease |hi_mem_min|. If that cannot be | |
> done, i.e., if |hi_mem_min=lo_mem_max+1|, we have to quit. | |
2207,2208c2517,2518 | |
< begin p←avail; {get top location in the |avail| stack} | |
< if p≠null then avail←link(avail) {and pop it off} | |
--- | |
> begin p:=avail; {get top location in the |avail| stack} | |
> if p<>null then avail:=link(avail) {and pop it off} | |
2210,2217c2520,2532 | |
< begin incr(mem_end); p←mem_end; | |
< end | |
< else begin runaway; {if memory is exhausted, display possible runaway text} | |
< overflow("memory size",mem_max-mem_base); {quit; all one-word nodes are busy} | |
< end; | |
< link(p)←null; {provide an oft-desired initialization of the new node} | |
< stat incr(dyn_used);@+tats@;{maintain statistics} | |
< get_avail←p; | |
--- | |
> begin incr(mem_end); p:=mem_end; | |
> end | |
> else begin decr(hi_mem_min); p:=hi_mem_min; | |
> if hi_mem_min<=lo_mem_max then | |
> begin runaway; {if memory is exhausted, display possible runaway text} | |
> overflow("main memory size",mem_max+1-mem_min); | |
> {quit; all one-word nodes are busy} | |
> @:TeX capacity exceeded main memory size}{\quad main memory size@> | |
> end; | |
> end; | |
> link(p):=null; {provide an oft-desired initialization of the new node} | |
> @!stat incr(dyn_used);@+tats@;{maintain statistics} | |
> get_avail:=p; | |
2225,2227c2540,2555 | |
< begin link(#)←avail; avail←#; | |
< stat decr(dyn_used);@+tats@/ | |
< end | |
--- | |
> begin link(#):=avail; avail:=#; | |
> @!stat decr(dyn_used);@+tats@/ | |
> end | |
> | |
> @ There's also a |fast_get_avail| routine, which saves the procedure-call | |
> overhead at the expense of extra programming. This routine is used in | |
> the places that would otherwise account for the most calls of |get_avail|. | |
> @^inner loop@> | |
> | |
> @d fast_get_avail(#)==@t@>@;@/ | |
> begin #:=avail; {avoid |get_avail| if possible, to save time} | |
> if #=null then #:=get_avail | |
> else begin avail:=link(#); link(#):=null; | |
> @!stat incr(dyn_used);@+tats@/ | |
> end; | |
> end | |
2230a2559 | |
> @^inner loop@> | |
2233,2237c2562,2569 | |
< available} | |
< var q:pointer; {the successor of node |p|} | |
< begin while p≠null do | |
< begin q←link(p); free_avail(p); p←q; | |
< end; | |
--- | |
> available} | |
> var @!q,@!r:pointer; {list traversers} | |
> begin if p<>null then | |
> begin r:=p; | |
> repeat q:=r; r:=link(r); @!stat decr(dyn_used);@+tats@/ | |
> until r=null; {now |q| is the last node on the list} | |
> link(q):=avail; avail:=p; | |
> end; | |
2252a2585,2587 | |
> (We require |mem_max<max_halfword| because terrible things can happen | |
> when |max_halfword| appears in the |link| field of a nonempty node.) | |
> | |
2259c2594 | |
< @<Globals...@>= | |
--- | |
> @<Glob...@>= | |
2263c2598 | |
< of size@@|s|, which must be 2@@or more. The |link| field of the first word | |
--- | |
> of size~|s|, which must be 2~or more. The |link| field of the first word | |
2270,2271c2605,2606 | |
< @p function get_node(@!s:integer):pointer; {variable-size node liberation} | |
< label found,exit; | |
--- | |
> @p function get_node(@!s:integer):pointer; {variable-size node allocation} | |
> label found,exit,restart; | |
2275c2610,2611 | |
< begin p←rover; {start at some free node in the ring} | |
--- | |
> @!t:integer; {temporary register} | |
> begin restart: p:=rover; {start at some free node in the ring} | |
2277,2278c2613,2615 | |
< and |goto found| if allocation was possible@>; | |
< p←rlink(p); {move to the next node in the ring} | |
--- | |
> and |goto found| if allocation was possible@>; | |
> @^inner loop@> | |
> p:=rlink(p); {move to the next node in the ring} | |
2281,2286c2618,2626 | |
< begin get_node←max_halfword; return; | |
< end; | |
< overflow("var size",hi_mem_base-mem_base); {sorry, nothing satisfactory is left} | |
< found: link(r)←null; {this node is now nonempty} | |
< stat var_used←var_used+s; {maintain usage statistics} | |
< if var_used>max_var_used then max_var_used←var_used; | |
--- | |
> begin get_node:=max_halfword; return; | |
> end; | |
> if lo_mem_max+2<hi_mem_min then if lo_mem_max+2<=mem_bot+max_halfword then | |
> @<Grow more variable-size memory and |goto restart|@>; | |
> overflow("main memory size",mem_max+1-mem_min); | |
> {sorry, nothing satisfactory is left} | |
> @:TeX capacity exceeded main memory size}{\quad main memory size@> | |
> found: link(r):=null; {this node is now nonempty} | |
> @!stat var_used:=var_used+s; {maintain usage statistics} | |
2288c2628 | |
< get_node←r; | |
--- | |
> get_node:=r; | |
2291,2292c2631,2666 | |
< @ The following operations remove an empty node from the doubly-linked | |
< list, knowing that it is not the only item in the list. | |
--- | |
> @ The lower part of |mem| grows by 1000 words at a time, unless | |
> we are very close to going under. When it grows, we simply link | |
> a new node into the available-space list. This method of controlled | |
> growth helps to keep the |mem| usage consecutive when \TeX\ is | |
> implemented on ``virtual memory'' systems. | |
> @^virtual memory@> | |
> | |
> @<Grow more variable-size memory and |goto restart|@>= | |
> begin if hi_mem_min-lo_mem_max>=1998 then t:=lo_mem_max+1000 | |
> else t:=lo_mem_max+1+(hi_mem_min-lo_mem_max) div 2; | |
> {|lo_mem_max+2<=t<hi_mem_min|} | |
> p:=llink(rover); q:=lo_mem_max; rlink(p):=q; llink(rover):=q;@/ | |
> if t>mem_bot+max_halfword then t:=mem_bot+max_halfword; | |
> rlink(q):=rover; llink(q):=p; link(q):=empty_flag; node_size(q):=t-lo_mem_max;@/ | |
> lo_mem_max:=t; link(lo_mem_max):=null; info(lo_mem_max):=null; | |
> rover:=q; goto restart; | |
> end | |
> | |
> @ Empirical tests show that the routine in this section performs a | |
> node-merging operation about 0.75 times per allocation, on the average, | |
> after which it finds that |r>p+1| about 95\pct! of the time. | |
> | |
> @<Try to allocate...@>= | |
> q:=p+node_size(p); {find the physical successor} | |
> @^inner loop@> | |
> while is_empty(q) do {merge node |p| with node |q|} | |
> begin t:=rlink(q); | |
> if q=rover then rover:=t; | |
> llink(t):=llink(q); rlink(llink(q)):=t;@/ | |
> q:=q+node_size(q); | |
> end; | |
> r:=q-s; | |
> if r>p+1 then @<Allocate from the top of node |p| and |goto found|@>; | |
> if r=p then if rlink(p)<>p then | |
> @<Allocate entire node |p| and |goto found|@>; | |
> node_size(p):=q-p {reset the size in case it grew} | |
2294,2312c2668,2671 | |
< @d remove_node(#) ==@; | |
< if #=rover then rover←rlink(#); | |
< llink(rlink(#))←llink(#); | |
< rlink(llink(#))←rlink(#) | |
< | |
< @ @<Try to allocate...@>= | |
< q←p+node_size(p); {find the physical successor} | |
< while is_empty(q) do {merge |p| with |q|} | |
< begin remove_node(q); q←q+node_size(q); | |
< end; | |
< r←q-s; | |
< if r>p+1 then @<Allocate from top of node |p| and |goto found|@>; | |
< if (r=p) and ((rlink(p)≠rover) or (llink(p)≠rover)) then | |
< @<Allocate entire node |p| and |goto found|@>; | |
< node_size(p)←q-p {reset the size in case it grew} | |
< | |
< @ @<Allocate from top...@>= | |
< begin node_size(p)←r-p; {store the remaining size} | |
< rover←p; {start searching here next time} | |
--- | |
> @ @<Allocate from the top...@>= | |
> begin node_size(p):=r-p; {store the remaining size} | |
> @^inner loop@> | |
> rover:=p; {start searching here next time} | |
2316,2318c2675,2679 | |
< @ @<Allocate entire...@>= | |
< begin remove_node(p); {delete node |p| from the ring} | |
< rover←rlink(p); {let |rover| rove around} | |
--- | |
> @ Here we delete node |p| from the ring, and let |rover| rove around. | |
> | |
> @<Allocate entire...@>= | |
> begin rover:=rlink(p); t:=llink(p); | |
> llink(rover):=t; rlink(t):=rover; | |
2324a2686 | |
> @^inner loop@> | |
2327c2689 | |
< liberation} | |
--- | |
> liberation} | |
2329,2335c2691,2694 | |
< begin if @<Node |p| isn't in the variable-size |mem|@> then | |
< confusion("freenode"); | |
< @:confusion free_node}{\quad freenode@> | |
< node_size(p)←s; link(p)←empty_flag; | |
< q←llink(rover); llink(p)←q; rlink(p)←rover; {set both links} | |
< llink(rover)←p; rlink(q)←p; {insert |p| into the ring} | |
< stat var_used←var_used-s;@+tats@;{maintain statistics} | |
--- | |
> begin node_size(p):=s; link(p):=empty_flag; | |
> q:=llink(rover); llink(p):=q; rlink(p):=rover; {set both links} | |
> llink(rover):=p; rlink(q):=p; {insert |p| into the ring} | |
> @!stat var_used:=var_used-s;@+tats@;{maintain statistics} | |
2343,2344c2702,2703 | |
< @p init procedure sort_avail; {sorts the available variable-size nodes | |
< by location} | |
--- | |
> @p @!init procedure sort_avail; {sorts the available variable-size nodes | |
> by location} | |
2347,2355c2706,2714 | |
< begin p←get_node(@'10000000000); {merge adjacent free areas} | |
< p←rlink(rover); rlink(rover)←max_halfword; old_rover←rover; | |
< while p≠old_rover do @<Sort |p| into the list starting at |rover| | |
< and advance |p| to |rlink(p)|@>; | |
< p←rover; | |
< while rlink(p)≠max_halfword do | |
< begin llink(rlink(p))←p; p←rlink(p); | |
< end; | |
< rlink(p)←rover; llink(rover)←p; | |
--- | |
> begin p:=get_node(@'10000000000); {merge adjacent free areas} | |
> p:=rlink(rover); rlink(rover):=max_halfword; old_rover:=rover; | |
> while p<>old_rover do @<Sort \(p)|p| into the list starting at |rover| | |
> and advance |p| to |rlink(p)|@>; | |
> p:=rover; | |
> while rlink(p)<>max_halfword do | |
> begin llink(rlink(p)):=p; p:=rlink(p); | |
> end; | |
> rlink(p):=rover; llink(rover):=p; | |
2359c2718,2719 | |
< @ The following |while| loop terminates, since the list that starts at | |
--- | |
> @ The following |while| loop is guaranteed to | |
> terminate, since the list that starts at | |
2362c2722 | |
< @<Sort |p|...@>= | |
--- | |
> @<Sort \(p)|p|...@>= | |
2364,2369c2724,2730 | |
< begin q←p; p←rlink(q); rlink(q)←rover; rover←q; | |
< end | |
< else begin q←rover; | |
< while rlink(q)<p do q←rlink(q); | |
< r←rlink(p); rlink(p)←rlink(q); rlink(q)←p; p←r; | |
< end | |
--- | |
> begin q:=p; p:=rlink(q); rlink(q):=rover; rover:=q; | |
> end | |
> else begin q:=rover; | |
> while rlink(q)<p do q:=rlink(q); | |
> r:=rlink(p); rlink(p):=rlink(q); rlink(q):=p; p:=r; | |
> end | |
> | |
2390c2751 | |
< two words, and they appear in |mem| locations less than |hi_mem_base|. | |
--- | |
> two words, and they appear in |mem| locations less than |hi_mem_min|. | |
2398,2400c2759,2761 | |
< and most fonts will stick to characters less than 128 (since higher codes | |
< are accessed outside of math mode only via ligatures and the \.{\\char} | |
< operator). | |
--- | |
> and most fonts will stick to characters whose codes are | |
> less than 128 (since higher codes | |
> are more difficult to access on most keyboards). | |
2407,2410c2768,2770 | |
< entries: The first of these would identify the font and the character | |
< dimensions, and it would also link to the second, where the full halfword | |
< |info| field would address the desired character. Such an extension of | |
< \TeX\ would not be difficult; further details are left to the reader. | |
--- | |
> entries: The first of these has |font=font_base|, and its |link| points | |
> to the second; | |
> the second identifies the font and the character dimensions. | |
2412c2772,2776 | |
< the same box dimensions. | |
--- | |
> the same box dimensions. The |character| field of the first |char_node| | |
> is a ``\\{charext}'' that distinguishes between graphic symbols whose | |
> dimensions are identical for typesetting purposes. (See the \MF\ manual.) | |
> Such an extension of \TeX\ would not be difficult; further details are | |
> left to the reader. | |
2419,2420c2783,2784 | |
< @d is_char_node(#) == (#>hi_mem_base) | |
< {does the argument point to a |char_node|?} | |
--- | |
> @d is_char_node(#) == (#>=hi_mem_min) | |
> {does the argument point to a |char_node|?} | |
2458c2822,2824 | |
< @d glue_set(#) == mem[#+6].gr {a word of type |glue_ratio| for glue setting} | |
--- | |
> @d glue_offset = 6 {position of |glue_set| in a box node} | |
> @d glue_set(#) == mem[#+glue_offset].gr | |
> {a word of type |glue_ratio| for glue setting} | |
2462,2463c2828,2829 | |
< The |subtype| field is set to |min_quarterword|, since that is the |span_count| | |
< value that is desired in case this |hlist_node| is changed to an |unset_node|. | |
--- | |
> The |subtype| field is set to |min_quarterword|, since that's the desired | |
> |span_count| value if this |hlist_node| is changed to an |unset_node|. | |
2467,2471c2833,2837 | |
< begin p←get_node(box_node_size); type(p)←hlist_node; | |
< subtype(p)←min_quarterword; | |
< width(p)←0; depth(p)←0; height(p)←0; shift_amount(p)←0; list_ptr(p)←null; | |
< glue_sign(p)←normal; glue_order(p)←normal; glue_set(p)←0.0; | |
< new_null_box←p; | |
--- | |
> begin p:=get_node(box_node_size); type(p):=hlist_node; | |
> subtype(p):=min_quarterword; | |
> width(p):=0; depth(p):=0; height(p):=0; shift_amount(p):=0; list_ptr(p):=null; | |
> glue_sign(p):=normal; glue_order(p):=normal; set_glue_ratio_zero(glue_set(p)); | |
> new_null_box:=p; | |
2475c2841 | |
< was made from a vertical list. | |
--- | |
> contains a vertical list. | |
2484c2850 | |
< an hlist; the |height| and |depth| are never running in a vlist. | |
--- | |
> an hlist; the |height| and |depth| are never running in a~vlist. | |
2497,2500c2863,2866 | |
< begin p←get_node(rule_node_size); type(p)←rule_node; | |
< subtype(p)←0; {the |subtype| is not used} | |
< width(p)←null_flag; depth(p)←null_flag; height(p)←null_flag; | |
< new_rule←p; | |
--- | |
> begin p:=get_node(rule_node_size); type(p):=rule_node; | |
> subtype(p):=0; {the |subtype| is not used} | |
> width(p):=null_flag; depth(p):=null_flag; height(p):=null_flag; | |
> new_rule:=p; | |
2506c2872 | |
< The |width| field of an |ins_node| is slightly misnamed; it actually holds | |
--- | |
> The |height| field of an |ins_node| is slightly misnamed; it actually holds | |
2508,2510c2874,2879 | |
< There is one more field, the |ins_ptr|, which points to the beginning of | |
< the vlist for the insertion. In the present implementation, |ins_ptr| | |
< occupies a full word, although half a word would be enough. | |
--- | |
> The |depth| field holds the |split_max_depth| to be used in case this | |
> insertion is split, and the |split_top_ptr| points to the corresponding | |
> |split_top_skip|. The |float_cost| field holds the |floating_penalty| that | |
> will be used if this insertion floats to a subsequent page after a | |
> split insertion of the same class. There is one more field, the | |
> |ins_ptr|, which points to the beginning of the vlist for the insertion. | |
2513,2514c2882,2885 | |
< @d ins_node_size=3 {number of words to allocate for an insertion} | |
< @d ins_ptr(#)==mem[#+2].int {the vertical list to be inserted} | |
--- | |
> @d ins_node_size=5 {number of words to allocate for an insertion} | |
> @d float_cost(#)==mem[#+1].int {the |floating_penalty| to be used} | |
> @d ins_ptr(#)==info(#+4) {the vertical list to be inserted} | |
> @d split_top_ptr(#)==link(#+4) {the |split_top_skip| to be used} | |
2517,2518c2888,2889 | |
< of a token list that contains the user's \.{\\mark} text. Like the |ins_ptr| | |
< field, this one occupies a full word instead of a halfword just because | |
--- | |
> of a token list that contains the user's \.{\\mark} text. | |
> This field occupies a full word instead of a halfword, because | |
2526,2529c2897,2901 | |
< @ An |adjust_node|, which occurs only in horizontal lists, specifies | |
< material that will be moved out into the surrounding vertical list; | |
< i.e., it is used to implement \TeX's `\.{\\vadjust}' operation. | |
< The |adjust_ptr| field points to the vlist containing this material. | |
--- | |
> @ An |adjust_node|, which occurs only in horizontal lists, | |
> specifies material that will be moved out into the surrounding | |
> vertical list; i.e., it is used to implement \TeX's `\.{\\vadjust}' | |
> operation. The |adjust_ptr| field points to the vlist containing this | |
> material. | |
2534,2540c2906,2918 | |
< @ A |ligature_node|, which occurs only in horizontal lists, specifies a | |
< composite character that was formed from two or more actual characters. | |
< The second word of the node, which is called the |lig_char| word, contains | |
< |font| and |character| fields just as in a |char_node|. The characters | |
< that generated the ligature have not been forgotten, since they are needed | |
< for diagnostic messages and for hyphenation; the |lig_ptr| field points to | |
< a linked list of character nodes for those characters. | |
--- | |
> @ A |ligature_node|, which occurs only in horizontal lists, specifies | |
> a character that was fabricated from the interaction of two or more | |
> actual characters. The second word of the node, which is called the | |
> |lig_char| word, contains |font| and |character| fields just as in a | |
> |char_node|. The characters that generated the ligature have not been | |
> forgotten, since they are needed for diagnostic messages and for | |
> hyphenation; the |lig_ptr| field points to a linked list of character | |
> nodes for all original characters that have been deleted. (This list | |
> might be empty if the characters that generated the ligature were | |
> retained in other nodes.) | |
> | |
> The |subtype| field is 0, plus 2 and/or 1 if the original source of the | |
> ligature included implicit left and/or right boundaries. | |
2547c2925,2928 | |
< contents of the |font|, |character|, and |lig_ptr| fields. | |
--- | |
> contents of the |font|, |character|, and |lig_ptr| fields. We also have | |
> a |new_lig_item| function, which returns a two-word node having a given | |
> |character| field. Such nodes are used for temporary processing as ligatures | |
> are being created. | |
2551,2554c2932,2940 | |
< begin p←get_node(small_node_size); type(p)←ligature_node; | |
< subtype(p)←0; {the |subtype| is not used} | |
< font(lig_char(p))←f; character(lig_char(p))←c; lig_ptr(p)←q; | |
< new_ligature←p; | |
--- | |
> begin p:=get_node(small_node_size); type(p):=ligature_node; | |
> font(lig_char(p)):=f; character(lig_char(p)):=c; lig_ptr(p):=q; | |
> subtype(p):=0; new_ligature:=p; | |
> end; | |
> @# | |
> function new_lig_item(@!c:quarterword):pointer; | |
> var p:pointer; {the new node} | |
> begin p:=get_node(small_node_size); character(p):=c; lig_ptr(p):=null; | |
> new_lig_item:=p; | |
2565c2951 | |
< lists that consist entirely of character, kern, and ligature nodes. | |
--- | |
> lists that consist entirely of character, kern, box, rule, and ligature nodes. | |
2581,2583c2967,2969 | |
< begin p←get_node(small_node_size); type(p)←disc_node; | |
< replace_count(p)←0; pre_break(p)←null; post_break(p)←null; | |
< new_disc←p; | |
--- | |
> begin p:=get_node(small_node_size); type(p):=disc_node; | |
> replace_count(p):=0; pre_break(p):=null; post_break(p):=null; | |
> new_disc:=p; | |
2592c2978 | |
< things by adding code to these extension modules. For example, there | |
--- | |
> things by adding code at the end of the program. For example, there | |
2598c2984 | |
< `\.{\\send}' and `\.{\\xsend}' as if they were extensions, in order to | |
--- | |
> `\.{\\write}' and `\.{\\special}' as if they were extensions, in order to | |
2615,2616c3001,3002 | |
< begin p←get_node(small_node_size); type(p)←math_node; | |
< subtype(p)←s; width(p)←w; new_math←p; | |
--- | |
> begin p:=get_node(small_node_size); type(p):=math_node; | |
> subtype(p):=s; width(p):=w; new_math:=p; | |
2623,2624c3009,3010 | |
< |type| of the previous node is |math_node| or less. Furthermore, a | |
< node is discarded after a break if its type is |math_node| or more. | |
--- | |
> |type| of the previous node is less than |math_node|. Furthermore, a | |
> node is discarded after a break if its type is |math_node| or~more. | |
2626c3012 | |
< @d precedes_break(#)==(type(#)≤math_node) | |
--- | |
> @d precedes_break(#)==(type(#)<math_node) | |
2647c3033 | |
< will be the same as the parameter number, plus one. | |
--- | |
> will be the same as the parameter number, plus~one. | |
2654c3040 | |
< | |
--- | |
> | |
2656,2657c3042,3043 | |
< @d mu_glue=98 {|subtype| for mskip glue} | |
< @d cond_math_glue=99 {special |subtype| to suppress glue in the next node} | |
--- | |
> @d cond_math_glue=98 {special |subtype| to suppress glue in the next node} | |
> @d mu_glue=99 {|subtype| for math glue} | |
2691a3078,3079 | |
> The reference count in the copy is |null|, because there is assumed | |
> to be exactly one reference to the new specification. | |
2695,2698c3083,3086 | |
< begin q←get_node(glue_spec_size);@/ | |
< mem[q]←mem[p]; glue_ref_count(q)←null;@/ | |
< width(q)←width(p); stretch(q)←stretch(p); shrink(q)←shrink(p); | |
< new_spec←q; | |
--- | |
> begin q:=get_node(glue_spec_size);@/ | |
> mem[q]:=mem[p]; glue_ref_count(q):=null;@/ | |
> width(q):=width(p); stretch(q):=stretch(p); shrink(q):=shrink(p); | |
> new_spec:=q; | |
2701,2703c3089,3092 | |
< @ And here's a function that creates a glue node for a given parameter; | |
< for example, |new_param_glue(disp_skip_code)| returns a pointer to a glue | |
< node for the current \.{\\dispskip}. | |
--- | |
> @ And here's a function that creates a glue node for a given parameter | |
> identified by its code number; for example, | |
> |new_param_glue(line_skip_code)| returns a pointer to a glue node for the | |
> current \.{\\lineskip}. | |
2708,2712c3097,3101 | |
< begin p←get_node(small_node_size); type(p)←glue_node; subtype(p)←n+1; | |
< leader_ptr(p)←null;@/ | |
< q←@<Current |mem| equivalent of glue parameter number |n|@>@t@>; | |
< glue_ptr(p)←q; incr(glue_ref_count(q)); | |
< new_param_glue←p; | |
--- | |
> begin p:=get_node(small_node_size); type(p):=glue_node; subtype(p):=n+1; | |
> leader_ptr(p):=null;@/ | |
> q:=@<Current |mem| equivalent of glue parameter number |n|@>@t@>; | |
> glue_ptr(p):=q; incr(glue_ref_count(q)); | |
> new_param_glue:=p; | |
2720,2722c3109,3111 | |
< begin p←get_node(small_node_size); type(p)←glue_node; subtype(p)←normal; | |
< leader_ptr(p)←null; glue_ptr(p)←q; incr(glue_ref_count(q)); | |
< new_glue←p; | |
--- | |
> begin p:=get_node(small_node_size); type(p):=glue_node; subtype(p):=normal; | |
> leader_ptr(p):=null; glue_ptr(p):=q; incr(glue_ref_count(q)); | |
> new_glue:=p; | |
2725c3114 | |
< @ Still another subroutine is needed: this one is sort of a combination | |
--- | |
> @ Still another subroutine is needed: This one is sort of a combination | |
2734,2736c3123,3125 | |
< begin temp_ptr←new_spec(@<Current |mem| equivalent of glue parameter...@>); | |
< p←new_glue(temp_ptr); glue_ref_count(temp_ptr)←null; subtype(p)←n+1; | |
< new_skip_param←p; | |
--- | |
> begin temp_ptr:=new_spec(@<Current |mem| equivalent of glue parameter...@>); | |
> p:=new_glue(temp_ptr); glue_ref_count(temp_ptr):=null; subtype(p):=n+1; | |
> new_skip_param:=p; | |
2744,2746c3133,3137 | |
< spacing in the vertical direction. The |subtype| is either |normal| or | |
< |mu_glue|, where the latter is used for \.{\\mkern} specifications | |
< in math formulas. | |
--- | |
> spacing in the vertical direction. The |subtype| is either |normal| (for | |
> kerns inserted from font information or math mode calculations) or |explicit| | |
> (for kerns inserted from \.{\\kern} and \.{\\/} commands) or |acc_kern| | |
> (for kerns inserted from non-math accents) or |mu_glue| (for kerns | |
> inserted from \.{\\mkern} specifications in math formulas). | |
2748a3140,3141 | |
> @d explicit=1 {|subtype| of kern nodes from \.{\\kern} and \.{\\/}} | |
> @d acc_kern=2 {|subtype| of kern nodes from accents} | |
2754,2757c3147,3150 | |
< begin p←get_node(small_node_size); type(p)←kern_node; | |
< subtype(p)←normal; | |
< width(p)←w; | |
< new_kern←p; | |
--- | |
> begin p:=get_node(small_node_size); type(p):=kern_node; | |
> subtype(p):=normal; | |
> width(p):=w; | |
> new_kern:=p; | |
2762c3155 | |
< the full range of integer values is not used: Any penalty |≥10000| is | |
--- | |
> the full range of integer values is not used: Any penalty |>=10000| is | |
2764c3157 | |
< Similarly, any penalty |≤-10000| is treated as negative infinity, and a | |
--- | |
> Similarly, any penalty |<=-10000| is treated as negative infinity, and a | |
2777,2779c3170,3172 | |
< begin p←get_node(small_node_size); type(p)←penalty_node; | |
< subtype(p)←0; {the |subtype| is not used} | |
< penalty(p)←m; new_penalty←p; | |
--- | |
> begin p:=get_node(small_node_size); type(p):=penalty_node; | |
> subtype(p):=0; {the |subtype| is not used} | |
> penalty(p):=m; new_penalty:=p; | |
2797c3190 | |
< @d glue_stretch(#)==mem[#+6].sc {total stretch in an unset node} | |
--- | |
> @d glue_stretch(#)==mem[#+glue_offset].sc {total stretch in an unset node} | |
2808,2810c3201,3206 | |
< below may have to be changed. However, other references to the nodes are made | |
< symbolically in terms of the \.{WEB} macro definitions above, so format changes | |
< will leave \TeX's other algorithms intact. | |
--- | |
> below may have to be changed. Such potentially dangerous parts of the | |
> program are listed in the index under `data structure assumptions'. | |
> @!@^data structure assumptions@> | |
> However, other references to the nodes are made symbolically in terms of | |
> the \.{WEB} macro definitions above, so that format changes will leave | |
> \TeX's other algorithms intact. | |
2811a3208 | |
> | |
2815c3212 | |
< example, locations |mem_base| to |mem_base+3| are always used to store the | |
--- | |
> example, locations |mem_bot| to |mem_bot+3| are always used to store the | |
2818,2821c3215,3218 | |
< symbolic names to the fixed positions. Dynamic allocation of variable-size | |
< nodes is restricted to locations |first_mem| through |(hi_mem_base-1)|, | |
< and single-word nodes are dynamically allocated in locations |second_mem| | |
< through |mem_max|, inclusive. | |
--- | |
> symbolic names to the fixed positions. Static variable-size nodes appear | |
> in locations |mem_bot| through |lo_mem_stat_max|, and static single-word nodes | |
> appear in locations |hi_mem_stat_min| through |mem_top|, inclusive. It is | |
> harmless to let |lig_trick| and |garbage| share the same location of |mem|. | |
2823c3220 | |
< @d zero_glue==mem_base {specification for \.{0pt plus 0pt minus 0pt}} | |
--- | |
> @d zero_glue==mem_bot {specification for \.{0pt plus 0pt minus 0pt}} | |
2828,2829c3225,3226 | |
< @d first_mem==fil_neg_glue+glue_spec_size {first dynamically allocatable word | |
< in the variable-size |mem|} | |
--- | |
> @d lo_mem_stat_max==fil_neg_glue+glue_spec_size-1 {largest statically | |
> allocated word in the variable-size |mem|} | |
2831,2847c3228,3244 | |
< @d page_ins_head==hi_mem_base {list of insertion data for current page} | |
< @d contrib_head==hi_mem_base+1 {vlist of items not yet on current page} | |
< @d page_head==hi_mem_base+2 {vlist for current page} | |
< @d temp_head==hi_mem_base+3 {head of a temporary list of some kind} | |
< @d hold_head==hi_mem_base+4 {head of a temporary list of another kind} | |
< @d scan_head==hi_mem_base+5 {head of token list built by |scan_keyword|} | |
< @d adjust_head==hi_mem_base+6 {head of adjustment list returned by |hpack|} | |
< @d active==hi_mem_base+7 {head of active list in |line_break|, needs two words} | |
< @d align_head==hi_mem_base+9 {head of preamble list for alignments} | |
< @d end_span==hi_mem_base+10 {tail of spanned-width lists} | |
< @d omit_template==hi_mem_base+11 {a constant token list} | |
< @d lig_trick==hi_mem_base+12 {a ligature masquerading as a |char_node|} | |
< @d garbage==hi_mem_base+13 {used for scrap information} | |
< @d second_mem==hi_mem_base+14 {first dynamically allocatable word in | |
< the one-word |mem|} | |
< | |
< @<Node |p| isn't in the variable-size |mem|@>=(p<first_mem)∨(p≥hi_mem_base) | |
--- | |
> @d page_ins_head==mem_top {list of insertion data for current page} | |
> @d contrib_head==mem_top-1 {vlist of items not yet on current page} | |
> @d page_head==mem_top-2 {vlist for current page} | |
> @d temp_head==mem_top-3 {head of a temporary list of some kind} | |
> @d hold_head==mem_top-4 {head of a temporary list of another kind} | |
> @d adjust_head==mem_top-5 {head of adjustment list returned by |hpack|} | |
> @d active==mem_top-7 {head of active list in |line_break|, needs two words} | |
> @d align_head==mem_top-8 {head of preamble list for alignments} | |
> @d end_span==mem_top-9 {tail of spanned-width lists} | |
> @d omit_template==mem_top-10 {a constant token list} | |
> @d null_list==mem_top-11 {permanently empty list} | |
> @d lig_trick==mem_top-12 {a ligature masquerading as a |char_node|} | |
> @d garbage==mem_top-12 {used for scrap information} | |
> @d backup_head==mem_top-13 {head of token list built by |scan_keyword|} | |
> @d hi_mem_stat_min==mem_top-13 {smallest statically allocated word in | |
> the one-word |mem|} | |
> @d hi_mem_stat_usage=14 {the number of one-word nodes always present} | |
2850c3247 | |
< initializing itself the slow way. | |
--- | |
> initializing itself the slow~way. | |
2856,2873c3253,3273 | |
< for k←mem_base+1 to first_mem-1 do mem[k].sc←0; | |
< {all glue dimensions are zeroed} | |
< k←mem_base;@+while k<first_mem do {set first words of glue specifications} | |
< begin glue_ref_count(k)←null+1; | |
< stretch_order(k)←normal; shrink_order(k)←normal; | |
< k←k+glue_spec_size; | |
< end; | |
< stretch(fil_glue)←unity; stretch_order(fil_glue)←fil;@/ | |
< stretch(fill_glue)←unity; stretch_order(fill_glue)←fill;@/ | |
< stretch(ss_glue)←unity; stretch_order(ss_glue)←fil;@/ | |
< shrink(ss_glue)←unity; shrink_order(ss_glue)←fil;@/ | |
< stretch(fil_neg_glue)←-unity; stretch_order(fil_neg_glue)←fil;@/ | |
< rover←first_mem; link(rover)←empty_flag; {now initialize the dynamic memory} | |
< node_size(rover)←hi_mem_base-rover; {which is one big available node} | |
< llink(rover)←rover; rlink(rover)←rover;@/ | |
< link(hi_mem_base)←null; info(hi_mem_base)←null; | |
< for k←hi_mem_base+1 to second_mem-1 do | |
< mem[k]←mem[hi_mem_base];{clear list heads} | |
--- | |
> for k:=mem_bot+1 to lo_mem_stat_max do mem[k].sc:=0; | |
> {all glue dimensions are zeroed} | |
> @^data structure assumptions@> | |
> k:=mem_bot;@+while k<=lo_mem_stat_max do | |
> {set first words of glue specifications} | |
> begin glue_ref_count(k):=null+1; | |
> stretch_order(k):=normal; shrink_order(k):=normal; | |
> k:=k+glue_spec_size; | |
> end; | |
> stretch(fil_glue):=unity; stretch_order(fil_glue):=fil;@/ | |
> stretch(fill_glue):=unity; stretch_order(fill_glue):=fill;@/ | |
> stretch(ss_glue):=unity; stretch_order(ss_glue):=fil;@/ | |
> shrink(ss_glue):=unity; shrink_order(ss_glue):=fil;@/ | |
> stretch(fil_neg_glue):=-unity; stretch_order(fil_neg_glue):=fil;@/ | |
> rover:=lo_mem_stat_max+1; | |
> link(rover):=empty_flag; {now initialize the dynamic memory} | |
> node_size(rover):=1000; {which is a 1000-word available node} | |
> llink(rover):=rover; rlink(rover):=rover;@/ | |
> lo_mem_max:=rover+1000; link(lo_mem_max):=null; info(lo_mem_max):=null;@/ | |
> for k:=hi_mem_stat_min to mem_top do | |
> mem[k]:=mem[lo_mem_max]; {clear list heads} | |
2875,2877c3275,3278 | |
< avail←null; mem_end←second_mem-1; {initialize the one-word memory} | |
< var_used←first_mem-mem_base; dyn_used←second_mem-hi_mem_base; | |
< max_var_used←var_used; {initialize statistics} | |
--- | |
> avail:=null; mem_end:=mem_top; | |
> hi_mem_min:=hi_mem_stat_min; {initialize the one-word memory} | |
> var_used:=lo_mem_stat_max+1-mem_bot; dyn_used:=hi_mem_stat_usage; | |
> {initialize statistics} | |
2887,2888c3288 | |
< are debugging; decreasing |mem_max| saves space and time, | |
< and decreasing |hi_mem_base| saves time.) | |
--- | |
> are debugging.) | |
2890,2895c3290,3296 | |
< @<Globals...@>= | |
< debug @!free: packed array [mem_base..mem_max] of boolean; {free cells} | |
< @t\hskip1em@>@!was_free: packed array [mem_base..mem_max] of boolean; | |
< {previously free cells} | |
< @t\hskip1em@>@!was_mem_end: pointer; {previous |mem_end|} | |
< @t\hskip1em@>@!panicking:boolean; {do we want to check memory constantly?} | |
--- | |
> @<Glob...@>= | |
> @!debug @!free: packed array [mem_min..mem_max] of boolean; {free cells} | |
> @t\hskip10pt@>@!was_free: packed array [mem_min..mem_max] of boolean; | |
> {previously free cells} | |
> @t\hskip10pt@>@!was_mem_end,@!was_lo_max,@!was_hi_min: pointer; | |
> {previous |mem_end|, |lo_mem_max|, and |hi_mem_min|} | |
> @t\hskip10pt@>@!panicking:boolean; {do we want to check memory constantly?} | |
2899,2900c3300,3302 | |
< debug was_mem_end←mem_base; {indicate that everything was previously free} | |
< panicking←false; | |
--- | |
> @!debug was_mem_end:=mem_min; {indicate that everything was previously free} | |
> was_lo_max:=mem_min; was_hi_min:=mem_max; | |
> panicking:=false; | |
2907c3309 | |
< @p debug procedure check_mem(@!print_locs : boolean); | |
--- | |
> @p @!debug procedure check_mem(@!print_locs : boolean); | |
2911,2912c3313,3315 | |
< begin for p←mem_base to mem_end do free[p]←false; {you can probably | |
< do this faster} | |
--- | |
> begin for p:=mem_min to lo_mem_max do free[p]:=false; {you can probably | |
> do this faster} | |
> for p:=hi_mem_min to mem_end do free[p]:=false; {ditto} | |
2917,2918c3320,3323 | |
< for p←0 to mem_end do was_free[p]←free[p]; {|was_free←free| might be faster} | |
< was_mem_end←mem_end; | |
--- | |
> for p:=mem_min to lo_mem_max do was_free[p]:=free[p]; | |
> for p:=hi_mem_min to mem_end do was_free[p]:=free[p]; | |
> {|was_free:=free| might be faster} | |
> was_mem_end:=mem_end; was_lo_max:=lo_mem_max; was_hi_min:=hi_mem_min; | |
2923,2932c3328,3338 | |
< p←avail; q←null; clobbered←false; | |
< while p≠null do | |
< begin if (p>mem_end)∨(p<second_mem) then clobbered←true | |
< else if free[p] then clobbered←true; | |
< if clobbered then | |
< begin print_nl("AVAIL list clobbered at "); | |
< print_int(q); goto done1; | |
< end; | |
< free[p]←true; q←p; p←link(q); | |
< end; | |
--- | |
> p:=avail; q:=null; clobbered:=false; | |
> while p<>null do | |
> begin if (p>mem_end)or(p<hi_mem_min) then clobbered:=true | |
> else if free[p] then clobbered:=true; | |
> if clobbered then | |
> begin print_nl("AVAIL list clobbered at "); | |
> @.AVAIL list clobbered...@> | |
> print_int(q); goto done1; | |
> end; | |
> free[p]:=true; q:=p; p:=link(q); | |
> end; | |
2936,2952c3342,3359 | |
< p←rover; q←null; clobbered←false; | |
< repeat if (p≥hi_mem_base)∨(p<first_mem) then clobbered←true | |
< else if (rlink(p)≥hi_mem_base)∨(rlink(p)<first_mem) then clobbered←true | |
< else if ¬(is_empty(p))∨(node_size(p)<2)∨@| | |
< (p+node_size(p)>hi_mem_base)∨@| (llink(rlink(p))≠p) then clobbered←true; | |
< if clobbered then | |
< begin print_nl("Double-AVAIL list clobbered at "); | |
< print_int(q); goto done2; | |
< end; | |
< for q←p to p+node_size(p)-1 do {mark all locations free} | |
< begin if free[q] then | |
< begin print_nl("Doubly free location at "); | |
< print_int(q); goto done2; | |
< end; | |
< free[q]←true; | |
< end; | |
< q←p; p←rlink(p); | |
--- | |
> p:=rover; q:=null; clobbered:=false; | |
> repeat if (p>=lo_mem_max)or(p<mem_min) then clobbered:=true | |
> else if (rlink(p)>=lo_mem_max)or(rlink(p)<mem_min) then clobbered:=true | |
> else if not(is_empty(p))or(node_size(p)<2)or@| | |
> (p+node_size(p)>lo_mem_max)or@| (llink(rlink(p))<>p) then clobbered:=true; | |
> if clobbered then | |
> begin print_nl("Double-AVAIL list clobbered at "); | |
> print_int(q); goto done2; | |
> end; | |
> for q:=p to p+node_size(p)-1 do {mark all locations free} | |
> begin if free[q] then | |
> begin print_nl("Doubly free location at "); | |
> @.Doubly free location...@> | |
> print_int(q); goto done2; | |
> end; | |
> free[q]:=true; | |
> end; | |
> q:=p; p:=rlink(p); | |
2957,2964c3364,3372 | |
< p←mem_base; | |
< while p≤hi_mem_base do {node |p| should not be empty} | |
< begin if is_empty(p) then | |
< begin print_nl("Bad flag at "); print_int(p); | |
< end; | |
< while (p≤hi_mem_base) and not free[p] do incr(p); | |
< while (p≤hi_mem_base) and free[p] do incr(p); | |
< end | |
--- | |
> p:=mem_min; | |
> while p<=lo_mem_max do {node |p| should not be empty} | |
> begin if is_empty(p) then | |
> begin print_nl("Bad flag at "); print_int(p); | |
> @.Bad flag...@> | |
> end; | |
> while (p<=lo_mem_max) and not free[p] do incr(p); | |
> while (p<=lo_mem_max) and free[p] do incr(p); | |
> end | |
2968,2971c3376,3384 | |
< for p←mem_base to mem_end do | |
< if not free[p] and ((p>was_mem_end) or was_free[p]) then | |
< begin print_char(" "); print_int(p); | |
< end; | |
--- | |
> for p:=mem_min to lo_mem_max do | |
> if not free[p] and ((p>was_lo_max) or was_free[p]) then | |
> begin print_char(" "); print_int(p); | |
> end; | |
> for p:=hi_mem_min to mem_end do | |
> if not free[p] and | |
> ((p<was_hi_min) or (p>was_mem_end) or was_free[p]) then | |
> begin print_char(" "); print_int(p); | |
> end; | |
2975c3388 | |
< to node@@|p|?'' In doing so, it fetches |link| and |info| fields of |mem| | |
--- | |
> to node~|p|?'' In doing so, it fetches |link| and |info| fields of |mem| | |
2983,2993c3396,3416 | |
< @p debug procedure search_mem(@!p:pointer); {look for pointers to |p|} | |
< var q:pointer; {current position being searched} | |
< begin for q←mem_base to mem_end do | |
< begin if link(q)=p then | |
< begin print_nl("LINK("); print_int(q); print_char(")"); | |
< end; | |
< if info(q)=p then | |
< begin print_nl("INFO("); print_int(q); print_char(")"); | |
< end; | |
< end; | |
< @<Search |eqtb| for equivalents equal to |p|@>; | |
--- | |
> @p @!debug procedure search_mem(@!p:pointer); {look for pointers to |p|} | |
> var q:integer; {current position being searched} | |
> begin for q:=mem_min to lo_mem_max do | |
> begin if link(q)=p then | |
> begin print_nl("LINK("); print_int(q); print_char(")"); | |
> end; | |
> if info(q)=p then | |
> begin print_nl("INFO("); print_int(q); print_char(")"); | |
> end; | |
> end; | |
> for q:=hi_mem_min to mem_end do | |
> begin if link(q)=p then | |
> begin print_nl("LINK("); print_int(q); print_char(")"); | |
> end; | |
> if info(q)=p then | |
> begin print_nl("INFO("); print_int(q); print_char(")"); | |
> end; | |
> end; | |
> @<Search |eqtb| for equivalents equal to |p|@>; | |
> @<Search |save_stack| for equivalents that point to |p|@>; | |
> @<Search |hyph_list| for pointers to |p|@>; | |
2995a3419 | |
> | |
3022,3037c3446,3461 | |
< begin while p>null do | |
< begin if is_char_node(p) then | |
< begin if p≤mem_end then | |
< begin if font(p)≠font_in_short_display then | |
< begin print_esc(":"); | |
< if (font(p)<0)∨(font(p)>font_max) then | |
< print_char("*") | |
< else print_int(font_code[font(p)]); | |
< print_char(" "); font_in_short_display←font(p); | |
< end; | |
< print_ascii(qo(character(p))); | |
< end; | |
< end | |
< else @<Print a short indication of the contents of node |p|@>; | |
< p←link(p); | |
< end; | |
--- | |
> begin while p>mem_min do | |
> begin if is_char_node(p) then | |
> begin if p<=mem_end then | |
> begin if font(p)<>font_in_short_display then | |
> begin if (font(p)<font_base)or(font(p)>font_max) then | |
> print_char("*") | |
> @.*\relax@> | |
> else @<Print the font identifier for |font(p)|@>; | |
> print_char(" "); font_in_short_display:=font(p); | |
> end; | |
> print_ASCII(qo(character(p))); | |
> end; | |
> end | |
> else @<Print a short indication of the contents of node |p|@>; | |
> p:=link(p); | |
> end; | |
3039c3463 | |
< | |
--- | |
> | |
3043c3467 | |
< unset_node: print("[]"); | |
--- | |
> unset_node: print("[]"); | |
3045c3469 | |
< glue_node: if glue_ptr(p)≠zero_glue then print_char(" "); | |
--- | |
> glue_node: if glue_ptr(p)<>zero_glue then print_char(" "); | |
3049,3054c3473,3479 | |
< short_display(post_break(p));@/ | |
< n←replace_count(p); | |
< while n>0 do | |
< begin p←link(p); decr(n); | |
< end; | |
< end; | |
--- | |
> short_display(post_break(p));@/ | |
> n:=replace_count(p); | |
> while n>0 do | |
> begin if link(p)<>null then p:=link(p); | |
> decr(n); | |
> end; | |
> end; | |
3064,3068c3489,3493 | |
< else begin print_esc(":"); | |
< if (font(p)<0)∨(font(p)>font_max) then print_char("*") | |
< else print_int(font_code[font(p)]); | |
< print_char(" "); print_ascii(qo(character(p))); | |
< end; | |
--- | |
> else begin if (font(p)<font_base)or(font(p)>font_max) then print_char("*") | |
> @.*\relax@> | |
> else @<Print the font identifier for |font(p)|@>; | |
> print_char(" "); print_ASCII(qo(character(p))); | |
> end; | |
3073c3498 | |
< if (p<hi_mem_base)∨(p>mem_end) then print_esc("CLOBBERED.") | |
--- | |
> if (p<hi_mem_min)or(p>mem_end) then print_esc("CLOBBERED.") | |
3079a3505 | |
> @.*\relax@> | |
3086c3512 | |
< {prints a glue component} | |
--- | |
> {prints a glue component} | |
3088c3514 | |
< if (order<normal)∨(order>filll) then print("foul") | |
--- | |
> if (order<normal)or(order>filll) then print("foul") | |
3090,3095c3516,3521 | |
< begin print("fil"); | |
< while order>fil do | |
< begin print_char("l"); decr(order); | |
< end; | |
< end | |
< else if s≠0 then print(s); | |
--- | |
> begin print("fil"); | |
> while order>fil do | |
> begin print_char("l"); decr(order); | |
> end; | |
> end | |
> else if s<>0 then print(s); | |
3100,3111c3526,3538 | |
< @p procedure print_spec(@!p:pointer;@!s:str_number); | |
< {prints a glue specification} | |
< begin if (p<mem_base)∨(p≥hi_mem_base) then print_char("*") | |
< else begin print_scaled(width(p)); | |
< if s≠0 then print(s); | |
< if stretch(p)≠0 then | |
< begin print(" plus "); print_glue(stretch(p),stretch_order(p),s); | |
< end; | |
< if shrink(p)≠0 then | |
< begin print(" minus "); print_glue(shrink(p),shrink_order(p),s); | |
< end; | |
< end; | |
--- | |
> @p procedure print_spec(@!p:integer;@!s:str_number); | |
> {prints a glue specification} | |
> begin if (p<mem_min)or(p>=lo_mem_max) then print_char("*") | |
> @.*\relax@> | |
> else begin print_scaled(width(p)); | |
> if s<>0 then print(s); | |
> if stretch(p)<>0 then | |
> begin print(" plus "); print_glue(stretch(p),stretch_order(p),s); | |
> end; | |
> if shrink(p)<>0 then | |
> begin print(" minus "); print_glue(shrink(p),shrink_order(p),s); | |
> end; | |
> end; | |
3115c3542 | |
< docu\-mentation. | |
--- | |
> documentation. | |
3129,3130c3556,3557 | |
< begin append_char("."); show_node_list(#); flush_char; | |
< end {|str_room| need not be checked; see |show_box| below} | |
--- | |
> begin append_char("."); show_node_list(#); flush_char; | |
> end {|str_room| need not be checked; see |show_box| below} | |
3139c3566 | |
< @<Globals...@>= | |
--- | |
> @<Glob...@>= | |
3155c3582 | |
< @p procedure show_node_list(@!p:pointer); {prints a node list symbolically} | |
--- | |
> @p procedure show_node_list(@!p:integer); {prints a node list symbolically} | |
3157a3585 | |
> @!g:real; {a glue ratio, as a floating point number} | |
3159,3174c3587,3604 | |
< begin if p>null then print("[]"); | |
< {indicate that there's been some truncation} | |
< return; | |
< end; | |
< n←0; | |
< while p>null do | |
< begin print_ln; print_current_string; {display the nesting history} | |
< if p>mem_end then {pointer out of range} | |
< begin print("Bad link, display aborted."); return; | |
< end; | |
< incr(n); if n>breadth_max then {time to stop} | |
< begin print("etc."); return; | |
< end; | |
< @<Display node |p|@>; | |
< p←link(p); | |
< end; | |
--- | |
> begin if p>null then print(" []"); | |
> {indicate that there's been some truncation} | |
> return; | |
> end; | |
> n:=0; | |
> while p>mem_min do | |
> begin print_ln; print_current_string; {display the nesting history} | |
> if p>mem_end then {pointer out of range} | |
> begin print("Bad link, display aborted."); return; | |
> @.Bad link...@> | |
> end; | |
> incr(n); if n>breadth_max then {time to stop} | |
> begin print("etc."); return; | |
> @.etc@> | |
> end; | |
> @<Display node |p|@>; | |
> p:=link(p); | |
> end; | |
3180,3195c3610,3625 | |
< else case type(p) of | |
< hlist_node,vlist_node,unset_node: @<Display box |p|@>; | |
< rule_node: @<Display rule |p|@>; | |
< ins_node: @<Display insertion |p|@>; | |
< whatsit_node: @<Display the whatsit node |p|@>; | |
< glue_node: @<Display glue |p|@>; | |
< kern_node: @<Display kern |p|@>; | |
< math_node: @<Display math node |p|@>; | |
< ligature_node: @<Display ligature |p|@>; | |
< penalty_node: @<Display penalty |p|@>; | |
< disc_node: @<Display discretionary |p|@>; | |
< mark_node: @<Display mark |p|@>; | |
< adjust_node: @<Display adjustment |p|@>; | |
< @t\4@>@<Cases of |show_node_list| that arise in mlists only@>@; | |
< othercases print("Unknown node type!") | |
< endcases | |
--- | |
> else case type(p) of | |
> hlist_node,vlist_node,unset_node: @<Display box |p|@>; | |
> rule_node: @<Display rule |p|@>; | |
> ins_node: @<Display insertion |p|@>; | |
> whatsit_node: @<Display the whatsit node |p|@>; | |
> glue_node: @<Display glue |p|@>; | |
> kern_node: @<Display kern |p|@>; | |
> math_node: @<Display math node |p|@>; | |
> ligature_node: @<Display ligature |p|@>; | |
> penalty_node: @<Display penalty |p|@>; | |
> disc_node: @<Display discretionary |p|@>; | |
> mark_node: @<Display mark |p|@>; | |
> adjust_node: @<Display adjustment |p|@>; | |
> @t\4@>@<Cases of |show_node_list| that arise in mlists only@>@; | |
> othercases print("Unknown node type!") | |
> endcases | |
3204,3209c3634,3639 | |
< @<Display special fields of the unset node |p|@> | |
< else begin @<Display the value of |glue_set(p)|@>; | |
< if shift_amount(p)≠0 then | |
< begin print(", shifted "); print_scaled(shift_amount(p)); | |
< end; | |
< end; | |
--- | |
> @<Display special fields of the unset node |p|@> | |
> else begin @<Display the value of |glue_set(p)|@>; | |
> if shift_amount(p)<>0 then | |
> begin print(", shifted "); print_scaled(shift_amount(p)); | |
> end; | |
> end; | |
3214,3219c3644,3653 | |
< begin if span_count(p)≠min_quarterword then | |
< begin print(" ("); print_int(qo(span_count(p))+1); | |
< print(" columns)"); | |
< end; | |
< print(", stretch "); print_glue(glue_stretch(p),glue_order(p),0); | |
< print(", shrink "); print_glue(glue_shrink(p),glue_sign(p),0); | |
--- | |
> begin if span_count(p)<>min_quarterword then | |
> begin print(" ("); print_int(qo(span_count(p))+1); | |
> print(" columns)"); | |
> end; | |
> if glue_stretch(p)<>0 then | |
> begin print(", stretch "); print_glue(glue_stretch(p),glue_order(p),0); | |
> end; | |
> if glue_shrink(p)<>0 then | |
> begin print(", shrink "); print_glue(glue_shrink(p),glue_sign(p),0); | |
> end; | |
3223c3657,3664 | |
< a structured type instead of an ordinary |real|. | |
--- | |
> a structured type instead of an ordinary |real|. Note that this routine | |
> should avoid arithmetic errors even if the |glue_set| field holds an | |
> arbitrary random value. The following code assumes that a properly | |
> formed nonzero |real| number has absolute value $2^{20}$ or more when | |
> it is regarded as an integer; this precaution was adequate to prevent | |
> floating point underflow on the author's computer. | |
> @^system dependencies@> | |
> @^dirty \PASCAL@> | |
3226,3235c3667,3679 | |
< if glue_set(p)≠0 then | |
< begin print(", glue set "); | |
< if glue_sign(p)=shrinking then print("- "); | |
< if abs(glue_set(p))>20000.0 then | |
< begin if glue_set(p)>0 then print_char(">") | |
< else print("< -"); | |
< print_glue(20000*unity,glue_order(p),0); | |
< end | |
< else print_glue(round(glue_set(p)*unity),glue_order(p),0); | |
< end | |
--- | |
> g:=float(glue_set(p)); | |
> if (g<>float_constant(0))and(glue_sign(p)<>normal) then | |
> begin print(", glue set "); | |
> if glue_sign(p)=shrinking then print("- "); | |
> if abs(mem[p+glue_offset].int)<@'4000000 then print("?.?") | |
> else if abs(g)>float_constant(20000) then | |
> begin if g>float_constant(0) then print_char(">") | |
> else print("< -"); | |
> print_glue(20000*unity,glue_order(p),0); | |
> end | |
> else print_glue(round(unity*g),glue_order(p),0); | |
> @^real multiplication@> | |
> end | |
3244c3688,3691 | |
< print(", natural size "); print_scaled(width(p)); | |
--- | |
> print(", natural size "); print_scaled(height(p)); | |
> print("; split("); print_spec(split_top_ptr(p),0); | |
> print_char(","); print_scaled(depth(p)); | |
> print("); float cost "); print_int(float_cost(p)); | |
3249,3264c3696,3711 | |
< if subtype(p)≥a_leaders then @<Display leaders |p|@> | |
< else begin print_esc("glue"); | |
< if subtype(p)≠normal then | |
< begin print_char("("); | |
< if subtype(p)<cond_math_glue then | |
< print_skip_param(subtype(p)-1) | |
< else if subtype(p)=cond_math_glue then print_esc("non_script") | |
< else print_esc("mskip"); | |
< print_char(")"); | |
< end; | |
< if subtype(p)≠cond_math_glue then | |
< begin print_char(" "); | |
< if subtype(p)<cond_math_glue then print_spec(glue_ptr(p),0) | |
< else print_spec(glue_ptr(p),"mu"); | |
< end; | |
< end | |
--- | |
> if subtype(p)>=a_leaders then @<Display leaders |p|@> | |
> else begin print_esc("glue"); | |
> if subtype(p)<>normal then | |
> begin print_char("("); | |
> if subtype(p)<cond_math_glue then | |
> print_skip_param(subtype(p)-1) | |
> else if subtype(p)=cond_math_glue then print_esc("nonscript") | |
> else print_esc("mskip"); | |
> print_char(")"); | |
> end; | |
> if subtype(p)<>cond_math_glue then | |
> begin print_char(" "); | |
> if subtype(p)<cond_math_glue then print_spec(glue_ptr(p),0) | |
> else print_spec(glue_ptr(p),"mu"); | |
> end; | |
> end | |
3267c3714 | |
< begin print_char("\"); | |
--- | |
> begin print_esc(""); | |
3274,3279c3721,3732 | |
< @ @<Display kern |p|@>= | |
< if subtype(p)=normal then | |
< begin print_esc("kern"); print_scaled(width(p)); | |
< end | |
< else begin print_esc("mkern"); print_scaled(width(p)); print("mu"); | |
< end | |
--- | |
> @ An ``explicit'' kern value is indicated implicitly by an explicit space. | |
> | |
> @<Display kern |p|@>= | |
> if subtype(p)<>mu_glue then | |
> begin print_esc("kern"); | |
> if subtype(p)<>normal then print_char(" "); | |
> print_scaled(width(p)); | |
> if subtype(p)=acc_kern then print(" (for accent)"); | |
> @.for accent@> | |
> end | |
> else begin print_esc("mkern"); print_scaled(width(p)); print("mu"); | |
> end | |
3285,3287c3738,3740 | |
< if width(p)≠0 then | |
< begin print(", surrounded "); print_scaled(width(p)); | |
< end; | |
--- | |
> if width(p)<>0 then | |
> begin print(", surrounded "); print_scaled(width(p)); | |
> end; | |
3292,3293c3745,3748 | |
< font_in_short_display←font(lig_char(p)); | |
< short_display(lig_ptr(p)); print_char(")"); | |
--- | |
> if subtype(p)>1 then print_char("|"); | |
> font_in_short_display:=font(lig_char(p)); short_display(lig_ptr(p)); | |
> if odd(subtype(p)) then print_char("|"); | |
> print_char(")"); | |
3306,3309c3761,3763 | |
< begin print(" replacing "); print_int(replace_count(p)); | |
< end; | |
< if pre_break(p)=null then print(" (exhyphen)") | |
< else node_list_display(pre_break(p)); {recursive call} | |
--- | |
> begin print(" replacing "); print_int(replace_count(p)); | |
> end; | |
> node_list_display(pre_break(p)); {recursive call} | |
3325,3330c3779,3784 | |
< begin @<Assign the values |depth_threshold←show_box_depth| and | |
< |breadth_max←show_box_breadth|@>; | |
< if breadth_max≤0 then breadth_max←5; | |
< if pool_ptr+depth_threshold≥pool_size then | |
< depth_threshold←pool_size-pool_ptr-1; | |
< {now there's enough room for prefix string} | |
--- | |
> begin @<Assign the values |depth_threshold:=show_box_depth| and | |
> |breadth_max:=show_box_breadth|@>; | |
> if breadth_max<=0 then breadth_max:=5; | |
> if pool_ptr+depth_threshold>=pool_size then | |
> depth_threshold:=pool_size-pool_ptr-1; | |
> {now there's enough room for prefix string} | |
3333a3788 | |
> | |
3349c3804 | |
< of a token list that is losing one reference} | |
--- | |
> of a token list that is losing one reference} | |
3356a3812,3815 | |
> @d fast_delete_glue_ref(#)==@t@>@;@/ | |
> begin if glue_ref_count(#)=null then free_node(#,glue_spec_size) | |
> else decr(glue_ref_count(#)); | |
> end | |
3359,3361c3818 | |
< begin if glue_ref_count(p)=null then free_node(p,glue_spec_size) | |
< else decr(glue_ref_count(p)); | |
< end; | |
--- | |
> fast_delete_glue_ref(p); | |
3363a3821,3822 | |
> In practice, the nodes deleted are usually charnodes (about 2/3 of the time), | |
> and they are glue nodes in about half of the remaining cases. | |
3369,3398c3828,3860 | |
< begin while p≠null do | |
< begin q←link(p); | |
< if is_char_node(p) then free_avail(p) | |
< else begin case type(p) of | |
< hlist_node,vlist_node,unset_node: begin flush_node_list(list_ptr(p)); | |
< free_node(p,box_node_size); goto done; | |
< end; | |
< rule_node: begin free_node(p,rule_node_size); goto done; | |
< end; | |
< ins_node: begin flush_node_list(ins_ptr(p)); | |
< free_node(p,ins_node_size); goto done; | |
< end; | |
< whatsit_node: @<Wipe out the whatsit node |p| and |goto done|@>; | |
< glue_node: begin delete_glue_ref(glue_ptr(p)); | |
< flush_node_list(leader_ptr(p)); | |
< end; | |
< kern_node,math_node,penalty_node: do_nothing; | |
< ligature_node: flush_node_list(lig_ptr(p)); | |
< mark_node: delete_token_ref(mark_ptr(p)); | |
< disc_node: begin flush_node_list(pre_break(p)); | |
< flush_node_list(post_break(p)); | |
< end; | |
< adjust_node: flush_node_list(adjust_ptr(p)); | |
< othercases confusion("flushing") | |
< @:confusion flushing}{\quad flushing@> | |
< endcases;@/ | |
< free_node(p,small_node_size); | |
< done:end; | |
< p←q; | |
< end; | |
--- | |
> begin while p<>null do | |
> @^inner loop@> | |
> begin q:=link(p); | |
> if is_char_node(p) then free_avail(p) | |
> else begin case type(p) of | |
> hlist_node,vlist_node,unset_node: begin flush_node_list(list_ptr(p)); | |
> free_node(p,box_node_size); goto done; | |
> end; | |
> rule_node: begin free_node(p,rule_node_size); goto done; | |
> end; | |
> ins_node: begin flush_node_list(ins_ptr(p)); | |
> delete_glue_ref(split_top_ptr(p)); | |
> free_node(p,ins_node_size); goto done; | |
> end; | |
> whatsit_node: @<Wipe out the whatsit node |p| and |goto done|@>; | |
> glue_node: begin fast_delete_glue_ref(glue_ptr(p)); | |
> if leader_ptr(p)<>null then flush_node_list(leader_ptr(p)); | |
> end; | |
> kern_node,math_node,penalty_node: do_nothing; | |
> ligature_node: flush_node_list(lig_ptr(p)); | |
> mark_node: delete_token_ref(mark_ptr(p)); | |
> disc_node: begin flush_node_list(pre_break(p)); | |
> flush_node_list(post_break(p)); | |
> end; | |
> adjust_node: flush_node_list(adjust_ptr(p)); | |
> @t\4@>@<Cases of |flush_node_list| that arise in mlists only@>@; | |
> othercases confusion("flushing") | |
> @:this can't happen flushing}{\quad flushing@> | |
> endcases;@/ | |
> free_node(p,small_node_size); | |
> done:end; | |
> p:=q; | |
> end; | |
3399a3862 | |
> | |
3401,3406c3864,3868 | |
< Another recursive operation on boxes is sometimes needed: The procedure | |
< @^recursion@> | |
< |copy_node_list| returns a pointer to another node list that has the | |
< same structure and meaning as the original. Note that since glue | |
< specifications and token lists have reference counts, we need not | |
< make copies of them. Reference counts can never get too large to fit in a | |
--- | |
> Another recursive operation that acts on boxes is sometimes needed: The | |
> procedure |copy_node_list| returns a pointer to another node list that has | |
> the same structure and meaning as the original. Note that since glue | |
> specifications and token lists have reference counts, we need not make | |
> copies of them. Reference counts can never get too large to fit in a | |
3408a3871 | |
> @^recursion@> | |
3421a3885 | |
> @^data structure assumptions@> | |
3424c3888 | |
< node list that starts at |p| and returns a pointer to the new list} | |
--- | |
> node list that starts at |p| and returns a pointer to the new list} | |
3429,3435c3893,3899 | |
< begin h←get_avail; q←h; | |
< while p≠null do | |
< begin @<Make a copy of node |p| in node |r|@>; | |
< link(q)←r; q←r; p←link(p); | |
< end; | |
< link(q)←null; q←link(h); free_avail(h); | |
< copy_node_list←q; | |
--- | |
> begin h:=get_avail; q:=h; | |
> while p<>null do | |
> begin @<Make a copy of node |p| in node |r|@>; | |
> link(q):=r; q:=r; p:=link(p); | |
> end; | |
> link(q):=null; q:=link(h); free_avail(h); | |
> copy_node_list:=q; | |
3439,3440c3903,3904 | |
< words←1; {this setting occurs in more branches than any other} | |
< if is_char_node(p) then r←get_avail | |
--- | |
> words:=1; {this setting occurs in more branches than any other} | |
> if is_char_node(p) then r:=get_avail | |
3442c3906 | |
< of initial words not yet copied@>; | |
--- | |
> of initial words not yet copied@>; | |
3444,3445c3908,3909 | |
< begin decr(words); mem[r+words]←mem[p+words]; | |
< end | |
--- | |
> begin decr(words); mem[r+words]:=mem[p+words]; | |
> end | |
3449,3458c3913,3924 | |
< hlist_node,vlist_node,unset_node: begin r←get_node(box_node_size); | |
< mem[r+6]←mem[p+6]; mem[r+5]←mem[p+5]; {copy the last two words} | |
< list_ptr(r)←copy_node_list(list_ptr(p)); {this affects |mem[r+5]|} | |
< words←5; | |
< end; | |
< rule_node: begin r←get_node(rule_node_size); words←rule_node_size; | |
< end; | |
< ins_node: begin r←get_node(ins_node_size); | |
< ins_ptr(r)←copy_node_list(ins_ptr(p)); words←ins_node_size-1; | |
< end; | |
--- | |
> hlist_node,vlist_node,unset_node: begin r:=get_node(box_node_size); | |
> mem[r+6]:=mem[p+6]; mem[r+5]:=mem[p+5]; {copy the last two words} | |
> list_ptr(r):=copy_node_list(list_ptr(p)); {this affects |mem[r+5]|} | |
> words:=5; | |
> end; | |
> rule_node: begin r:=get_node(rule_node_size); words:=rule_node_size; | |
> end; | |
> ins_node: begin r:=get_node(ins_node_size); mem[r+4]:=mem[p+4]; | |
> add_glue_ref(split_top_ptr(p)); | |
> ins_ptr(r):=copy_node_list(ins_ptr(p)); {this affects |mem[r+4]|} | |
> words:=ins_node_size-1; | |
> end; | |
3460,3480c3926,3946 | |
< point to it; set |words| to the number of initial words not yet copied@>; | |
< glue_node: begin r←get_node(small_node_size); add_glue_ref(glue_ptr(p)); | |
< glue_ptr(r)←glue_ptr(p); leader_ptr(r)←copy_node_list(leader_ptr(p)); | |
< end; | |
< kern_node,math_node,penalty_node: begin r←get_node(small_node_size); | |
< words←small_node_size; | |
< end; | |
< ligature_node: begin r←get_node(small_node_size); | |
< mem[lig_char(r)]←mem[lig_char(p)]; {copy |font| and |character|} | |
< lig_ptr(r)←copy_node_list(lig_ptr(p)); | |
< end; | |
< disc_node: begin r←get_node(small_node_size); | |
< pre_break(r)←copy_node_list(pre_break(p)); | |
< post_break(r)←copy_node_list(post_break(p)); | |
< end; | |
< mark_node: begin r←get_node(small_node_size); add_token_ref(mark_ptr(p)); | |
< words←small_node_size; | |
< end; | |
< adjust_node: begin r←get_node(small_node_size); | |
< adjust_ptr(r)←copy_node_list(adjust_ptr(p)); | |
< end; | |
--- | |
> point to it; set |words| to the number of initial words not yet copied@>; | |
> glue_node: begin r:=get_node(small_node_size); add_glue_ref(glue_ptr(p)); | |
> glue_ptr(r):=glue_ptr(p); leader_ptr(r):=copy_node_list(leader_ptr(p)); | |
> end; | |
> kern_node,math_node,penalty_node: begin r:=get_node(small_node_size); | |
> words:=small_node_size; | |
> end; | |
> ligature_node: begin r:=get_node(small_node_size); | |
> mem[lig_char(r)]:=mem[lig_char(p)]; {copy |font| and |character|} | |
> lig_ptr(r):=copy_node_list(lig_ptr(p)); | |
> end; | |
> disc_node: begin r:=get_node(small_node_size); | |
> pre_break(r):=copy_node_list(pre_break(p)); | |
> post_break(r):=copy_node_list(post_break(p)); | |
> end; | |
> mark_node: begin r:=get_node(small_node_size); add_token_ref(mark_ptr(p)); | |
> words:=small_node_size; | |
> end; | |
> adjust_node: begin r:=get_node(small_node_size); | |
> adjust_ptr(r):=copy_node_list(adjust_ptr(p)); | |
> end; {|words=1=small_node_size-1|} | |
3482c3948 | |
< @:confusion copying}{\quad copying@> | |
--- | |
> @:this can't happen copying}{\quad copying@> | |
3483a3950 | |
> | |
3489,3490c3956,3957 | |
< e.g., `\.{\\chcode \`\\\${} = 3}' to make \.{\char'44} a math delimiter, | |
< and the command code |math_delim| is equal to@@3. Some other codes have | |
--- | |
> e.g., `\.{\\catcode \`\\\${} = 3}' to make \.{\char'44} a math delimiter, | |
> and the command code |math_shift| is equal to~3. Some other codes have | |
3496,3497c3963,3964 | |
< ``chcode'' commands, several of which are used also as ordinary commands | |
< when the chcode cannot emerge from \TeX's scanning routine. | |
--- | |
> ``catcode'' commands, several of which share their numeric codes with | |
> ordinary commands when the catcode cannot emerge from \TeX's scanning routine. | |
3499,3505c3966,3973 | |
< @d escape=0 {escape delimiter (called \.{\\} in the \TeX\ manual)} | |
< @d relax=0 { do nothing ( \.{\\relax} )} | |
< @d left_brace=1 {beginning of a group ( \.{\{} )} | |
< @d right_brace=2 {ending of a group ( \.{\}} )} | |
< @d math_delim=3 {mathematics delimiter ( \.{\$} )} | |
< @d tab_mark=4 {alignment delimiter ( \.{\&}, \.{\\span} )} | |
< @d car_ret=5 {carriage return ( |carriage_return|, also \.{\\cr} )} | |
--- | |
> @d escape=0 {escape delimiter (called \.\\ in {\sl The \TeX book\/})} | |
> @:TeXbook}{\sl The \TeX book@> | |
> @d relax=0 {do nothing ( \.{\\relax} )} | |
> @d left_brace=1 {beginning of a group ( \.\{ )} | |
> @d right_brace=2 {ending of a group ( \.\} )} | |
> @d math_shift=3 {mathematics shift character ( \.\$ )} | |
> @d tab_mark=4 {alignment delimiter ( \.\&, \.{\\span} )} | |
> @d car_ret=5 {end of line ( |carriage_return|, \.{\\cr}, \.{\\crcr} )} | |
3507c3975 | |
< @d mac_param=6 {macro parameter symbol ( \.{\#} )} | |
--- | |
> @d mac_param=6 {macro parameter symbol ( \.\# )} | |
3509,3511c3977,3979 | |
< @d sub_mark=8 {subscript ( \.{\char'176} )} | |
< @d ignore=9 {characters to ignore ( \.{\^\^J} )} | |
< @d endv=9 {end of \<v↓j> list in alignment template} | |
--- | |
> @d sub_mark=8 {subscript ( \.{\char'137} )} | |
> @d ignore=9 {characters to ignore ( \.{\^\^@@} )} | |
> @d endv=9 {end of \<v_j> list in alignment template} | |
3515c3983 | |
< @d active_char=13 {characters that invoke macros ( \.{\^\^[} )} | |
--- | |
> @d active_char=13 {characters that invoke macros ( \.{\char`\~} )} | |
3518c3986 | |
< @d end_line=14 {characters that introduce comments ( \.{\char'45} )} | |
--- | |
> @d comment=14 {characters that introduce comments ( \.\% )} | |
3520c3988 | |
< @d stop=14 {end of input ( \.{\\end}, \.{\\dump} )} | |
--- | |
> @d stop=14 {end of job ( \.{\\end}, \.{\\dump} )} | |
3523c3991 | |
< @d max_char_code=15 {largest chcode for individual characters} | |
--- | |
> @d max_char_code=15 {largest catcode for individual characters} | |
3525c3993,3995 | |
< @ Next are the ordinary run-of-the-mill command codes. | |
--- | |
> @ Next are the ordinary run-of-the-mill command codes. Codes that are | |
> |min_internal| or more represent internal quantities that might be | |
> expanded by `\.{\\the}'. | |
3530,3538c4000,4009 | |
< @d input=19 {input a source file ( \.{\\input} )} | |
< @d xray=20 {peek inside of \TeX\ ( \.{\\show}, \.{\\showbox}, etc.@@)} | |
< @d make_box=21 {make a box ( \.{\\box}, \.{\\copy}, \.{\\hbox}, etc.@@)} | |
< @d hmove=22 {horizontal motion ( \.{\\moveleft}, \.{\\moveright} )} | |
< @d vmove=23 {vertical motion ( \.{\\raise}, \.{\\lower} )} | |
< @d unbox=24 {unglue a box ( \.{\\unbox} )} | |
< @d unskip=25 {nullify glue ( \.{\\unskip} )} | |
< @d hskip=26 {horizontal glue ( \.{\\hskip}, \.{\\hfil}, etc.@@)} | |
< @d vskip=27 {vertical glue ( \.{\\vskip}, \.{\\vfil}, etc.@@)} | |
--- | |
> @d xray=19 {peek inside of \TeX\ ( \.{\\show}, \.{\\showbox}, etc.~)} | |
> @d make_box=20 {make a box ( \.{\\box}, \.{\\copy}, \.{\\hbox}, etc.~)} | |
> @d hmove=21 {horizontal motion ( \.{\\moveleft}, \.{\\moveright} )} | |
> @d vmove=22 {vertical motion ( \.{\\raise}, \.{\\lower} )} | |
> @d un_hbox=23 {unglue a box ( \.{\\unhbox}, \.{\\unhcopy} )} | |
> @d un_vbox=24 {unglue a box ( \.{\\unvbox}, \.{\\unvcopy} )} | |
> @d remove_item=25 {nullify last item ( \.{\\unpenalty}, | |
> \.{\\unkern}, \.{\\unskip} )} | |
> @d hskip=26 {horizontal glue ( \.{\\hskip}, \.{\\hfil}, etc.~)} | |
> @d vskip=27 {vertical glue ( \.{\\vskip}, \.{\\vfil}, etc.~)} | |
3540c4011 | |
< @d kern=29 {fixed space ( \.{kern})} | |
--- | |
> @d kern=29 {fixed space ( \.{\\kern})} | |
3542c4013 | |
< @d leader_ship=31 {use a box ( \.{\\shipout}, \.{\\leaders}, etc.@@)} | |
--- | |
> @d leader_ship=31 {use a box ( \.{\\shipout}, \.{\\leaders}, etc.~)} | |
3550,3568c4021,4039 | |
< @d ignore_space=39 {gobble |spacer| tokens ( \.{\\ignorespace} )} | |
< @d break_penalty=40 {additional badness ( \.{\\penalty}, \.{\\dpenalty}@@)} | |
< @d start_par=41 {begin paragraph ( \.{\\indent}, \.{\\noindent} )} | |
< @d ital_corr=42 {italic correction ( \.{\\/} )} | |
< @d accent=43 {attach accent in text ( \.{\\accent} )} | |
< @d math_accent=44 {attach accent in math ( \.{\\mathaccent} )} | |
< @d discretionary=45 {discretionary texts ( \.{\\discretionary} )} | |
< @d eq_no=46 {equation number ( \.{\\eqno}, \.{\\leqno} )} | |
< @d left_right=47 {variable delimiter ( \.{\\left}, \.{\\right} )} | |
< @d math_comp=48 {component of formula ( \.{\\mathbin}, etc.@@)} | |
< @d limit_switch=49 {diddle limit conventions ( \.{\\limitswitch}@@)} | |
< @d above=50 {generalized fraction ( \.{\\above}, \.{\\atop}, etc.@@)} | |
< @d math_style=51 {style specification ( \.{\\displaystyle}, etc.@@)} | |
< @d non_script=52 {conditional math glue ( \.{\\nonscript} )} | |
< @d vcenter=53 {vertically center a vbox ( \.{\\vcenter} )} | |
< @d case_shift=54 {force specific case ( \.{\\lowercase}, \.{\\uppercase}@@)} | |
< @d if_test=55 {select conditional text ( \.{\\if}, \.{\\ifeven}, etc.@@)} | |
< @d case_branch=56 {choose numbered text ( \.{\\case} )} | |
< @d else_code=57 {delimiter for conditionals ( \.{\\else} )} | |
--- | |
> @d ignore_spaces=39 {gobble |spacer| tokens ( \.{\\ignorespaces} )} | |
> @d after_assignment=40 {save till assignment is done ( \.{\\afterassignment} )} | |
> @d after_group=41 {save till group is done ( \.{\\aftergroup} )} | |
> @d break_penalty=42 {additional badness ( \.{\\penalty} )} | |
> @d start_par=43 {begin paragraph ( \.{\\indent}, \.{\\noindent} )} | |
> @d ital_corr=44 {italic correction ( \.{\\/} )} | |
> @d accent=45 {attach accent in text ( \.{\\accent} )} | |
> @d math_accent=46 {attach accent in math ( \.{\\mathaccent} )} | |
> @d discretionary=47 {discretionary texts ( \.{\\-}, \.{\\discretionary} )} | |
> @d eq_no=48 {equation number ( \.{\\eqno}, \.{\\leqno} )} | |
> @d left_right=49 {variable delimiter ( \.{\\left}, \.{\\right} )} | |
> @d math_comp=50 {component of formula ( \.{\\mathbin}, etc.~)} | |
> @d limit_switch=51 {diddle limit conventions ( \.{\\displaylimits}, etc.~)} | |
> @d above=52 {generalized fraction ( \.{\\above}, \.{\\atop}, etc.~)} | |
> @d math_style=53 {style specification ( \.{\\displaystyle}, etc.~)} | |
> @d math_choice=54 {choice specification ( \.{\\mathchoice} )} | |
> @d non_script=55 {conditional math glue ( \.{\\nonscript} )} | |
> @d vcenter=56 {vertically center a vbox ( \.{\\vcenter} )} | |
> @d case_shift=57 {force specific case ( \.{\\lowercase}, \.{\\uppercase}~)} | |
3570,3581c4041,4055 | |
< @d extension=59 {extensions to \TeX\ ( \.{\\send}, \.{\\open}, etc.@@)} | |
< @d group_begin=60 {begin local grouping ( \.{\\groupbegin} )} | |
< @d group_end=61 {end local grouping ( \.{\\groupend} )} | |
< @d omit=62 {omit alignment template ( \.{\\omit} )} | |
< @d ex_space=63 {explicit space ( \.{\\\ } )} | |
< @d radical=64 {square root and similar signs ( \.{\\radical} )} | |
< @d the=66 {convert to arabic or roman numerals ( \.{\\number} )} | |
< @d number=65 {read a parameter or register ( \.{\\the}, \.{\\minus} )} | |
< @d register=67 {read a register ( \.{\\count}, \.{\\dimen}, \.{\\skip} )} | |
< @d last_skip=68 {most recent glue ( \.{\\lastskip} )} | |
< @d set_aux=69 {specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )} | |
< @d max_non_prefixed_command=69 {largest command code that can't be \.{\\global}} | |
--- | |
> @d extension=59 {extensions to \TeX\ ( \.{\\write}, \.{\\special}, etc.~)} | |
> @d in_stream=60 {files for reading ( \.{\\openin}, \.{\\closein} )} | |
> @d begin_group=61 {begin local grouping ( \.{\\begingroup} )} | |
> @d end_group=62 {end local grouping ( \.{\\endgroup} )} | |
> @d omit=63 {omit alignment template ( \.{\\omit} )} | |
> @d ex_space=64 {explicit space ( \.{\\\ } )} | |
> @d no_boundary=65 {suppress boundary ligatures ( \.{\\noboundary} )} | |
> @d radical=66 {square root and similar signs ( \.{\\radical} )} | |
> @d end_cs_name=67 {end control sequence ( \.{\\endcsname} )} | |
> @d min_internal=68 {the smallest code that can follow \.{\\the}} | |
> @d char_given=68 {character code defined by \.{\\chardef}} | |
> @d math_given=69 {math code defined by \.{\\mathchardef}} | |
> @d last_item=70 {most recent item ( \.{\\lastpenalty}, | |
> \.{\\lastkern}, \.{\\lastskip} )} | |
> @d max_non_prefixed_command=70 {largest command code that can't be \.{\\global}} | |
3584a4059,4060 | |
> Codes that are |max_internal| or less represent internal quantities | |
> that might be expanded by `\.{\\the}'. | |
3586,3612c4062,4095 | |
< @d assign_toks=70 {special token list ( \.{\\output}, \.{\\everypar} )} | |
< @d assign_int=71 {user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.@@)} | |
< @d assign_dimen=72 {user-defined length ( \.{\\hsize}, etc.@@)} | |
< @d assign_glue=73 {user-defined glue ( \.{\\baselineskip}, etc.@@)} | |
< @d assign_tex_info=74 {user-defined font parameter ( \.{\\texinfo} )} | |
< @d hang_indent=75 {specify hanging indentation ( \.{\\hangindent} )} | |
< @d def_code=76 {define a character code ( \.{\\chcode}, etc.@@)} | |
< @d def_family=77 {declare math fonts ( \.{\\textfont}, etc.@@)} | |
< @d set_font=78 {set current font ( \.{\\:} )} | |
< @d set_family=79 {set current family ( \.{\\fam} )} | |
< @d prefix=80 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )} | |
< @d let=81 {alternative name for a control sequence ( \.{\\let} )} | |
< @d def=82 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )} | |
< @d def_font=83 {define a font file ( \.{\\font} )} | |
< @d set_register=84 {set a register ( \.{\\setcount}, \.{\\setdimen}, | |
< \.{\\setskip} )} | |
< @d adv_register=85 {advance a register ( \.{\\advcount}, \.{\\advdimen}, | |
< \.{\\advskip} )} | |
< @d mult_register=86 {multiply a register ( \.{\\multcount}, \.{\\multdimen}, | |
< \.{\\multskip} )} | |
< @d div_register=87 {divide a register ( \.{\\divcount}, \.{\\divdimen}, | |
< \.{\\divskip} )} | |
< @d set_box=88 {set a box ( \.{\\setbox} )} | |
< @d set_shape=89 {specify fancy paragraph shape ( \.{\\parshape} )} | |
< @d hyph_data=90 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )} | |
< @d set_interaction=91 {define level of interaction ( \.{\\batchmode}, etc.@@)} | |
< @d max_command=91 {the largest command code seen at |big_switch|} | |
--- | |
> @d toks_register=71 {token list register ( \.{\\toks} )} | |
> @d assign_toks=72 {special token list ( \.{\\output}, \.{\\everypar}, etc.~)} | |
> @d assign_int=73 {user-defined integer ( \.{\\tolerance}, \.{\\day}, etc.~)} | |
> @d assign_dimen=74 {user-defined length ( \.{\\hsize}, etc.~)} | |
> @d assign_glue=75 {user-defined glue ( \.{\\baselineskip}, etc.~)} | |
> @d assign_mu_glue=76 {user-defined muglue ( \.{\\thinmuskip}, etc.~)} | |
> @d assign_font_dimen=77 {user-defined font dimension ( \.{\\fontdimen} )} | |
> @d assign_font_int=78 {user-defined font integer ( \.{\\hyphenchar}, | |
> \.{\\skewchar} )} | |
> @d set_aux=79 {specify state info ( \.{\\spacefactor}, \.{\\prevdepth} )} | |
> @d set_prev_graf=80 {specify state info ( \.{\\prevgraf} )} | |
> @d set_page_dimen=81 {specify state info ( \.{\\pagegoal}, etc.~)} | |
> @d set_page_int=82 {specify state info ( \.{\\deadcycles}, | |
> \.{\\insertpenalties} )} | |
> @d set_box_dimen=83 {change dimension of box ( \.{\\wd}, \.{\\ht}, \.{\\dp} )} | |
> @d set_shape=84 {specify fancy paragraph shape ( \.{\\parshape} )} | |
> @d def_code=85 {define a character code ( \.{\\catcode}, etc.~)} | |
> @d def_family=86 {declare math fonts ( \.{\\textfont}, etc.~)} | |
> @d set_font=87 {set current font ( font identifiers )} | |
> @d def_font=88 {define a font file ( \.{\\font} )} | |
> @d register=89 {internal register ( \.{\\count}, \.{\\dimen}, etc.~)} | |
> @d max_internal=89 {the largest code that can follow \.{\\the}} | |
> @d advance=90 {advance a register or parameter ( \.{\\advance} )} | |
> @d multiply=91 {multiply a register or parameter ( \.{\\multiply} )} | |
> @d divide=92 {divide a register or parameter ( \.{\\divide} )} | |
> @d prefix=93 {qualify a definition ( \.{\\global}, \.{\\long}, \.{\\outer} )} | |
> @d let=94 {assign a command code ( \.{\\let}, \.{\\futurelet} )} | |
> @d shorthand_def=95 {code definition ( \.{\\chardef}, \.{\\countdef}, etc.~)} | |
> @d read_to_cs=96 {read into a control sequence ( \.{\\read} )} | |
> @d def=97 {macro definition ( \.{\\def}, \.{\\gdef}, \.{\\xdef}, \.{\\edef} )} | |
> @d set_box=98 {set a box ( \.{\\setbox} )} | |
> @d hyph_data=99 {hyphenation data ( \.{\\hyphenation}, \.{\\patterns} )} | |
> @d set_interaction=100 {define level of interaction ( \.{\\batchmode}, etc.~)} | |
> @d max_command=100 {the largest command code seen at |big_switch|} | |
3616c4099,4100 | |
< than |max_command| so that their special nature is easily discernable. | |
--- | |
> than |max_command| so that their special nature is easily discernible. | |
> The ``expandable'' commands come first. | |
3619,3627c4103,4122 | |
< @d top_bot_mark=max_command+2 {inserted mark ( \.{\\topmark}, etc.\ } | |
< @d call=max_command+3 {non-long, non-outer control sequence} | |
< @d long_call=max_command+4 {long, non-outer control sequence} | |
< @d outer_call=max_command+5 {non-long, outer control sequence} | |
< @d long_outer_call=max_command+6 {long, outer control sequence} | |
< @d glue_ref=max_command+7 {pointer to a glue specification} | |
< @d shape_ref=max_command+8 {pointer to a parshape specification} | |
< @d box_ref=max_command+9 {pointer to a box node, or |null|} | |
< @d data=max_command+10 {the equivalent is simply a halfword number} | |
--- | |
> @d expand_after=max_command+2 {special expansion ( \.{\\expandafter} )} | |
> @d no_expand=max_command+3 {special nonexpansion ( \.{\\noexpand} )} | |
> @d input=max_command+4 {input a source file ( \.{\\input}, \.{\\endinput} )} | |
> @d if_test=max_command+5 {conditional text ( \.{\\if}, \.{\\ifcase}, etc.~)} | |
> @d fi_or_else=max_command+6 {delimiters for conditionals ( \.{\\else}, etc.~)} | |
> @d cs_name=max_command+7 {make a control sequence from tokens ( \.{\\csname} )} | |
> @d convert=max_command+8 {convert to text ( \.{\\number}, \.{\\string}, etc.~)} | |
> @d the=max_command+9 {expand an internal quantity ( \.{\\the} )} | |
> @d top_bot_mark=max_command+10 {inserted mark ( \.{\\topmark}, etc.~)} | |
> @d call=max_command+11 {non-long, non-outer control sequence} | |
> @d long_call=max_command+12 {long, non-outer control sequence} | |
> @d outer_call=max_command+13 {non-long, outer control sequence} | |
> @d long_outer_call=max_command+14 {long, outer control sequence} | |
> @d end_template=max_command+15 {end of an alignment template} | |
> @d dont_expand=max_command+16 {the following token was marked by \.{\\noexpand}} | |
> @d glue_ref=max_command+17 {the equivalent points to a glue specification} | |
> @d shape_ref=max_command+18 {the equivalent points to a parshape specification} | |
> @d box_ref=max_command+19 {the equivalent points to a box node, or is |null|} | |
> @d data=max_command+20 {the equivalent is simply a halfword number} | |
> | |
3654,3655c4149,4150 | |
< \yskip\noindent The mode is temporarily set to zero while processing \.{\\send} | |
< texts in the |ship_out| routine. | |
--- | |
> \yskip\noindent The mode is temporarily set to zero while processing \.{\\write} | |
> texts in the |ship_out| routine. | |
3666c4161 | |
< @p procedure print_mode(@!m:integer); {prints the current mode} | |
--- | |
> @p procedure print_mode(@!m:integer); {prints the mode represented by |m|} | |
3668,3677c4163,4173 | |
< case m div (max_command+1) of | |
< 0:print("vertical"); | |
< 1:print("horizontal"); | |
< 2:print("displayed math"); | |
< end | |
< else case (-m) div (max_command+1) of | |
< 0:print("internal vertical"); | |
< 1:print("restricted horizontal"); | |
< 2:print("math"); | |
< end; | |
--- | |
> case m div (max_command+1) of | |
> 0:print("vertical"); | |
> 1:print("horizontal"); | |
> 2:print("display math"); | |
> end | |
> else if m=0 then print("no") | |
> else case (-m) div (max_command+1) of | |
> 0:print("internal vertical"); | |
> 1:print("restricted horizontal"); | |
> 2:print("math"); | |
> end; | |
3694c4190 | |
< \yskip\hang|already| is the number of lines of the current paragraph that | |
--- | |
> \yskip\hang|prev_graf| is the number of lines of the current paragraph that | |
3697c4193 | |
< \yskip\hang|aux| is an auxiliary integer that gives further information | |
--- | |
> \yskip\hang|aux| is an auxiliary |memory_word| that gives further information | |
3703c4199 | |
< calculations, or it is |≤1000|pt if the next box on the vertical list is to | |
--- | |
> calculations, or it is |<=-1000|pt if the next box on the vertical list is to | |
3705,3706c4201,4204 | |
< known as |space_factor|; it holds the current space factor use in spacing | |
< calculations. In math mode, |aux| is also known as |incompleat_noad|; if | |
--- | |
> known as |space_factor| and |clang|; it holds the current space factor used in | |
> spacing calculations, and the current language used for hyphenation. | |
> (The value of |clang| is undefined in restricted horizontal mode.) | |
> In math mode, |aux| is also known as |incompleat_noad|; if | |
3711c4209 | |
< There is also a sixth quantity, |mode_line|, which is used to correlate | |
--- | |
> There is also a sixth quantity, |mode_line|, which correlates | |
3714c4212 | |
< of this line number is used as the |mode_line| at the level of the | |
--- | |
> of this line number is the |mode_line| at the level of the | |
3716a4215,4216 | |
> In horizontal mode, the |prev_graf| field is used for initial language data. | |
> | |
3718c4218 | |
< |tail|, |already|, |aux|, and |mode_line| values for all semantic levels | |
--- | |
> |tail|, |prev_graf|, |aux|, and |mode_line| values for all semantic levels | |
3720c4220 | |
< level is kept in the global quantities |mode|, |head|, |tail|, |already|, | |
--- | |
> level is kept in the global quantities |mode|, |head|, |tail|, |prev_graf|, | |
3727,3730c4227,4231 | |
< @!list_state_record=record@!mode_field:-mmode..mmode; | |
< @!head_field,@!tail_field: pointer; | |
< @!already_field,@!aux_field,@!ml_field: integer; | |
< end; | |
--- | |
> @!list_state_record=record@!mode_field:-mmode..mmode;@+ | |
> @!head_field,@!tail_field: pointer; | |
> @!pg_field,@!ml_field: integer;@+ | |
> @!aux_field: memory_word; | |
> end; | |
3735c4236 | |
< @d already==cur_list.already_field {number of paragraph lines accumulated} | |
--- | |
> @d prev_graf==cur_list.pg_field {number of paragraph lines accumulated} | |
3737,3739c4238,4241 | |
< @d prev_depth==aux {the name of |aux| in vertical mode} | |
< @d space_factor==aux {the name of |aux| in horizontal mode} | |
< @d incompleat_noad==aux {the name of |aux| in math mode} | |
--- | |
> @d prev_depth==aux.sc {the name of |aux| in vertical mode} | |
> @d space_factor==aux.hh.lh {part of |aux| in horizontal mode} | |
> @d clang==aux.hh.rh {the other part of |aux| in horizontal mode} | |
> @d incompleat_noad==aux.int {the name of |aux| in math mode} | |
3742d4243 | |
< | |
3752,3753c4253,4254 | |
< @d tail_append(#)==begin link(tail)←#; tail←link(tail); | |
< end | |
--- | |
> @d tail_append(#)==begin link(tail):=#; tail:=link(tail); | |
> end | |
3764,3766c4265,4268 | |
< nest_ptr←0; max_nest_stack←0; | |
< mode←vmode; head←contrib_head; tail←contrib_head; | |
< prev_depth←ignore_depth; mode_line←0; already←0; shown_mode←0;@/ | |
--- | |
> nest_ptr:=0; max_nest_stack:=0; | |
> mode:=vmode; head:=contrib_head; tail:=contrib_head; | |
> prev_depth:=ignore_depth; mode_line:=0; | |
> prev_graf:=0; shown_mode:=0; | |
3775,3779c4277,4282 | |
< begin max_nest_stack←nest_ptr; | |
< if nest_ptr=nest_size then overflow("semantic nest size",nest_size); | |
< end; | |
< nest[nest_ptr]←cur_list; {stack the record} | |
< incr(nest_ptr); head←get_avail; tail←head; already←0; mode_line←line; | |
--- | |
> begin max_nest_stack:=nest_ptr; | |
> if nest_ptr=nest_size then overflow("semantic nest size",nest_size); | |
> @:TeX capacity exceeded semantic nest size}{\quad semantic nest size@> | |
> end; | |
> nest[nest_ptr]:=cur_list; {stack the record} | |
> incr(nest_ptr); head:=get_avail; tail:=head; prev_graf:=0; mode_line:=line; | |
3788c4291 | |
< begin free_avail(head); decr(nest_ptr); cur_list←nest[nest_ptr]; | |
--- | |
> begin free_avail(head); decr(nest_ptr); cur_list:=nest[nest_ptr]; | |
3793c4296,4297 | |
< @p procedure show_activities; | |
--- | |
> @p procedure@?print_totals; forward;@t\2@> | |
> procedure show_activities; | |
3796c4300 | |
< @!a:integer; {auxiliary} | |
--- | |
> @!a:memory_word; {auxiliary} | |
3798,3827c4302,4346 | |
< begin nest[nest_ptr]←cur_list; {put the top level into the array} | |
< print_nl(""); | |
< for p←nest_ptr downto 0 do | |
< begin m←nest[p].mode_field; a←nest[p].aux_field; | |
< print_nl("### "); print_mode(m); | |
< print(" entered at line "); print_int(abs(nest[p].ml_field)); | |
< if nest[p].ml_field<0 then print(" (\output routine)"); | |
< if p=0 then | |
< begin print_nl("### current page:"); | |
< @<Show the status of the current page@>; | |
< print_nl("### recent contributions:"); | |
< end; | |
< show_box(link(nest[p].head_field)); | |
< case abs(m) div (max_command+1) of | |
< 0: begin print_nl("prevdepth "); | |
< if a≤ignore_depth then print("ignored") | |
< else print_scaled(a); | |
< if nest[p].already_field≠0 then | |
< begin print(", already "); | |
< print_int(nest[p].already_field); | |
< end; | |
< end; | |
< 1: begin print_nl("spacefactor "); print_int(a); | |
< end; | |
< 2: if a≠null then | |
< begin print("this will be denominator of:"); show_box(a); | |
< end; | |
< end; {there are no other cases} | |
< end; | |
< end; | |
--- | |
> @!t:integer; {ditto} | |
> begin nest[nest_ptr]:=cur_list; {put the top level into the array} | |
> print_nl(""); print_ln; | |
> for p:=nest_ptr downto 0 do | |
> begin m:=nest[p].mode_field; a:=nest[p].aux_field; | |
> print_nl("### "); print_mode(m); | |
> print(" entered at line "); print_int(abs(nest[p].ml_field)); | |
> if m=hmode then if nest[p].pg_field <> @'40600000 then | |
> begin print(" (language"); print_int(nest[p].pg_field mod @'200000); | |
> print(":hyphenmin"); print_int(nest[p].pg_field div @'20000000); | |
> print_char(","); print_int((nest[p].pg_field div @'200000) mod @'100); | |
> print_char(")"); | |
> end; | |
> if nest[p].ml_field<0 then print(" (\output routine)"); | |
> if p=0 then | |
> begin @<Show the status of the current page@>; | |
> if link(contrib_head)<>null then | |
> print_nl("### recent contributions:"); | |
> end; | |
> show_box(link(nest[p].head_field)); | |
> @<Show the auxiliary field, |a|@>; | |
> end; | |
> end; | |
> | |
> @ @<Show the auxiliary...@>= | |
> case abs(m) div (max_command+1) of | |
> 0: begin print_nl("prevdepth "); | |
> if a.sc<=ignore_depth then print("ignored") | |
> else print_scaled(a.sc); | |
> if nest[p].pg_field<>0 then | |
> begin print(", prevgraf "); | |
> print_int(nest[p].pg_field); print(" line"); | |
> if nest[p].pg_field<>1 then print_char("s"); | |
> end; | |
> end; | |
> 1: begin print_nl("spacefactor "); print_int(a.hh.lh); | |
> if m>0 then@+ if a.hh.rh>0 then | |
> begin print(", current language "); print_int(a.hh.rh);@+ | |
> end; | |
> end; | |
> 2: if a.int<>null then | |
> begin print("this will be denominator of:"); show_box(a.int);@+ | |
> end; | |
> end {there are no other cases} | |
> | |
3830,3831c4349,4351 | |
< let us consider the data structures used by its syntactic routines. In | |
< other words, we turn now to the tables that \TeX\ looks at when it is scanning | |
--- | |
> we ought to consider the data structures used by its syntactic routines. In | |
> other words, our next concern will be | |
> the tables that \TeX\ looks at when it is scanning | |
3835c4355 | |
< current ``equiv\-a\-lents'' of things; i.e., it explains what things mean | |
--- | |
> current ``equivalents'' of things; i.e., it explains what things mean | |
3840c4360 | |
< \yskip\hang 1) |eqtb[single_base..(hash_base-1)]| holds the current | |
--- | |
> \yskip\hangg 1) |eqtb[active_base..(hash_base-1)]| holds the current | |
3843,3844c4363,4364 | |
< \yskip\hang 2) |eqtb[hash_base..(glue_base-1)]| holds the current | |
< equivalents of multi-letter control sequences. | |
--- | |
> \yskip\hangg 2) |eqtb[hash_base..(glue_base-1)]| holds the current | |
> equivalents of multiletter control sequences. | |
3846c4366 | |
< \yskip\hang 3) |eqtb[glue_base..(local_base-1)]| holds the current | |
--- | |
> \yskip\hangg 3) |eqtb[glue_base..(local_base-1)]| holds the current | |
3849c4369 | |
< \yskip\hang 4) |eqtb[local_base..(int_base-1)]| holds the current | |
--- | |
> \yskip\hangg 4) |eqtb[local_base..(int_base-1)]| holds the current | |
3851c4371 | |
< the current ``chcodes,'' the current font, and a pointer to the current | |
--- | |
> the current ``catcodes,'' the current font, and a pointer to the current | |
3854c4374 | |
< \yskip\hang 5) |eqtb[int_base..(dimen_base-1)]| holds the current | |
--- | |
> \yskip\hangg 5) |eqtb[int_base..(dimen_base-1)]| holds the current | |
3858,3859c4378,4379 | |
< \yskip\hang 6) |eqtb[dimen_base..eqtb_size]| holds the current equivalents | |
< of fullword di\-men\-sion parameters like the current hsize or amount of | |
--- | |
> \yskip\hangg 6) |eqtb[dimen_base..eqtb_size]| holds the current equivalents | |
> of fullword dimension parameters like the current hsize or amount of | |
3864c4384 | |
< in region@@3 of |eqtb|, while the current meaning of the control sequence | |
--- | |
> in region~3 of |eqtb|, while the current meaning of the control sequence | |
3866c4386 | |
< \.{\\let}) appears in region@@2. | |
--- | |
> \.{\\let}) appears in region~2. | |
3871c4391 | |
< \yskip\hang 1) The |eq_level| (a quarterword) is the level of grouping at | |
--- | |
> \yskip\hangg 1) The |eq_level| (a quarterword) is the level of grouping at | |
3878c4398 | |
< \yskip\hang 2) The |eq_type| (another quarterword) specifies what kind of | |
--- | |
> \yskip\hangg 2) The |eq_type| (another quarterword) specifies what kind of | |
3883c4403 | |
< \yskip\hang 3) The |equiv| (a halfword) is the current equivalent value. | |
--- | |
> \yskip\hangg 3) The |equiv| (a halfword) is the current equivalent value. | |
3900,3902c4420,4422 | |
< In the first region we have 128 equivalents for single-character control | |
< sequences, followed by 128 equivalents for ``active characters'' that | |
< act as control sequences. | |
--- | |
> In the first region we have 256 equivalents for ``active characters'' that | |
> act as control sequences, followed by 256 equivalents for single-character | |
> control sequences. | |
3904c4424 | |
< Then comes region@@2, which corresponds to the hash table that we will | |
--- | |
> Then comes region~2, which corresponds to the hash table that we will | |
3906,3907c4426,4427 | |
< control sequence that is perpetually undefined. There also are three | |
< locations for special control sequences that are perpetually defined | |
--- | |
> control sequence that is perpetually undefined. There also are several | |
> locations for control sequences that are perpetually defined | |
3910,3914c4430,4450 | |
< @d single_base=1 {beginning of region 1, for single-letter control sequences} | |
< @d active_base=single_base+128 {equivalents of active characters} | |
< @d hash_base=active_base+128 {beginning of region 2, for the hash table} | |
< @d special_control_sequence=hash_base+hash_size {for error recovery} | |
< @d undefined_control_sequence=hash_base+hash_size+3 {dummy location} | |
--- | |
> @d active_base=1 {beginning of region 1, for active character equivalents} | |
> @d single_base=active_base+256 {equivalents of one-character control sequences} | |
> @d null_cs=single_base+256 {equivalent of \.{\\csname\\endcsname}} | |
> @d hash_base=null_cs+1 {beginning of region 2, for the hash table} | |
> @d frozen_control_sequence=hash_base+hash_size {for error recovery} | |
> @d frozen_protection=frozen_control_sequence {inaccessible but definable} | |
> @d frozen_cr=frozen_control_sequence+1 {permanent `\.{\\cr}'} | |
> @d frozen_end_group=frozen_control_sequence+2 {permanent `\.{\\endgroup}'} | |
> @d frozen_right=frozen_control_sequence+3 {permanent `\.{\\right}'} | |
> @d frozen_fi=frozen_control_sequence+4 {permanent `\.{\\fi}'} | |
> @d frozen_end_template=frozen_control_sequence+5 {permanent `\.{\\endtemplate}'} | |
> @d frozen_endv=frozen_control_sequence+6 {second permanent `\.{\\endtemplate}'} | |
> @d frozen_relax=frozen_control_sequence+7 {permanent `\.{\\relax}'} | |
> @d end_write=frozen_control_sequence+8 {permanent `\.{\\endwrite}'} | |
> @d frozen_dont_expand=frozen_control_sequence+9 | |
> {permanent `\.{\\notexpanded:}'} | |
> @d frozen_null_font=frozen_control_sequence+10 | |
> {permanent `\.{\\nullfont}'} | |
> @d font_id_base=frozen_null_font-font_base | |
> {begins table of 257 permanent font identifiers} | |
> @d undefined_control_sequence=frozen_null_font+257 {dummy location} | |
3918,3922c4454,4469 | |
< eq_type(undefined_control_sequence)←undefined_cs; | |
< equiv(undefined_control_sequence)←null; | |
< eq_level(undefined_control_sequence)←level_zero; | |
< for k←single_base to undefined_control_sequence-1 do | |
< eqtb[k]←eqtb[undefined_control_sequence]; | |
--- | |
> eq_type(undefined_control_sequence):=undefined_cs; | |
> equiv(undefined_control_sequence):=null; | |
> eq_level(undefined_control_sequence):=level_zero; | |
> for k:=active_base to undefined_control_sequence-1 do | |
> eqtb[k]:=eqtb[undefined_control_sequence]; | |
> | |
> @ Here is a routine that displays the current meaning of an |eqtb| entry | |
> in region 1 or~2. (Similar routines for the other regions will appear | |
> below.) | |
> | |
> @<Show equivalent |n|, in region 1 or 2@>= | |
> begin sprint_cs(n); print_char("="); print_cmd_chr(eq_type(n),equiv(n)); | |
> if eq_type(n)>=call then | |
> begin print_char(":"); show_token_list(link(equiv(n)),null,32); | |
> end; | |
> end | |
3925c4472 | |
< glue parameters defined here. It is important that the ``mskip'' | |
--- | |
> glue parameters defined here. It is important that the ``muskip'' | |
3928c4475 | |
< @d line_skip_code=0 {interline glue if |baseline_skip| is unfeasible} | |
--- | |
> @d line_skip_code=0 {interline glue if |baseline_skip| is infeasible} | |
3931,3945c4478,4495 | |
< @d disp_skip_code=3 {extra glue just above and below displayed math} | |
< @d disp_a_skip_code=4 {glue above displayed math following short lines} | |
< @d disp_b_skip_code=5 {glue below displayed math following short lines} | |
< @d left_skip_code=6 {glue at left of justified lines} | |
< @d right_skip_code=7 {glue at right of justified lines} | |
< @d top_skip_code=8 {glue at top of main pages} | |
< @d split_top_skip_code=9 {glue at top of split pages} | |
< @d tab_skip_code=10 {glue between aligned entries} | |
< @d space_skip_code=11 {glue between words (if not |zero_glue|)} | |
< @d xspace_skip_code=12 {glue after sentences (if not |zero_glue|)} | |
< @d par_fill_skip_code=13 {glue on last line of paragraph} | |
< @d thin_mskip_code=14 {thin space in math formula} | |
< @d med_mskip_code=15 {medium space in math formula} | |
< @d thick_mskip_code=16 {thick space in math formula} | |
< @d glue_pars=17 {total number of glue parameters} | |
--- | |
> @d above_display_skip_code=3 {extra glue just above displayed math} | |
> @d below_display_skip_code=4 {extra glue just below displayed math} | |
> @d above_display_short_skip_code=5 | |
> {glue above displayed math following short lines} | |
> @d below_display_short_skip_code=6 | |
> {glue below displayed math following short lines} | |
> @d left_skip_code=7 {glue at left of justified lines} | |
> @d right_skip_code=8 {glue at right of justified lines} | |
> @d top_skip_code=9 {glue at top of main pages} | |
> @d split_top_skip_code=10 {glue at top of split pages} | |
> @d tab_skip_code=11 {glue between aligned entries} | |
> @d space_skip_code=12 {glue between words (if not |zero_glue|)} | |
> @d xspace_skip_code=13 {glue after sentences (if not |zero_glue|)} | |
> @d par_fill_skip_code=14 {glue on last line of paragraph} | |
> @d thin_mu_skip_code=15 {thin space in math formula} | |
> @d med_mu_skip_code=16 {medium space in math formula} | |
> @d thick_mu_skip_code=17 {thick space in math formula} | |
> @d glue_pars=18 {total number of glue parameters} | |
3947c4497,4498 | |
< @d local_base=skip_base+256 {beginning of region 6} | |
--- | |
> @d mu_skip_base=skip_base+256 {table of 256 ``muskip'' registers} | |
> @d local_base=mu_skip_base+256 {beginning of region 4} | |
3949a4501 | |
> @d mu_skip(#)==equiv(mu_skip_base+#) {|mem| location of math glue spec} | |
3954,3956c4506,4509 | |
< @d disp_skip==glue_par(disp_skip_code) | |
< @d disp_a_skip==glue_par(disp_a_skip_code) | |
< @d disp_b_skip==glue_par(disp_b_skip_code) | |
--- | |
> @d above_display_skip==glue_par(above_display_skip_code) | |
> @d below_display_skip==glue_par(below_display_skip_code) | |
> @d above_display_short_skip==glue_par(above_display_short_skip_code) | |
> @d below_display_short_skip==glue_par(below_display_short_skip_code) | |
3965,3967c4518,4520 | |
< @d thin_mskip==glue_par(thin_mskip_code) | |
< @d med_mskip==glue_par(med_mskip_code) | |
< @d thick_mskip==glue_par(thick_mskip_code) | |
--- | |
> @d thin_mu_skip==glue_par(thin_mu_skip_code) | |
> @d med_mu_skip==glue_par(med_mu_skip_code) | |
> @d thick_mu_skip==glue_par(thick_mu_skip_code) | |
3981,3983c4534,4537 | |
< disp_skip_code: print_esc("dispskip"); | |
< disp_a_skip_code: print_esc("dispaskip"); | |
< disp_b_skip_code: print_esc("dispbskip"); | |
--- | |
> above_display_skip_code: print_esc("abovedisplayskip"); | |
> below_display_skip_code: print_esc("belowdisplayskip"); | |
> above_display_short_skip_code: print_esc("abovedisplayshortskip"); | |
> below_display_short_skip_code: print_esc("belowdisplayshortskip"); | |
3992,3994c4546,4548 | |
< thin_mskip_code: print_esc("thinmskip"); | |
< med_mskip_code: print_esc("medmskip"); | |
< thick_mskip_code: print_esc("thickmskip"); | |
--- | |
> thin_mu_skip_code: print_esc("thinmuskip"); | |
> med_mu_skip_code: print_esc("medmuskip"); | |
> thick_mu_skip_code: print_esc("thickmuskip"); | |
4004c4558 | |
< primitive("lineskip",assign_glue,line_skip_code);@/ | |
--- | |
> primitive("lineskip",assign_glue,glue_base+line_skip_code);@/ | |
4006c4560 | |
< primitive("baselineskip",assign_glue,baseline_skip_code);@/ | |
--- | |
> primitive("baselineskip",assign_glue,glue_base+baseline_skip_code);@/ | |
4008c4562 | |
< primitive("parskip",assign_glue,par_skip_code);@/ | |
--- | |
> primitive("parskip",assign_glue,glue_base+par_skip_code);@/ | |
4010,4016c4564,4574 | |
< primitive("dispskip",assign_glue,disp_skip_code);@/ | |
< @!@:disp_skip_}{\.{\\dispskip} primitive@> | |
< primitive("dispaskip",assign_glue,disp_a_skip_code);@/ | |
< @!@:disp_a_skip_}{\.{\\dispaskip} primitive@> | |
< primitive("dispbskip",assign_glue,disp_b_skip_code);@/ | |
< @!@:disp_b_skip_}{\.{\\dispbskip} primitive@> | |
< primitive("leftskip",assign_glue,left_skip_code);@/ | |
--- | |
> primitive("abovedisplayskip",assign_glue,glue_base+above_display_skip_code);@/ | |
> @!@:above_display_skip_}{\.{\\abovedisplayskip} primitive@> | |
> primitive("belowdisplayskip",assign_glue,glue_base+below_display_skip_code);@/ | |
> @!@:below_display_skip_}{\.{\\belowdisplayskip} primitive@> | |
> primitive("abovedisplayshortskip", | |
> assign_glue,glue_base+above_display_short_skip_code);@/ | |
> @!@:above_display_short_skip_}{\.{\\abovedisplayshortskip} primitive@> | |
> primitive("belowdisplayshortskip", | |
> assign_glue,glue_base+below_display_short_skip_code);@/ | |
> @!@:below_display_short_skip_}{\.{\\belowdisplayshortskip} primitive@> | |
> primitive("leftskip",assign_glue,glue_base+left_skip_code);@/ | |
4018c4576 | |
< primitive("rightskip",assign_glue,right_skip_code);@/ | |
--- | |
> primitive("rightskip",assign_glue,glue_base+right_skip_code);@/ | |
4020c4578 | |
< primitive("topskip",assign_glue,top_skip_code);@/ | |
--- | |
> primitive("topskip",assign_glue,glue_base+top_skip_code);@/ | |
4022c4580 | |
< primitive("splittopskip",assign_glue,split_top_skip_code);@/ | |
--- | |
> primitive("splittopskip",assign_glue,glue_base+split_top_skip_code);@/ | |
4024c4582 | |
< primitive("tabskip",assign_glue,tab_skip_code);@/ | |
--- | |
> primitive("tabskip",assign_glue,glue_base+tab_skip_code);@/ | |
4026c4584 | |
< primitive("spaceskip",assign_glue,space_skip_code);@/ | |
--- | |
> primitive("spaceskip",assign_glue,glue_base+space_skip_code);@/ | |
4028c4586 | |
< primitive("xspaceskip",assign_glue,xspace_skip_code);@/ | |
--- | |
> primitive("xspaceskip",assign_glue,glue_base+xspace_skip_code);@/ | |
4030c4588 | |
< primitive("parfillskip",assign_glue,par_fill_skip_code);@/ | |
--- | |
> primitive("parfillskip",assign_glue,glue_base+par_fill_skip_code);@/ | |
4032,4037c4590,4595 | |
< primitive("thinmskip",assign_glue,thin_mskip_code);@/ | |
< @!@:thin_mskip_}{\.{\\thinskip} primitive@> | |
< primitive("medmskip",assign_glue,med_mskip_code);@/ | |
< @!@:med_mskip_}{\.{\\medmskip} primitive@> | |
< primitive("thickmskip",assign_glue,thick_mskip_code);@/ | |
< @!@:thick_mskip_}{\.{\\thickmskip} primitive@> | |
--- | |
> primitive("thinmuskip",assign_mu_glue,glue_base+thin_mu_skip_code);@/ | |
> @!@:thin_mu_skip_}{\.{\\thinmuskip} primitive@> | |
> primitive("medmuskip",assign_mu_glue,glue_base+med_mu_skip_code);@/ | |
> @!@:med_mu_skip_}{\.{\\medmuskip} primitive@> | |
> primitive("thickmuskip",assign_mu_glue,glue_base+thick_mu_skip_code);@/ | |
> @!@:thick_mu_skip_}{\.{\\thickmuskip} primitive@> | |
4040c4598,4604 | |
< assign_glue:print_skip_param(chr_code); | |
--- | |
> assign_glue,assign_mu_glue: if chr_code<skip_base then | |
> print_skip_param(chr_code-glue_base) | |
> else if chr_code<mu_skip_base then | |
> begin print_esc("skip"); print_int(chr_code-skip_base); | |
> end | |
> else begin print_esc("muskip"); print_int(chr_code-mu_skip_base); | |
> end; | |
4045,4048c4609,4626 | |
< equiv(glue_base)←zero_glue; eq_level(glue_base)←level_one; | |
< eq_type(glue_base)←glue_ref; | |
< for k←glue_base+1 to local_base-1 do eqtb[k]←eqtb[glue_base]; | |
< glue_ref_count(zero_glue)←glue_ref_count(zero_glue)+local_base-glue_base; | |
--- | |
> equiv(glue_base):=zero_glue; eq_level(glue_base):=level_one; | |
> eq_type(glue_base):=glue_ref; | |
> for k:=glue_base+1 to local_base-1 do eqtb[k]:=eqtb[glue_base]; | |
> glue_ref_count(zero_glue):=glue_ref_count(zero_glue)+local_base-glue_base; | |
> | |
> @ @<Show equivalent |n|, in region 3@>= | |
> if n<skip_base then | |
> begin print_skip_param(n-glue_base); print_char("="); | |
> if n<glue_base+thin_mu_skip_code then print_spec(equiv(n),"pt") | |
> else print_spec(equiv(n),"mu"); | |
> end | |
> else if n<mu_skip_base then | |
> begin print_esc("skip"); print_int(n-skip_base); print_char("="); | |
> print_spec(equiv(n),"pt"); | |
> end | |
> else begin print_esc("muskip"); print_int(n-mu_skip_base); print_char("="); | |
> print_spec(equiv(n),"mu"); | |
> end | |
4051c4629 | |
< bulk of this region is taken up by five tables that are indexed by seven-bit | |
--- | |
> bulk of this region is taken up by five tables that are indexed by eight-bit | |
4054c4632,4633 | |
< token parameters, as well as the table of 256 \.{\\box} registers. | |
--- | |
> token parameters, as well as the tables of \.{\\toks} and \.{\\box} | |
> registers. | |
4059c4638,4646 | |
< @d box_base=local_base+3 {table of 256 box registers} | |
--- | |
> @d every_math_loc=local_base+3 {points to token list for \.{\\everymath}} | |
> @d every_display_loc=local_base+4 {points to token list for \.{\\everydisplay}} | |
> @d every_hbox_loc=local_base+5 {points to token list for \.{\\everyhbox}} | |
> @d every_vbox_loc=local_base+6 {points to token list for \.{\\everyvbox}} | |
> @d every_job_loc=local_base+7 {points to token list for \.{\\everyjob}} | |
> @d every_cr_loc=local_base+8 {points to token list for \.{\\everycr}} | |
> @d err_help_loc=local_base+9 {points to token list for \.{\\errhelp}} | |
> @d toks_base=local_base+10 {table of 256 token list registers} | |
> @d box_base=toks_base+256 {table of 256 box registers} | |
4062,4068c4649,4655 | |
< @d cur_fam_loc=math_font_base+48 {current font family} | |
< @d ch_code_base=cur_fam_loc+1 {table of 128 character command codes} | |
< @d math_code_base=ch_code_base+128 {table of 128 math mode mappings} | |
< @d lc_code_base=math_code_base+128 {table of 128 lower case mappings} | |
< @d uc_code_base=lc_code_base+128 {table of 128 upper case mappings} | |
< @d sf_code_base=uc_code_base+128 {table of 128 space factor mappings} | |
< @d int_base=sf_code_base+128 {beginning of region 5} | |
--- | |
> @d cat_code_base=math_font_base+48 | |
> {table of 256 command codes (the ``catcodes'')} | |
> @d lc_code_base=cat_code_base+256 {table of 256 lowercase mappings} | |
> @d uc_code_base=lc_code_base+256 {table of 256 uppercase mappings} | |
> @d sf_code_base=uc_code_base+256 {table of 256 spacefactor mappings} | |
> @d math_code_base=sf_code_base+256 {table of 256 math mode mappings} | |
> @d int_base=math_code_base+256 {beginning of region 5} | |
4072a4660,4667 | |
> @d every_math==equiv(every_math_loc) | |
> @d every_display==equiv(every_display_loc) | |
> @d every_hbox==equiv(every_hbox_loc) | |
> @d every_vbox==equiv(every_vbox_loc) | |
> @d every_job==equiv(every_job_loc) | |
> @d every_cr==equiv(every_cr_loc) | |
> @d err_help==equiv(err_help_loc) | |
> @d toks(#)==equiv(toks_base+#) | |
4075d4669 | |
< @d cur_fam==equiv(cur_fam_loc) | |
4077,4078c4671 | |
< @d ch_code(#)==equiv(ch_code_base+#) | |
< @d math_code(#)==equiv(math_code_base+#) | |
--- | |
> @d cat_code(#)==equiv(cat_code_base+#) | |
4081a4675,4676 | |
> @d math_code(#)==equiv(math_code_base+#) | |
> {Note: |math_code(c)| is the true math code plus |min_halfword|} | |
4087a4683,4696 | |
> primitive("everymath",assign_toks,every_math_loc); | |
> @!@:every_math_}{\.{\\everymath} primitive@> | |
> primitive("everydisplay",assign_toks,every_display_loc); | |
> @!@:every_display_}{\.{\\everydisplay} primitive@> | |
> primitive("everyhbox",assign_toks,every_hbox_loc); | |
> @!@:every_hbox_}{\.{\\everyhbox} primitive@> | |
> primitive("everyvbox",assign_toks,every_vbox_loc); | |
> @!@:every_vbox_}{\.{\\everyvbox} primitive@> | |
> primitive("everyjob",assign_toks,every_job_loc); | |
> @!@:every_job_}{\.{\\everyjob} primitive@> | |
> primitive("everycr",assign_toks,every_cr_loc); | |
> @!@:every_cr_}{\.{\\everycr} primitive@> | |
> primitive("errhelp",assign_toks,err_help_loc); | |
> @!@:err_help_}{\.{\\errhelp} primitive@> | |
4090,4091c4699,4712 | |
< assign_toks: if chr_code=output_routine_loc then print_esc("output") | |
< else print_esc("everypar"); | |
--- | |
> assign_toks: if chr_code>=toks_base then | |
> begin print_esc("toks"); print_int(chr_code-toks_base); | |
> end | |
> else case chr_code of | |
> output_routine_loc: print_esc("output"); | |
> every_par_loc: print_esc("everypar"); | |
> every_math_loc: print_esc("everymath"); | |
> every_display_loc: print_esc("everydisplay"); | |
> every_hbox_loc: print_esc("everyhbox"); | |
> every_vbox_loc: print_esc("everyvbox"); | |
> every_job_loc: print_esc("everyjob"); | |
> every_cr_loc: print_esc("everycr"); | |
> othercases print_esc("errhelp") | |
> endcases; | |
4097c4718,4722 | |
< conventional interpretation of ascii code. | |
--- | |
> conventional interpretation of ASCII code. These initial values should | |
> not be changed when \TeX\ is adapted for use with non-English languages; | |
> all changes to the initialization conventions should be made in format | |
> packages, not in \TeX\ itself, so that global interchange of formats is | |
> possible. | |
4099c4724,4725 | |
< @d undefined_font==font_base | |
--- | |
> @d null_font==font_base | |
> @d var_code==@'70000 {math code meaning ``use the current family''} | |
4102,4124c4728,4811 | |
< par_shape_ptr←null; eq_type(par_shape_loc)←shape_ref; | |
< eq_level(par_shape_loc)←level_one;@/ | |
< eqtb[output_routine_loc]←eqtb[undefined_control_sequence]; | |
< eqtb[every_par_loc]←eqtb[undefined_control_sequence]; | |
< box(0)←null; eq_type(box_base)←box_ref; eq_level(box_base)←level_one; | |
< for k←box_base+1 to box_base+255 do eqtb[k]←eqtb[box_base]; | |
< cur_font←undefined_font; eq_type(cur_font_loc)←data; | |
< eq_level(cur_font_loc)←level_one;@/ | |
< for k←math_font_base to math_font_base+47 do eqtb[k]←eqtb[cur_font_loc]; | |
< cur_fam←0; eq_type(cur_fam_loc)←data; eq_level(cur_fam_loc)←level_one;@/ | |
< for k←ch_code_base to int_base-1 do eqtb[k]←eqtb[cur_fam_loc]; | |
< for k←0 to 127 do | |
< begin ch_code(k)←other_char; math_code(k)←k; sf_code(k)←1000; | |
< end; | |
< ch_code(carriage_return)←car_ret; ch_code(" ")←spacer; ch_code("\")←escape; | |
< ch_code(invalid_code)←invalid_char; ch_code(null_code)←ignore; | |
< for k←"A" to "Z" do | |
< begin ch_code(k)←letter; ch_code(k+"a"-"A")←letter;@/ | |
< math_code(k)←k+@'70400; math_code(k+"a"-"A")←k+"a"-"A"+@'70400;@/ | |
< lc_code(k)←k+"a"-"A"; lc_code(k+"a"-"A")←k+"a"-"A";@/ | |
< uc_code(k)←k; uc_code(k+"a"-"A")←k;@/ | |
< sf_code(k)←999; | |
< end; | |
--- | |
> par_shape_ptr:=null; eq_type(par_shape_loc):=shape_ref; | |
> eq_level(par_shape_loc):=level_one;@/ | |
> for k:=output_routine_loc to toks_base+255 do | |
> eqtb[k]:=eqtb[undefined_control_sequence]; | |
> box(0):=null; eq_type(box_base):=box_ref; eq_level(box_base):=level_one; | |
> for k:=box_base+1 to box_base+255 do eqtb[k]:=eqtb[box_base]; | |
> cur_font:=null_font; eq_type(cur_font_loc):=data; | |
> eq_level(cur_font_loc):=level_one;@/ | |
> for k:=math_font_base to math_font_base+47 do eqtb[k]:=eqtb[cur_font_loc]; | |
> equiv(cat_code_base):=0; eq_type(cat_code_base):=data; | |
> eq_level(cat_code_base):=level_one;@/ | |
> for k:=cat_code_base+1 to int_base-1 do eqtb[k]:=eqtb[cat_code_base]; | |
> for k:=0 to 255 do | |
> begin cat_code(k):=other_char; math_code(k):=hi(k); sf_code(k):=1000; | |
> end; | |
> cat_code(carriage_return):=car_ret; cat_code(" "):=spacer; | |
> cat_code("\"):=escape; cat_code("%"):=comment; | |
> cat_code(invalid_code):=invalid_char; cat_code(null_code):=ignore; | |
> for k:="0" to "9" do math_code(k):=hi(k+var_code); | |
> for k:="A" to "Z" do | |
> begin cat_code(k):=letter; cat_code(k+"a"-"A"):=letter;@/ | |
> math_code(k):=hi(k+var_code+@"100); | |
> math_code(k+"a"-"A"):=hi(k+"a"-"A"+var_code+@"100);@/ | |
> lc_code(k):=k+"a"-"A"; lc_code(k+"a"-"A"):=k+"a"-"A";@/ | |
> uc_code(k):=k; uc_code(k+"a"-"A"):=k;@/ | |
> sf_code(k):=999; | |
> end; | |
> | |
> @ @<Show equivalent |n|, in region 4@>= | |
> if n=par_shape_loc then | |
> begin print_esc("parshape"); print_char("="); | |
> if par_shape_ptr=null then print_char("0") | |
> else print_int(info(par_shape_ptr)); | |
> end | |
> else if n<toks_base then | |
> begin print_cmd_chr(assign_toks,n); print_char("="); | |
> if equiv(n)<>null then show_token_list(link(equiv(n)),null,32); | |
> end | |
> else if n<box_base then | |
> begin print_esc("toks"); print_int(n-toks_base); print_char("="); | |
> if equiv(n)<>null then show_token_list(link(equiv(n)),null,32); | |
> end | |
> else if n<cur_font_loc then | |
> begin print_esc("box"); print_int(n-box_base); print_char("="); | |
> if equiv(n)=null then print("void") | |
> else begin depth_threshold:=0; breadth_max:=1; show_node_list(equiv(n)); | |
> end; | |
> end | |
> else if n<cat_code_base then @<Show the font identifier in |eqtb[n]|@> | |
> else @<Show the halfword code in |eqtb[n]|@> | |
> | |
> @ @<Show the font identifier in |eqtb[n]|@>= | |
> begin if n=cur_font_loc then print("current font") | |
> else if n<math_font_base+16 then | |
> begin print_esc("textfont"); print_int(n-math_font_base); | |
> end | |
> else if n<math_font_base+32 then | |
> begin print_esc("scriptfont"); print_int(n-math_font_base-16); | |
> end | |
> else begin print_esc("scriptscriptfont"); print_int(n-math_font_base-32); | |
> end; | |
> print_char("=");@/ | |
> print_esc(hash[font_id_base+equiv(n)].rh); | |
> {that's |font_id_text(equiv(n))|} | |
> end | |
> | |
> @ @<Show the halfword code in |eqtb[n]|@>= | |
> if n<math_code_base then | |
> begin if n<lc_code_base then | |
> begin print_esc("catcode"); print_int(n-cat_code_base); | |
> end | |
> else if n<uc_code_base then | |
> begin print_esc("lccode"); print_int(n-lc_code_base); | |
> end | |
> else if n<sf_code_base then | |
> begin print_esc("uccode"); print_int(n-uc_code_base); | |
> end | |
> else begin print_esc("sfcode"); print_int(n-sf_code_base); | |
> end; | |
> print_char("="); print_int(equiv(n)); | |
> end | |
> else begin print_esc("mathcode"); print_int(n-math_code_base); | |
> print_char("="); print_int(ho(equiv(n))); | |
> end | |
4128c4815 | |
< |ch_code..sf_code| tables that precede it, since delimiter codes are | |
--- | |
> |cat_code..math_code| tables that precede it, since delimiter codes are | |
4130c4817,4819 | |
< halfword. This is what makes region@@5 different from region 4. | |
--- | |
> halfword. This is what makes region~5 different from region~4. We will | |
> store the |eq_level| information in an auxiliary array of quarterwords | |
> that will be defined later. | |
4137,4171c4826,4878 | |
< @d widow_penalty_code=5 {penalty for creating a widow line} | |
< @d display_widow_penalty_code=6 {ditto, just before a display} | |
< @d broken_penalty_code=7 {penalty for breaking a page at a broken line} | |
< @d bin_op_penalty_code=8 {penalty for breaking after a binary operation} | |
< @d rel_penalty_code=9 {penalty for breaking after a relation} | |
< @d pre_display_penalty_code=10 | |
< {penalty for breaking just before a displayed formula} | |
< @d post_display_penalty_code=11 | |
< {penalty for breaking just after a displayed formula} | |
< @d inter_line_penalty_code=12 {additional penalty between lines} | |
< @d double_hyphen_demerits_code=13 {demerits for double hyphen break} | |
< @d final_hyphen_demerits_code=14 {demerits for final hyphen break} | |
< @d adj_demerits_code=15 {demerits for adjacent incompatible lines} | |
< @d mag_code=16 {magnification ratio} | |
< @d delimiter_factor_code=17 {ratio for variable-size delimiters} | |
< @d looseness_code=18 {change in number of lines for a paragraph} | |
< @d time_code=19 {current time of day} | |
< @d day_code=20 {current day of the month} | |
< @d month_code=21 {current month of the year} | |
< @d year_code=22 {current year of our Lord} | |
< @d show_box_breadth_code=23 {nodes per level in |show_box|} | |
< @d show_box_depth_code=24 {maximum level in |show_box|} | |
< @d hbadness_code=25 {show hboxes exceeding this badness} | |
< @d vbadness_code=26 {show vboxes exceeding this badness} | |
< @d pause_code=27 {pause after each line is read from a file} | |
< @d tracing_online_code=28 {show diagnostic output on terminal} | |
< @d tracing_macros_code=29 {show macros as they are being expanded} | |
< @d tracing_stats_code=30 {show memory usage if \TeX\ knows it} | |
< @d tracing_output_code=31 {show boxes when they are shipped out} | |
< @d tracing_lost_chars_code=32 {show characters that aren't in the font} | |
< @d tracing_commands_code=33 {show command codes at |big_switch|} | |
< @d uc_hyph_code=34 {hyphenate words beginning with a capital letter} | |
< @d output_penalty_code=35 {penalty found at current page break} | |
< @d hang_after_code=36 {hanging indentation changes after this many lines} | |
< @d int_pars=37 {total number of integer parameters} | |
--- | |
> @d club_penalty_code=5 {penalty for creating a club line} | |
> @d widow_penalty_code=6 {penalty for creating a widow line} | |
> @d display_widow_penalty_code=7 {ditto, just before a display} | |
> @d broken_penalty_code=8 {penalty for breaking a page at a broken line} | |
> @d bin_op_penalty_code=9 {penalty for breaking after a binary operation} | |
> @d rel_penalty_code=10 {penalty for breaking after a relation} | |
> @d pre_display_penalty_code=11 | |
> {penalty for breaking just before a displayed formula} | |
> @d post_display_penalty_code=12 | |
> {penalty for breaking just after a displayed formula} | |
> @d inter_line_penalty_code=13 {additional penalty between lines} | |
> @d double_hyphen_demerits_code=14 {demerits for double hyphen break} | |
> @d final_hyphen_demerits_code=15 {demerits for final hyphen break} | |
> @d adj_demerits_code=16 {demerits for adjacent incompatible lines} | |
> @d mag_code=17 {magnification ratio} | |
> @d delimiter_factor_code=18 {ratio for variable-size delimiters} | |
> @d looseness_code=19 {change in number of lines for a paragraph} | |
> @d time_code=20 {current time of day} | |
> @d day_code=21 {current day of the month} | |
> @d month_code=22 {current month of the year} | |
> @d year_code=23 {current year of our Lord} | |
> @d show_box_breadth_code=24 {nodes per level in |show_box|} | |
> @d show_box_depth_code=25 {maximum level in |show_box|} | |
> @d hbadness_code=26 {hboxes exceeding this badness will be shown by |hpack|} | |
> @d vbadness_code=27 {vboxes exceeding this badness will be shown by |vpack|} | |
> @d pausing_code=28 {pause after each line is read from a file} | |
> @d tracing_online_code=29 {show diagnostic output on terminal} | |
> @d tracing_macros_code=30 {show macros as they are being expanded} | |
> @d tracing_stats_code=31 {show memory usage if \TeX\ knows it} | |
> @d tracing_paragraphs_code=32 {show line-break calculations} | |
> @d tracing_pages_code=33 {show page-break calculations} | |
> @d tracing_output_code=34 {show boxes when they are shipped out} | |
> @d tracing_lost_chars_code=35 {show characters that aren't in the font} | |
> @d tracing_commands_code=36 {show command codes at |big_switch|} | |
> @d tracing_restores_code=37 {show equivalents when they are restored} | |
> @d uc_hyph_code=38 {hyphenate words beginning with a capital letter} | |
> @d output_penalty_code=39 {penalty found at current page break} | |
> @d max_dead_cycles_code=40 {bound on consecutive dead cycles of output} | |
> @d hang_after_code=41 {hanging indentation changes after this many lines} | |
> @d floating_penalty_code=42 {penalty for insertions heldover after a split} | |
> @d global_defs_code=43 {override \.{\\global} specifications} | |
> @d cur_fam_code=44 {current family} | |
> @d escape_char_code=45 {escape character for token output} | |
> @d default_hyphen_char_code=46 {value of \.{\\hyphenchar} when a font is loaded} | |
> @d default_skew_char_code=47 {value of \.{\\skewchar} when a font is loaded} | |
> @d end_line_char_code=48 {character placed at the right end of the buffer} | |
> @d new_line_char_code=49 {character that prints as |print_ln|} | |
> @d language_code=50 {current hyphenation table} | |
> @d left_hyphen_min_code=51 {minimum left hyphenation fragment size} | |
> @d right_hyphen_min_code=52 {minimum right hyphenation fragment size} | |
> @d holding_inserts_code=53 {do not remove insertion nodes from \.{\\box255}} | |
> @d error_context_lines_code=54 {maximum intermediate line pairs shown} | |
> @d int_pars=55 {total number of integer parameters} | |
4173,4174c4880,4881 | |
< @d del_code_base=count_base+256 {128 delimiter code mappings} | |
< @d dimen_base=del_code_base+128 {beginning of region 6} | |
--- | |
> @d del_code_base=count_base+256 {256 delimiter code mappings} | |
> @d dimen_base=del_code_base+256 {beginning of region 6} | |
4183a4891 | |
> @d club_penalty==int_par(club_penalty_code) | |
4206c4914 | |
< @d pause==int_par(pause_code) | |
--- | |
> @d pausing==int_par(pausing_code) | |
4209a4918,4919 | |
> @d tracing_paragraphs==int_par(tracing_paragraphs_code) | |
> @d tracing_pages==int_par(tracing_pages_code) | |
4212a4923 | |
> @d tracing_restores==int_par(tracing_restores_code) | |
4214a4926 | |
> @d max_dead_cycles==int_par(max_dead_cycles_code) | |
4216,4219c4928,4944 | |
< | |
< @<Assign the values |depth_threshold←show_box_depth|...@>= | |
< depth_threshold←show_box_depth; | |
< breadth_max←show_box_breadth | |
--- | |
> @d floating_penalty==int_par(floating_penalty_code) | |
> @d global_defs==int_par(global_defs_code) | |
> @d cur_fam==int_par(cur_fam_code) | |
> @d escape_char==int_par(escape_char_code) | |
> @d default_hyphen_char==int_par(default_hyphen_char_code) | |
> @d default_skew_char==int_par(default_skew_char_code) | |
> @d end_line_char==int_par(end_line_char_code) | |
> @d new_line_char==int_par(new_line_char_code) | |
> @d language==int_par(language_code) | |
> @d left_hyphen_min==int_par(left_hyphen_min_code) | |
> @d right_hyphen_min==int_par(right_hyphen_min_code) | |
> @d holding_inserts==int_par(holding_inserts_code) | |
> @d error_context_lines==int_par(error_context_lines_code) | |
> | |
> @<Assign the values |depth_threshold:=show_box_depth|...@>= | |
> depth_threshold:=show_box_depth; | |
> breadth_max:=show_box_breadth | |
4229a4955 | |
> club_penalty_code:print_esc("clubpenalty"); | |
4252c4978 | |
< pause_code:print_esc("pause"); | |
--- | |
> pausing_code:print_esc("pausing"); | |
4255a4982,4983 | |
> tracing_paragraphs_code:print_esc("tracingparagraphs"); | |
> tracing_pages_code:print_esc("tracingpages"); | |
4258a4987 | |
> tracing_restores_code:print_esc("tracingrestores"); | |
4260a4990 | |
> max_dead_cycles_code:print_esc("maxdeadcycles"); | |
4261a4992,5004 | |
> floating_penalty_code:print_esc("floatingpenalty"); | |
> global_defs_code:print_esc("globaldefs"); | |
> cur_fam_code:print_esc("fam"); | |
> escape_char_code:print_esc("escapechar"); | |
> default_hyphen_char_code:print_esc("defaulthyphenchar"); | |
> default_skew_char_code:print_esc("defaultskewchar"); | |
> end_line_char_code:print_esc("endlinechar"); | |
> new_line_char_code:print_esc("newlinechar"); | |
> language_code:print_esc("language"); | |
> left_hyphen_min_code:print_esc("lefthyphenmin"); | |
> right_hyphen_min_code:print_esc("righthyphenmin"); | |
> holding_inserts_code:print_esc("holdinginserts"); | |
> error_context_lines_code:print_esc("errorcontextlines"); | |
4269c5012 | |
< primitive("pretolerance",assign_int,pretolerance_code);@/ | |
--- | |
> primitive("pretolerance",assign_int,int_base+pretolerance_code);@/ | |
4271c5014 | |
< primitive("tolerance",assign_int,tolerance_code);@/ | |
--- | |
> primitive("tolerance",assign_int,int_base+tolerance_code);@/ | |
4273c5016 | |
< primitive("linepenalty",assign_int,line_penalty_code);@/ | |
--- | |
> primitive("linepenalty",assign_int,int_base+line_penalty_code);@/ | |
4275c5018 | |
< primitive("hyphenpenalty",assign_int,hyphen_penalty_code);@/ | |
--- | |
> primitive("hyphenpenalty",assign_int,int_base+hyphen_penalty_code);@/ | |
4277c5020 | |
< primitive("exhyphenpenalty",assign_int,ex_hyphen_penalty_code);@/ | |
--- | |
> primitive("exhyphenpenalty",assign_int,int_base+ex_hyphen_penalty_code);@/ | |
4279c5022,5024 | |
< primitive("widowpenalty",assign_int,widow_penalty_code);@/ | |
--- | |
> primitive("clubpenalty",assign_int,int_base+club_penalty_code);@/ | |
> @!@:club_penalty_}{\.{\\clubpenalty} primitive@> | |
> primitive("widowpenalty",assign_int,int_base+widow_penalty_code);@/ | |
4281c5026,5027 | |
< primitive("displaywidowpenalty",assign_int,display_widow_penalty_code);@/ | |
--- | |
> primitive("displaywidowpenalty", | |
> assign_int,int_base+display_widow_penalty_code);@/ | |
4283c5029 | |
< primitive("brokenpenalty",assign_int,broken_penalty_code);@/ | |
--- | |
> primitive("brokenpenalty",assign_int,int_base+broken_penalty_code);@/ | |
4285c5031 | |
< primitive("binoppenalty",assign_int,bin_op_penalty_code);@/ | |
--- | |
> primitive("binoppenalty",assign_int,int_base+bin_op_penalty_code);@/ | |
4287c5033 | |
< primitive("relpenalty",assign_int,rel_penalty_code);@/ | |
--- | |
> primitive("relpenalty",assign_int,int_base+rel_penalty_code);@/ | |
4289c5035 | |
< primitive("predisplaypenalty",assign_int,pre_display_penalty_code);@/ | |
--- | |
> primitive("predisplaypenalty",assign_int,int_base+pre_display_penalty_code);@/ | |
4291c5037 | |
< primitive("postdisplaypenalty",assign_int,post_display_penalty_code);@/ | |
--- | |
> primitive("postdisplaypenalty",assign_int,int_base+post_display_penalty_code);@/ | |
4293c5039 | |
< primitive("interlinepenalty",assign_int,inter_line_penalty_code);@/ | |
--- | |
> primitive("interlinepenalty",assign_int,int_base+inter_line_penalty_code);@/ | |
4295c5041,5042 | |
< primitive("doublehyphendemerits",assign_int,double_hyphen_demerits_code);@/ | |
--- | |
> primitive("doublehyphendemerits", | |
> assign_int,int_base+double_hyphen_demerits_code);@/ | |
4297c5044,5045 | |
< primitive("finalhyphendemerits",assign_int,final_hyphen_demerits_code);@/ | |
--- | |
> primitive("finalhyphendemerits", | |
> assign_int,int_base+final_hyphen_demerits_code);@/ | |
4299c5047 | |
< primitive("adjdemerits",assign_int,adj_demerits_code);@/ | |
--- | |
> primitive("adjdemerits",assign_int,int_base+adj_demerits_code);@/ | |
4301c5049 | |
< primitive("mag",assign_int,mag_code);@/ | |
--- | |
> primitive("mag",assign_int,int_base+mag_code);@/ | |
4303c5051 | |
< primitive("delimiterfactor",assign_int,delimiter_factor_code);@/ | |
--- | |
> primitive("delimiterfactor",assign_int,int_base+delimiter_factor_code);@/ | |
4305c5053 | |
< primitive("looseness",assign_int,looseness_code);@/ | |
--- | |
> primitive("looseness",assign_int,int_base+looseness_code);@/ | |
4307c5055 | |
< primitive("time",assign_int,time_code);@/ | |
--- | |
> primitive("time",assign_int,int_base+time_code);@/ | |
4309c5057 | |
< primitive("day",assign_int,day_code);@/ | |
--- | |
> primitive("day",assign_int,int_base+day_code);@/ | |
4311c5059 | |
< primitive("month",assign_int,month_code);@/ | |
--- | |
> primitive("month",assign_int,int_base+month_code);@/ | |
4313c5061 | |
< primitive("year",assign_int,year_code);@/ | |
--- | |
> primitive("year",assign_int,int_base+year_code);@/ | |
4315c5063 | |
< primitive("showboxbreadth",assign_int,show_box_breadth_code);@/ | |
--- | |
> primitive("showboxbreadth",assign_int,int_base+show_box_breadth_code);@/ | |
4317c5065 | |
< primitive("showboxdepth",assign_int,show_box_depth_code);@/ | |
--- | |
> primitive("showboxdepth",assign_int,int_base+show_box_depth_code);@/ | |
4319c5067 | |
< primitive("hbadness",assign_int,hbadness_code);@/ | |
--- | |
> primitive("hbadness",assign_int,int_base+hbadness_code);@/ | |
4321c5069 | |
< primitive("vbadness",assign_int,vbadness_code);@/ | |
--- | |
> primitive("vbadness",assign_int,int_base+vbadness_code);@/ | |
4323,4325c5071,5073 | |
< primitive("pause",assign_int,pause_code);@/ | |
< @!@:pause_}{\.{\\pause} primitive@> | |
< primitive("tracingonline",assign_int,tracing_online_code);@/ | |
--- | |
> primitive("pausing",assign_int,int_base+pausing_code);@/ | |
> @!@:pausing_}{\.{\\pausing} primitive@> | |
> primitive("tracingonline",assign_int,int_base+tracing_online_code);@/ | |
4327c5075 | |
< primitive("tracingmacros",assign_int,tracing_macros_code);@/ | |
--- | |
> primitive("tracingmacros",assign_int,int_base+tracing_macros_code);@/ | |
4329c5077 | |
< primitive("tracingstats",assign_int,tracing_stats_code);@/ | |
--- | |
> primitive("tracingstats",assign_int,int_base+tracing_stats_code);@/ | |
4331c5079,5083 | |
< primitive("tracingoutput",assign_int,tracing_output_code);@/ | |
--- | |
> primitive("tracingparagraphs",assign_int,int_base+tracing_paragraphs_code);@/ | |
> @!@:tracing_paragraphs_}{\.{\\tracingparagraphs} primitive@> | |
> primitive("tracingpages",assign_int,int_base+tracing_pages_code);@/ | |
> @!@:tracing_pages_}{\.{\\tracingpages} primitive@> | |
> primitive("tracingoutput",assign_int,int_base+tracing_output_code);@/ | |
4333c5085 | |
< primitive("tracinglostchars",assign_int,tracing_lost_chars_code);@/ | |
--- | |
> primitive("tracinglostchars",assign_int,int_base+tracing_lost_chars_code);@/ | |
4335c5087 | |
< primitive("tracingcommands",assign_int,tracing_commands_code);@/ | |
--- | |
> primitive("tracingcommands",assign_int,int_base+tracing_commands_code);@/ | |
4337c5089,5091 | |
< primitive("uchyph",assign_int,uc_hyph_code);@/ | |
--- | |
> primitive("tracingrestores",assign_int,int_base+tracing_restores_code);@/ | |
> @!@:tracing_restores_}{\.{\\tracingrestores} primitive@> | |
> primitive("uchyph",assign_int,int_base+uc_hyph_code);@/ | |
4339c5093 | |
< primitive("outputpenalty",assign_int,output_penalty_code);@/ | |
--- | |
> primitive("outputpenalty",assign_int,int_base+output_penalty_code);@/ | |
4341c5095,5097 | |
< primitive("hangafter",assign_int,hang_after_code);@/ | |
--- | |
> primitive("maxdeadcycles",assign_int,int_base+max_dead_cycles_code);@/ | |
> @!@:max_dead_cycles_}{\.{\\maxdeadcycles} primitive@> | |
> primitive("hangafter",assign_int,int_base+hang_after_code);@/ | |
4342a5099,5124 | |
> primitive("floatingpenalty",assign_int,int_base+floating_penalty_code);@/ | |
> @!@:floating_penalty_}{\.{\\floatingpenalty} primitive@> | |
> primitive("globaldefs",assign_int,int_base+global_defs_code);@/ | |
> @!@:global_defs_}{\.{\\globaldefs} primitive@> | |
> primitive("fam",assign_int,int_base+cur_fam_code);@/ | |
> @!@:fam_}{\.{\\fam} primitive@> | |
> primitive("escapechar",assign_int,int_base+escape_char_code);@/ | |
> @!@:escape_char_}{\.{\\escapechar} primitive@> | |
> primitive("defaulthyphenchar",assign_int,int_base+default_hyphen_char_code);@/ | |
> @!@:default_hyphen_char_}{\.{\\defaulthyphenchar} primitive@> | |
> primitive("defaultskewchar",assign_int,int_base+default_skew_char_code);@/ | |
> @!@:default_skew_char_}{\.{\\defaultskewchar} primitive@> | |
> primitive("endlinechar",assign_int,int_base+end_line_char_code);@/ | |
> @!@:end_line_char_}{\.{\\endlinechar} primitive@> | |
> primitive("newlinechar",assign_int,int_base+new_line_char_code);@/ | |
> @!@:new_line_char_}{\.{\\newlinechar} primitive@> | |
> primitive("language",assign_int,int_base+language_code);@/ | |
> @!@:language_}{\.{\\language} primitive@> | |
> primitive("lefthyphenmin",assign_int,int_base+left_hyphen_min_code);@/ | |
> @!@:left_hyphen_min_}{\.{\\lefthyphenmin} primitive@> | |
> primitive("righthyphenmin",assign_int,int_base+right_hyphen_min_code);@/ | |
> @!@:right_hyphen_min_}{\.{\\righthyphenmin} primitive@> | |
> primitive("holdinginserts",assign_int,int_base+holding_inserts_code);@/ | |
> @!@:holding_inserts_}{\.{\\holdinginserts} primitive@> | |
> primitive("errorcontextlines",assign_int,int_base+error_context_lines_code);@/ | |
> @!@:error_context_lines_}{\.{\\errorcontextlines} primitive@> | |
4345c5127,5129 | |
< assign_int: print_param(chr_code); | |
--- | |
> assign_int: if chr_code<count_base then print_param(chr_code-int_base) | |
> else begin print_esc("count"); print_int(chr_code-count_base); | |
> end; | |
4349a5134 | |
> @^null delimiter@> | |
4352,4354c5137,5141 | |
< for k←int_base to del_code_base-1 do eqtb[k].int←0; | |
< mag←1000; tolerance←10000; | |
< for k←0 to 127 do del_code(k)←-1; | |
--- | |
> for k:=int_base to del_code_base-1 do eqtb[k].int:=0; | |
> mag:=1000; tolerance:=10000; hang_after:=1; max_dead_cycles:=25; | |
> escape_char:="\"; end_line_char:=carriage_return; | |
> for k:=0 to 255 do del_code(k):=-1; | |
> del_code("."):=0; {this null delimiter is used in error recovery} | |
4364,4367c5151,5180 | |
< begin time←12*60; {minutes since midnight} | |
< day←4; {fourth day of the month} | |
< month←7; {seventh month of the year} | |
< year←1776; {Anno Domini} | |
--- | |
> begin time:=12*60; {minutes since midnight} | |
> day:=4; {fourth day of the month} | |
> month:=7; {seventh month of the year} | |
> year:=1776; {Anno Domini} | |
> end; | |
> | |
> @ @<Show equivalent |n|, in region 5@>= | |
> begin if n<count_base then print_param(n-int_base) | |
> else if n<del_code_base then | |
> begin print_esc("count"); print_int(n-count_base); | |
> end | |
> else begin print_esc("delcode"); print_int(n-del_code_base); | |
> end; | |
> print_char("="); print_int(eqtb[n].int); | |
> end | |
> | |
> @ @<Set variable |c| to the current escape character@>=c:=escape_char | |
> | |
> @ @<Character |s| is the current new-line character@>=s=new_line_char | |
> | |
> @ \TeX\ is occasionally supposed to print diagnostic information that | |
> goes only into the transcript file, unless |tracing_online| is positive. | |
> Here are two routines that adjust the destination of print commands: | |
> | |
> @p procedure begin_diagnostic; {prepare to do some tracing} | |
> begin old_setting:=selector; | |
> if (tracing_online<=0)and(selector=term_and_log) then | |
> begin decr(selector); | |
> if history=spotless then history:=warning_issued; | |
> end; | |
4368a5182,5194 | |
> @# | |
> procedure end_diagnostic(@!blank_line:boolean); | |
> {restore proper conditions after tracing} | |
> begin print_nl(""); | |
> if blank_line then print_ln; | |
> selector:=old_setting; | |
> end; | |
> | |
> @ Of course we had better declare another global variable, if the previous | |
> routines are going to work. | |
> | |
> @<Glob...@>= | |
> @!old_setting:0..max_selector; | |
4371,4372c5197 | |
< here, and the 256 \.{\\dimen} registers. It also contains the current | |
< amount of hanging indentation, which is slightly special. | |
--- | |
> here, and the 256 \.{\\dimen} registers. | |
4376,4381c5201,5206 | |
< @d var_unit_code=2 {variable unit for dimensions} | |
< @d line_skip_limit_code=3 {threshold for |line_skip| instead of |baseline_skip|} | |
< @d hsize_code=4 {line width in horizontal mode} | |
< @d vsize_code=5 {page height in vertical mode} | |
< @d max_depth_code=6 {maximum depth of boxes on main pages} | |
< @d split_max_depth_code=7 {maximum depth of boxes on split pages} | |
--- | |
> @d line_skip_limit_code=2 {threshold for |line_skip| instead of |baseline_skip|} | |
> @d hsize_code=3 {line width in horizontal mode} | |
> @d vsize_code=4 {page height in vertical mode} | |
> @d max_depth_code=5 {maximum depth of boxes on main pages} | |
> @d split_max_depth_code=6 {maximum depth of boxes on split pages} | |
> @d box_max_depth_code=7 {maximum depth of explicit vboxes} | |
4384c5209 | |
< @d delimiter_limit_code=10 {maximum amount uncovered by variable delimiters} | |
--- | |
> @d delimiter_shortfall_code=10 {maximum amount uncovered by variable delimiters} | |
4391,4394c5216,5222 | |
< @d dimen_pars=17 {total number of dimension parameters} | |
< @d hanging_indent_code=dimen_pars {amount of hanging indentation} | |
< @d scaled_base=dimen_base+dimen_pars+1 | |
< {table of 256 user-defined \.{\\dimen} registers} | |
--- | |
> @d hang_indent_code=17 {amount of hanging indentation} | |
> @d h_offset_code=18 {amount of horizontal offset when shipping pages out} | |
> @d v_offset_code=19 {amount of vertical offset when shipping pages out} | |
> @d emergency_stretch_code=20 {reduces badnesses on final pass of line-breaking} | |
> @d dimen_pars=21 {total number of dimension parameters} | |
> @d scaled_base=dimen_base+dimen_pars | |
> {table of 256 user-defined \.{\\dimen} registers} | |
4401d5228 | |
< @d var_unit==dimen_par(var_unit_code) | |
4406a5234 | |
> @d box_max_depth==dimen_par(box_max_depth_code) | |
4409c5237 | |
< @d delimiter_limit==dimen_par(delimiter_limit_code) | |
--- | |
> @d delimiter_shortfall==dimen_par(delimiter_shortfall_code) | |
4416c5244,5247 | |
< @d hanging_indent==dimen_par(hanging_indent_code) | |
--- | |
> @d hang_indent==dimen_par(hang_indent_code) | |
> @d h_offset==dimen_par(h_offset_code) | |
> @d v_offset==dimen_par(v_offset_code) | |
> @d emergency_stretch==dimen_par(emergency_stretch_code) | |
4422d5252 | |
< var_unit_code:print_esc("varunit"); | |
4427a5258 | |
> box_max_depth_code:print_esc("boxmaxdepth"); | |
4430c5261 | |
< delimiter_limit_code:print_esc("delimiterlimit"); | |
--- | |
> delimiter_shortfall_code:print_esc("delimitershortfall"); | |
4436a5268,5271 | |
> hang_indent_code:print_esc("hangindent"); | |
> h_offset_code:print_esc("hoffset"); | |
> v_offset_code:print_esc("voffset"); | |
> emergency_stretch_code:print_esc("emergencystretch"); | |
4442c5277 | |
< primitive("parindent",assign_dimen,par_indent_code);@/ | |
--- | |
> primitive("parindent",assign_dimen,dimen_base+par_indent_code);@/ | |
4444c5279 | |
< primitive("mathsurround",assign_dimen,math_surround_code);@/ | |
--- | |
> primitive("mathsurround",assign_dimen,dimen_base+math_surround_code);@/ | |
4446,4448c5281 | |
< primitive("varunit",assign_dimen,var_unit_code);@/ | |
< @!@:var_unit_}{\.{\\varunit} primitive@> | |
< primitive("lineskiplimit",assign_dimen,line_skip_limit_code);@/ | |
--- | |
> primitive("lineskiplimit",assign_dimen,dimen_base+line_skip_limit_code);@/ | |
4450c5283 | |
< primitive("hsize",assign_dimen,hsize_code);@/ | |
--- | |
> primitive("hsize",assign_dimen,dimen_base+hsize_code);@/ | |
4452c5285 | |
< primitive("vsize",assign_dimen,vsize_code);@/ | |
--- | |
> primitive("vsize",assign_dimen,dimen_base+vsize_code);@/ | |
4454c5287 | |
< primitive("maxdepth",assign_dimen,max_depth_code);@/ | |
--- | |
> primitive("maxdepth",assign_dimen,dimen_base+max_depth_code);@/ | |
4456c5289 | |
< primitive("splitmaxdepth",assign_dimen,split_max_depth_code);@/ | |
--- | |
> primitive("splitmaxdepth",assign_dimen,dimen_base+split_max_depth_code);@/ | |
4458c5291,5293 | |
< primitive("hfuzz",assign_dimen,hfuzz_code);@/ | |
--- | |
> primitive("boxmaxdepth",assign_dimen,dimen_base+box_max_depth_code);@/ | |
> @!@:box_max_depth_}{\.{\\boxmaxdepth} primitive@> | |
> primitive("hfuzz",assign_dimen,dimen_base+hfuzz_code);@/ | |
4460c5295 | |
< primitive("vfuzz",assign_dimen,vfuzz_code);@/ | |
--- | |
> primitive("vfuzz",assign_dimen,dimen_base+vfuzz_code);@/ | |
4462,4464c5297,5301 | |
< primitive("delimiterlimit",assign_dimen,delimiter_limit_code);@/ | |
< @!@:delimiter_limit_}{\.{\\delimiterlimit} primitive@> | |
< primitive("nulldelimiterspace",assign_dimen,null_delimiter_space_code);@/ | |
--- | |
> primitive("delimitershortfall", | |
> assign_dimen,dimen_base+delimiter_shortfall_code);@/ | |
> @!@:delimiter_shortfall_}{\.{\\delimitershortfall} primitive@> | |
> primitive("nulldelimiterspace", | |
> assign_dimen,dimen_base+null_delimiter_space_code);@/ | |
4466c5303 | |
< primitive("scriptspace",assign_dimen,script_space_code);@/ | |
--- | |
> primitive("scriptspace",assign_dimen,dimen_base+script_space_code);@/ | |
4468c5305 | |
< primitive("predisplaysize",assign_dimen,pre_display_size_code);@/ | |
--- | |
> primitive("predisplaysize",assign_dimen,dimen_base+pre_display_size_code);@/ | |
4470c5307 | |
< primitive("displaywidth",assign_dimen,display_width_code);@/ | |
--- | |
> primitive("displaywidth",assign_dimen,dimen_base+display_width_code);@/ | |
4472c5309 | |
< primitive("displayindent",assign_dimen,display_indent_code);@/ | |
--- | |
> primitive("displayindent",assign_dimen,dimen_base+display_indent_code);@/ | |
4474c5311 | |
< primitive("overfullrule",assign_dimen,overfull_rule_code);@/ | |
--- | |
> primitive("overfullrule",assign_dimen,dimen_base+overfull_rule_code);@/ | |
4475a5313,5320 | |
> primitive("hangindent",assign_dimen,dimen_base+hang_indent_code);@/ | |
> @!@:hang_indent_}{\.{\\hangindent} primitive@> | |
> primitive("hoffset",assign_dimen,dimen_base+h_offset_code);@/ | |
> @!@:h_offset_}{\.{\\hoffset} primitive@> | |
> primitive("voffset",assign_dimen,dimen_base+v_offset_code);@/ | |
> @!@:v_offset_}{\.{\\voffset} primitive@> | |
> primitive("emergencystretch",assign_dimen,dimen_base+emergency_stretch_code);@/ | |
> @!@:emergency_stretch_}{\.{\\emergencystretch} primitive@> | |
4478c5323,5326 | |
< assign_dimen:print_length_param(chr_code); | |
--- | |
> assign_dimen: if chr_code<scaled_base then | |
> print_length_param(chr_code-dimen_base) | |
> else begin print_esc("dimen"); print_int(chr_code-scaled_base); | |
> end; | |
4481c5329,5351 | |
< for k←dimen_base to eqtb_size do eqtb[k].sc←0; | |
--- | |
> for k:=dimen_base to eqtb_size do eqtb[k].sc:=0; | |
> | |
> @ @<Show equivalent |n|, in region 6@>= | |
> begin if n<scaled_base then print_length_param(n-dimen_base) | |
> else begin print_esc("dimen"); print_int(n-scaled_base); | |
> end; | |
> print_char("="); print_scaled(eqtb[n].sc); print("pt"); | |
> end | |
> | |
> @ Here is a procedure that displays the contents of |eqtb[n]| | |
> symbolically. | |
> | |
> @p@t\4@>@<Declare the procedure called |print_cmd_chr|@>@;@/ | |
> @!stat procedure show_eqtb(@!n:pointer); | |
> begin if n<active_base then print_char("?") {this can't happen} | |
> else if n<glue_base then @<Show equivalent |n|, in region 1 or 2@> | |
> else if n<local_base then @<Show equivalent |n|, in region 3@> | |
> else if n<int_base then @<Show equivalent |n|, in region 4@> | |
> else if n<dimen_base then @<Show equivalent |n|, in region 5@> | |
> else if n<=eqtb_size then @<Show equivalent |n|, in region 6@> | |
> else print_char("?"); {this can't happen either} | |
> end; | |
> tats | |
4488,4489c5358,5359 | |
< @<Globals...@>= | |
< @!eqtb:array[single_base..eqtb_size] of memory_word; | |
--- | |
> @<Glob...@>= | |
> @!eqtb:array[active_base..eqtb_size] of memory_word; | |
4493c5363 | |
< for k←int_base to eqtb_size do xeq_level[k]←level_one; | |
--- | |
> for k:=int_base to eqtb_size do xeq_level[k]:=level_one; | |
4496,4497c5366,5367 | |
< given value, it is interested only in regions 1 to@@3 of@@|eqtb|, and in the | |
< first part of region@@4. | |
--- | |
> given value, it is interested only in regions 1 to~3 of~|eqtb|, and in the | |
> first part of region~4. | |
4500,4522c5370,5374 | |
< for q←single_base to box_base+255 do | |
< begin if equiv(q)=p then | |
< begin print_nl("EQUIV("); print_int(q); print_char(")"); | |
< end; | |
< end | |
< | |
< @ \TeX\ is occasionally supposed to print diagnostic information that | |
< goes only into the transcript file, unless |tracing_online| is nonzero. | |
< Here are two routines that adjust the destination of print commands: | |
< | |
< @p procedure begin_diagnostic; {prepare to do some tracing} | |
< begin old_setting←selector; save_offset←offset; | |
< if (tracing_online=0)∧(selector=term_and_err) then decr(selector); | |
< end; | |
< @# | |
< procedure end_diagnostic; {restore proper conditions after tracing} | |
< begin if offset>0 then print_ln; | |
< selector←old_setting; | |
< if (tracing_online=0)∧(old_setting=term_and_err) then offset←save_offset; | |
< end; | |
< | |
< @ Of course we had better declare two more global variables, if the previous | |
< routines are going to work. | |
--- | |
> for q:=active_base to box_base+255 do | |
> begin if equiv(q)=p then | |
> begin print_nl("EQUIV("); print_int(q); print_char(")"); | |
> end; | |
> end | |
4524,4526d5375 | |
< @<Glob...@>= | |
< @!old_setting:0..max_selector; | |
< @!save_offset:0..max_print_line; | |
4531c5380 | |
< table, it is never removed again, because there are complicated situations | |
--- | |
> table, it is never removed, because there are complicated situations | |
4540c5389 | |
< belonging to the same coalesced list as the identifier corresponding to@@|p|; | |
--- | |
> belonging to the same coalesced list as the identifier corresponding to~|p|; | |
4542c5391 | |
< |p|'s identifier. If position@@|p| of the hash table is empty, we have | |
--- | |
> |p|'s identifier. If position~|p| of the hash table is empty, we have | |
4545,4546c5394,5395 | |
< |hash_used| is maintained in such a way that all locations |p≥hash_used| | |
< are nonempty. The global variable |cs_count| tells how many multi-letter | |
--- | |
> |hash_used| is maintained in such a way that all locations |p>=hash_used| | |
> are nonempty. The global variable |cs_count| tells how many multiletter | |
4550,4552c5399 | |
< |true| during the time that new hash table entries are forbidden. Another | |
< global variable, |cs_ptr|, records the position in |eqtb| of the most recently | |
< found control sequence. | |
--- | |
> |true| during the time that new hash table entries are forbidden. | |
4556a5404 | |
> @d font_id_text(#) == text(font_id_base+#) {a frozen font identifier's name} | |
4558c5406 | |
< @<Globals...@>= | |
--- | |
> @<Glob...@>= | |
4560c5408 | |
< {the hash table} | |
--- | |
> {the hash table} | |
4563d5410 | |
< @!cs_ptr:pointer; {control sequence found here, zero if none found} | |
4567,4569c5414,5416 | |
< no_new_control_sequence←true; {new identifiers are usually forbidden} | |
< next(hash_base)←0; text(hash_base)←0; | |
< for k←hash_base+1 to undefined_control_sequence-1 do hash[k]←hash[hash_base]; | |
--- | |
> no_new_control_sequence:=true; {new identifiers are usually forbidden} | |
> next(hash_base):=0; text(hash_base):=0; | |
> for k:=hash_base+1 to undefined_control_sequence-1 do hash[k]:=hash[hash_base]; | |
4572,4573c5419,5423 | |
< hash_used←special_control_sequence; {nothing is used} | |
< cs_count←0; | |
--- | |
> hash_used:=frozen_control_sequence; {nothing is used} | |
> cs_count:=0; | |
> eq_type(frozen_dont_expand):=dont_expand; | |
> text(frozen_dont_expand):="notexpanded:"; | |
> @.notexpanded:@> | |
4585a5436 | |
> @!d:integer; {number of characters in incomplete current string} | |
4589,4601c5440,5452 | |
< p←h+hash_base; {we start searching here; note that |0≤h<hash_prime|} | |
< loop@+begin if (text(p)>0) and (length(text(p))=l) then | |
< if str_eq_buf(text(p),j) then goto found; | |
< if next(p)=0 then | |
< begin if no_new_control_sequence then | |
< p←undefined_control_sequence | |
< else @<Insert a new control sequence after |p|, then make | |
< |p| point to it@>; | |
< goto found; | |
< end; | |
< p←next(p); | |
< end; | |
< found: id_lookup←p; | |
--- | |
> p:=h+hash_base; {we start searching here; note that |0<=h<hash_prime|} | |
> loop@+begin if text(p)>0 then if length(text(p))=l then | |
> if str_eq_buf(text(p),j) then goto found; | |
> if next(p)=0 then | |
> begin if no_new_control_sequence then | |
> p:=undefined_control_sequence | |
> else @<Insert a new control sequence after |p|, then make | |
> |p| point to it@>; | |
> goto found; | |
> end; | |
> p:=next(p); | |
> end; | |
> found: id_lookup:=p; | |
4606,4614c5457,5469 | |
< begin repeat if hash_is_full then overflow("hash size",hash_size); | |
< decr(hash_used); | |
< until text(hash_used)=0; {search for an empty location in |hash|} | |
< next(p)←hash_used; p←hash_used; | |
< end; | |
< str_room(l); | |
< for k←j to j+l-1 do append_char(buffer[k]); | |
< text(p)←make_string; | |
< stat incr(cs_count);@+tats@;@/ | |
--- | |
> begin repeat if hash_is_full then overflow("hash size",hash_size); | |
> @:TeX capacity exceeded hash size}{\quad hash size@> | |
> decr(hash_used); | |
> until text(hash_used)=0; {search for an empty location in |hash|} | |
> next(p):=hash_used; p:=hash_used; | |
> end; | |
> str_room(l); d:=cur_length; | |
> while pool_ptr>str_start[str_ptr] do | |
> begin decr(pool_ptr); str_pool[pool_ptr+l]:=str_pool[pool_ptr]; | |
> end; {move current string up to make room for another} | |
> for k:=j to j+l-1 do append_char(buffer[k]); | |
> text(p):=make_string; pool_ptr:=pool_ptr+d; | |
> @!stat incr(cs_count);@+tats@;@/ | |
4617c5472 | |
< @ The value of |hash_prime| should be roughly 85\%\ of |hash_size|, and it | |
--- | |
> @ The value of |hash_prime| should be roughly 85\pct! of |hash_size|, and it | |
4619a5475,5476 | |
> [See J.~S. Vitter, {\sl Journal of the ACM\/ \bf30} (1983), 231--258.] | |
> @^Vitter, Jeffrey Scott@> | |
4622,4626c5479,5483 | |
< h←buffer[j]; | |
< for k←j+1 to j+l-1 do | |
< begin h←h+h+buffer[k]; | |
< while h≥hash_prime do h←h-hash_prime; | |
< end | |
--- | |
> h:=buffer[j]; | |
> for k:=j+1 to j+l-1 do | |
> begin h:=h+h+buffer[k]; | |
> while h>=hash_prime do h:=h-hash_prime; | |
> end | |
4632,4633c5489,5492 | |
< if it consists entirely of letters. This procedure might be invoked with | |
< invalid data, so it is ``extra robust''. | |
--- | |
> unless it is a single nonletter or an active character. This procedure | |
> might be invoked with invalid data, so it is ``extra robust.'' The | |
> individual characters must be printed one at a time using |print|, since | |
> they may be unprintable. | |
4636c5495 | |
< procedure print_cs(@!p:pointer); {prints a purported control sequence} | |
--- | |
> procedure print_cs(@!p:integer); {prints a purported control sequence} | |
4638,4646c5497,5512 | |
< if p≥active_base then print(p-active_base) | |
< else if p<single_base then print_esc("IMPOSSIBLE.") | |
< else begin print_esc(p-single_base); | |
< if ch_code(p)=letter then print_char(" "); | |
< end | |
< else if p≥undefined_control_sequence then print_esc("IMPOSSIBLE.") | |
< else if text(p)=0 then print_esc("NONEXISTENT.") | |
< else begin print_esc(text(p)); print_char(" "); | |
< end; | |
--- | |
> if p>=single_base then | |
> if p=null_cs then | |
> begin print_esc("csname"); print_esc("endcsname"); print_char(" "); | |
> end | |
> else begin print_esc(p-single_base); | |
> if cat_code(p-single_base)=letter then print_char(" "); | |
> end | |
> else if p<active_base then print_esc("IMPOSSIBLE.") | |
> @.IMPOSSIBLE@> | |
> else print(p-active_base) | |
> else if p>=undefined_control_sequence then print_esc("IMPOSSIBLE.") | |
> else if (text(p)<0)or(text(p)>=str_ptr) then print_esc("NONEXISTENT.") | |
> @.NONEXISTENT@> | |
> else begin print_esc(text(p)); | |
> print_char(" "); | |
> end; | |
4652c5518,5519 | |
< @p procedure sprint_cs(@!p:pointer); {prints a control sequence} | |
--- | |
> @<Basic printing procedures@>= | |
> procedure sprint_cs(@!p:pointer); {prints a control sequence} | |
4654,4655c5521,5524 | |
< if p<active_base then print_esc(p-single_base) | |
< else print(p-active_base) | |
--- | |
> if p<single_base then print(p-active_base) | |
> else if p<null_cs then print_esc(p-single_base) | |
> else begin print_esc("csname"); print_esc("endcsname"); | |
> end | |
4665c5534 | |
< @p init procedure primitive(@!s:str_number;@!c:quarterword;@!o:halfword); | |
--- | |
> @p @!init procedure primitive(@!s:str_number;@!c:quarterword;@!o:halfword); | |
4669,4676c5538,5545 | |
< begin if s<128 then cur_val←s+single_base | |
< else begin k←str_start[s]; l←str_start[s+1]-k; | |
< {we will move |s| into the (empty) |buffer|} | |
< for j←0 to l-1 do buffer[j]←str_pool[k+j]; | |
< cur_val←id_lookup(0,l); {|no_new_control_sequence| is |false|} | |
< flush_string; text(cur_val)←s; {we don't want to have the string twice} | |
< end; | |
< eq_level(cur_val)←level_one; eq_type(cur_val)←c; equiv(cur_val)←o; | |
--- | |
> begin if s<256 then cur_val:=s+single_base | |
> else begin k:=str_start[s]; l:=str_start[s+1]-k; | |
> {we will move |s| into the (empty) |buffer|} | |
> for j:=0 to l-1 do buffer[j]:=so(str_pool[k+j]); | |
> cur_val:=id_lookup(0,l); {|no_new_control_sequence| is |false|} | |
> flush_string; text(cur_val):=s; {we don't want to have the string twice} | |
> end; | |
> eq_level(cur_val):=level_one; eq_type(cur_val):=c; equiv(cur_val):=o; | |
4685,4688c5554,5567 | |
< primitive("relax",relax,0);@/ | |
< @!@:relax_}{\.{\\relax} primitive@> | |
< primitive("let",let,0);@/ | |
< @!@:let_}{\.{\\let} primitive@> | |
--- | |
> primitive(" ",ex_space,0);@/ | |
> @!@:Single-character primitives /}{\quad\.{\\\ }@> | |
> primitive("/",ital_corr,0);@/ | |
> @!@:Single-character primitives /}{\quad\.{\\/}@> | |
> primitive("accent",accent,0);@/ | |
> @!@:accent_}{\.{\\accent} primitive@> | |
> primitive("advance",advance,0);@/ | |
> @!@:advance_}{\.{\\advance} primitive@> | |
> primitive("afterassignment",after_assignment,0);@/ | |
> @!@:after_assignment_}{\.{\\afterassignment} primitive@> | |
> primitive("aftergroup",after_group,0);@/ | |
> @!@:after_group_}{\.{\\aftergroup} primitive@> | |
> primitive("begingroup",begin_group,0);@/ | |
> @!@:begin_group_}{\.{\\begingroup} primitive@> | |
4691,4698c5570,5582 | |
< primitive("mathchar",math_char_num,0);@/ | |
< @!@:math_char_}{\.{\\mathchar} primitive@> | |
< primitive("mark",mark,0);@/ | |
< @!@:mark_}{\.{\\mark} primitive@> | |
< primitive("input",input,0);@/ | |
< @!@:input_}{\.{\\input} primitive@> | |
< primitive("penalty",break_penalty,0);@/ | |
< @!@:penalty_}{\.{\\penalty} primitive@> | |
--- | |
> primitive("csname",cs_name,0);@/ | |
> @!@:cs_name_}{\.{\\csname} primitive@> | |
> primitive("delimiter",delim_num,0);@/ | |
> @!@:delimiter_}{\.{\\delimiter} primitive@> | |
> primitive("divide",divide,0);@/ | |
> @!@:divide_}{\.{\\divide} primitive@> | |
> primitive("endcsname",end_cs_name,0);@/ | |
> @!@:end_cs_name_}{\.{\\endcsname} primitive@> | |
> primitive("endgroup",end_group,0); | |
> @!@:end_group_}{\.{\\endgroup} primitive@> | |
> text(frozen_end_group):="endgroup"; eqtb[frozen_end_group]:=eqtb[cur_val];@/ | |
> primitive("expandafter",expand_after,0);@/ | |
> @!@:expand_after_}{\.{\\expandafter} primitive@> | |
4701,4714c5585,5586 | |
< primitive(":",set_font,0);@/ | |
< @!@:Single-character primitives :}{\quad\.{\\:}@> | |
< primitive("fam",set_family,0);@/ | |
< @!@:fam_}{\.{\\fam} primitive@> | |
< primitive("number",number,0);@/ | |
< @!@:number_}{\.{\\number} primitive@> | |
< primitive("setbox",set_box,0);@/ | |
< @!@:set_box_}{\.{\\setbox} primitive@> | |
< primitive("unbox",unbox,0);@/ | |
< @!@:unbox_}{\.{\\unbox} primitive@> | |
< primitive("unskip",unskip,0);@/ | |
< @!@:unskip_}{\.{\\unskip} primitive@> | |
< primitive("lastskip",last_skip,0);@/ | |
< @!@:last_skip_}{\.{\\lastskip} primitive@> | |
--- | |
> primitive("fontdimen",assign_font_dimen,0);@/ | |
> @!@:font_dimen_}{\.{\\fontdimen} primitive@> | |
4717,4722d5588 | |
< primitive("valign",valign,0);@/ | |
< @!@:valign_}{\.{\\valign} primitive@> | |
< primitive("noalign",no_align,0);@/ | |
< @!@:no_align_}{\.{\\noalign} primitive@> | |
< primitive("vrule",vrule,0);@/ | |
< @!@:vrule_}{\.{\\vrule} primitive@> | |
4724a5591,5592 | |
> primitive("ignorespaces",ignore_spaces,0);@/ | |
> @!@:ignore_spaces_}{\.{\\ignorespaces} primitive@> | |
4727,4736c5595,5596 | |
< primitive("vadjust",vadjust,0);@/ | |
< @!@:vadjust_}{\.{\\vadjust} primitive@> | |
< primitive("ignorespace",ignore_space,0);@/ | |
< @!@:ignore_space_}{\.{\\ignorespace} primitive@> | |
< primitive("parshape",set_shape,0);@/ | |
< @!@:par_shape_}{\.{\\parshape} primitive@> | |
< primitive("/",ital_corr,0);@/ | |
< @!@:Single-character primitives /}{\quad\.{\\/}@> | |
< primitive("accent",accent,0);@/ | |
< @!@:accent_}{\.{\\accent} primitive@> | |
--- | |
> primitive("mark",mark,0);@/ | |
> @!@:mark_}{\.{\\mark} primitive@> | |
4739,4744c5599,5610 | |
< primitive("texinfo",assign_tex_info,0);@/ | |
< @!@:tex_info_}{\.{\\texinfo} primitive@> | |
< primitive("delimiter",delim_num,0);@/ | |
< @!@:delimiter_}{\.{\\delimiter} primitive@> | |
< primitive("limitswitch",limit_switch,0);@/ | |
< @!@:limit_switch_}{\.{\\limitswitch} primitive@> | |
--- | |
> primitive("mathchar",math_char_num,0);@/ | |
> @!@:math_char_}{\.{\\mathchar} primitive@> | |
> primitive("mathchoice",math_choice,0);@/ | |
> @!@:math_choice_}{\.{\\mathchoice} primitive@> | |
> primitive("multiply",multiply,0);@/ | |
> @!@:multiply_}{\.{\\multiply} primitive@> | |
> primitive("noalign",no_align,0);@/ | |
> @!@:no_align_}{\.{\\noalign} primitive@> | |
> primitive("noboundary",no_boundary,0);@/ | |
> @!@:no_boundary_}{\.{\\noboundary} primitive@> | |
> primitive("noexpand",no_expand,0);@/ | |
> @!@:no_expand_}{\.{\\noexpand} primitive@> | |
4747,4752d5612 | |
< primitive("vcenter",vcenter,0);@/ | |
< @!@:vcenter_}{\.{\\vcenter} primitive@> | |
< primitive("case",case_branch,0);@/ | |
< @!@:case_}{\.{\\case} primitive@> | |
< primitive("else",else_code,0);@/ | |
< @!@:else_}{\.{\\else} primitive@> | |
4755,4760c5615,5620 | |
< primitive("groupbegin",group_begin,0);@/ | |
< @!@:group_begin_}{\.{\\groupbegin} primitive@> | |
< primitive("groupend",group_end,0);@/ | |
< @!@:group_end_}{\.{\\groupend} primitive@> | |
< primitive(" ",ex_space,0);@/ | |
< @!@:Single-character primitives /}{\quad\.{\\\ }@> | |
--- | |
> primitive("parshape",set_shape,0);@/ | |
> @!@:par_shape_}{\.{\\parshape} primitive@> | |
> primitive("penalty",break_penalty,0);@/ | |
> @!@:penalty_}{\.{\\penalty} primitive@> | |
> primitive("prevgraf",set_prev_graf,0);@/ | |
> @!@:prev_graf_}{\.{\\prevgraf} primitive@> | |
4762a5623,5641 | |
> primitive("read",read_to_cs,0);@/ | |
> @!@:read_}{\.{\\read} primitive@> | |
> primitive("relax",relax,256); {cf.\ |scan_file_name|} | |
> @!@:relax_}{\.{\\relax} primitive@> | |
> text(frozen_relax):="relax"; eqtb[frozen_relax]:=eqtb[cur_val];@/ | |
> primitive("setbox",set_box,0);@/ | |
> @!@:set_box_}{\.{\\setbox} primitive@> | |
> primitive("the",the,0);@/ | |
> @!@:the_}{\.{\\the} primitive@> | |
> primitive("toks",toks_register,0);@/ | |
> @!@:toks_}{\.{\\toks} primitive@> | |
> primitive("vadjust",vadjust,0);@/ | |
> @!@:vadjust_}{\.{\\vadjust} primitive@> | |
> primitive("valign",valign,0);@/ | |
> @!@:valign_}{\.{\\valign} primitive@> | |
> primitive("vcenter",vcenter,0);@/ | |
> @!@:vcenter_}{\.{\\vcenter} primitive@> | |
> primitive("vrule",vrule,0);@/ | |
> @!@:vrule_}{\.{\\vrule} primitive@> | |
4768c5647 | |
< explained below. | |
--- | |
> below. | |
4771,4776c5650,5655 | |
< relax: print_esc("relax"); | |
< let: print_esc("let"); | |
< char_num: print_esc("char"); | |
< math_char_num: print_esc("mathchar"); | |
< mark: print_esc("mark"); | |
< input: print_esc("input"); | |
--- | |
> accent: print_esc("accent"); | |
> advance: print_esc("advance"); | |
> after_assignment: print_esc("afterassignment"); | |
> after_group: print_esc("aftergroup"); | |
> assign_font_dimen: print_esc("fontdimen"); | |
> begin_group: print_esc("begingroup"); | |
4777a5657,5658 | |
> char_num: print_esc("char"); | |
> cs_name: print_esc("csname"); | |
4779,4785c5660,5665 | |
< set_font: print_esc(":"); | |
< set_family: print_esc("fam"); | |
< number: print_esc("number"); | |
< set_box: print_esc("setbox"); | |
< unbox: print_esc("unbox"); | |
< unskip: print_esc("unskip"); | |
< last_skip: print_esc("lastskip"); | |
--- | |
> delim_num: print_esc("delimiter"); | |
> divide: print_esc("divide"); | |
> end_cs_name: print_esc("endcsname"); | |
> end_group: print_esc("endgroup"); | |
> ex_space: print_esc(" "); | |
> expand_after: print_esc("expandafter"); | |
4787,4789d5666 | |
< valign: print_esc("valign"); | |
< no_align: print_esc("noalign"); | |
< vrule: print_esc("vrule"); | |
4790a5668 | |
> ignore_spaces: print_esc("ignorespaces"); | |
4792,4794d5669 | |
< vadjust: print_esc("vadjust"); | |
< ignore_space: print_esc("ignorespace"); | |
< set_shape: print_esc("parshape"); | |
4796c5671 | |
< accent: print_esc("accent"); | |
--- | |
> mark: print_esc("mark"); | |
4798,4800c5673,5678 | |
< assign_tex_info: print_esc("texinfo"); | |
< delim_num: print_esc("delimiter"); | |
< limit_switch: print_esc("limitswitch"); | |
--- | |
> math_char_num: print_esc("mathchar"); | |
> math_choice: print_esc("mathchoice"); | |
> multiply: print_esc("multiply"); | |
> no_align: print_esc("noalign"); | |
> no_boundary:print_esc("noboundary"); | |
> no_expand: print_esc("noexpand"); | |
4802,4804d5679 | |
< vcenter: print_esc("vcenter"); | |
< case_branch: print_esc("case"); | |
< else_code: print_esc("else"); | |
4806,4808d5680 | |
< group_begin: print_esc("groupbegin"); | |
< group_end: print_esc("groupend"); | |
< ex_space: print_esc(" "); | |
4810,4813c5682,5696 | |
< | |
< @ We will deal with the other primitives later, at some point in the program | |
< where their |eq_type| and |equiv| values are more meaningful. For example, | |
< the primitives for math mode will be loaded when we consider the routines | |
--- | |
> read_to_cs: print_esc("read"); | |
> relax: print_esc("relax"); | |
> set_box: print_esc("setbox"); | |
> set_prev_graf: print_esc("prevgraf"); | |
> set_shape: print_esc("parshape"); | |
> the: print_esc("the"); | |
> toks_register: print_esc("toks"); | |
> vadjust: print_esc("vadjust"); | |
> valign: print_esc("valign"); | |
> vcenter: print_esc("vcenter"); | |
> vrule: print_esc("vrule"); | |
> | |
> @ We will deal with the other primitives later, at some point in the program | |
> where their |eq_type| and |equiv| values are more meaningful. For example, | |
> the primitives for math mode will be loaded when we consider the routines | |
4816c5699 | |
< module where |"radical"| entered |eqtb| is listed under `\.{\\radical} | |
--- | |
> section where |"radical"| entered |eqtb| is listed under `\.{\\radical} | |
4819a5703,5709 | |
> | |
> Meanwhile, this is a convenient place to catch up on something we were unable | |
> to do before the hash table was defined: | |
> | |
> @<Print the font identifier for |font(p)|@>= | |
> print_esc(font_id_text(font(p))) | |
> | |
4821c5711 | |
< The nested structure provided by `$\.{\char'173}\ldotsm\.{\char'175}$' groups | |
--- | |
> The nested structure provided by `$\.{\char'173}\ldots\.{\char'175}$' groups | |
4834c5724 | |
< interpreted in one of three ways: | |
--- | |
> interpreted in one of four ways: | |
4836c5726 | |
< \yskip\hang 1) If |save_type(p)=restore_old_value|, then | |
--- | |
> \yskip\hangg 1) If |save_type(p)=restore_old_value|, then | |
4839c5729 | |
< Furthermore if |save_index(p)≥int_base|, then |save_level(p)| | |
--- | |
> Furthermore if |save_index(p)>=int_base|, then |save_level(p)| | |
4842c5732 | |
< \yskip\hang 2) If |save_type(p)=restore_zero|, then |save_index(p)| | |
--- | |
> \yskip\hangg 2) If |save_type(p)=restore_zero|, then |save_index(p)| | |
4844c5734,5735 | |
< of the current group and replaced by |eqtb[undefined_control_sequence]|. | |
--- | |
> of the current group, when it should be | |
> replaced by the current value of |eqtb[undefined_control_sequence]|. | |
4846c5737,5741 | |
< \yskip\hang 3) If |save_type(p)=level_boundary|, then |save_level(p)| | |
--- | |
> \yskip\hangg 3) If |save_type(p)=insert_token|, then |save_index(p)| | |
> is a token that should be inserted into \TeX's input when the current | |
> group ends. | |
> | |
> \yskip\hangg 4) If |save_type(p)=level_boundary|, then |save_level(p)| | |
4853c5748 | |
< {saved level for regions 6 and 7, or group code} | |
--- | |
> {saved level for regions 5 and 6, or group code} | |
4855c5750 | |
< {|eqtb| location or |save_stack| location} | |
--- | |
> {|eqtb| location or token or |save_stack| location} | |
4858c5753,5754 | |
< @d level_boundary=2 {|save_type| corresponding to beginning of group} | |
--- | |
> @d insert_token=2 {|save_type| when a token is being saved for later use} | |
> @d level_boundary=3 {|save_type| corresponding to beginning of group} | |
4866c5762 | |
< the `\.\$' that begins a math formula causes a |math_delim_group| to | |
--- | |
> the `\.\$' that begins a math formula causes a |math_shift_group| to | |
4869c5765 | |
< one that starts with \.{\\groupbegin} should end with \.{\\groupend}. | |
--- | |
> one that starts with \.{\\begingroup} should end with \.{\\endgroup}. | |
4874,4889c5770,5784 | |
< @d vbox_group=3 {code for `\.{\\vbox}\grp'} | |
< @d vtop_group=4 {code for `\.{\\vtop}\grp'} | |
< @d true_group=5 {code for `\.{\\if...}\grp'} | |
< @d false_group=6 {code for `\.{\\else}\grp'} | |
< @d case_group=7 {code for `\.{\\case}\grp'} | |
< @d align_group=8 {code for `\.{\\halign}\grp', `\.{\\valign}\grp'} | |
< @d no_align_group=9 {code for `\.{\\noalign}\grp'} | |
< @d output_group=10 {code for output routine} | |
< @d math_group=11 {code for, e.g, `\.{\char'176}\grp'} | |
< @d disc_group=12 {code for `\.{\\discretionary}\grp\grp\grp'} | |
< @d insert_group=13 {code for `\.{\\insert}\grp', `\.{\\vadjust}\grp'} | |
< @d vcenter_group=14 {code for `\.{\\vcenter}\grp'} | |
< @d semi_simple_group=15 {code for `\.{\\groupbegin...\\groupend}'} | |
< @d math_delim_group=16 {code for `\.{\$...\$}'} | |
< @d math_left_group=17 {code for `\.{\\left...\\right}'} | |
< @d max_group_code=17 | |
--- | |
> @d adjusted_hbox_group=3 {code for `\.{\\hbox}\grp' in vertical mode} | |
> @d vbox_group=4 {code for `\.{\\vbox}\grp'} | |
> @d vtop_group=5 {code for `\.{\\vtop}\grp'} | |
> @d align_group=6 {code for `\.{\\halign}\grp', `\.{\\valign}\grp'} | |
> @d no_align_group=7 {code for `\.{\\noalign}\grp'} | |
> @d output_group=8 {code for output routine} | |
> @d math_group=9 {code for, e.g., `\.{\char'136}\grp'} | |
> @d disc_group=10 {code for `\.{\\discretionary}\grp\grp\grp'} | |
> @d insert_group=11 {code for `\.{\\insert}\grp', `\.{\\vadjust}\grp'} | |
> @d vcenter_group=12 {code for `\.{\\vcenter}\grp'} | |
> @d math_choice_group=13 {code for `\.{\\mathchoice}\grp\grp\grp\grp'} | |
> @d semi_simple_group=14 {code for `\.{\\begingroup...\\endgroup}'} | |
> @d math_shift_group=15 {code for `\.{\$...\$}'} | |
> @d math_left_group=16 {code for `\.{\\left...\\right}'} | |
> @d max_group_code=16 | |
4892c5787 | |
< @!group_code=0..max_group_code; {|save_index| for a level boundary} | |
--- | |
> @!group_code=0..max_group_code; {|save_level| for a level boundary} | |
4896,4898c5791,5792 | |
< topmost |level_boundary| word. And |cur_level| is the current depth | |
< of nesting, not counting |true_group| and |false_group| and |case_group| | |
< levels. The routines are designed to preserve the condition that no entry | |
--- | |
> topmost |level_boundary| word. And |cur_level| is the current depth of | |
> nesting. The routines are designed to preserve the condition that no entry | |
4901c5795 | |
< @ @<Globals...@>= | |
--- | |
> @ @<Glob...@>= | |
4915,4916c5809,5810 | |
< save_ptr←0; cur_level←level_one; cur_group←bottom_level; cur_boundary←0; | |
< max_save_stack←0; | |
--- | |
> save_ptr:=0; cur_level:=level_one; cur_group:=bottom_level; cur_boundary:=0; | |
> max_save_stack:=0; | |
4923,4925c5817,5820 | |
< begin max_save_stack←save_ptr; | |
< if max_save_stack>save_size-6 then overflow("save size",save_size); | |
< end | |
--- | |
> begin max_save_stack:=save_ptr; | |
> if max_save_stack>save_size-6 then overflow("save size",save_size); | |
> @:TeX capacity exceeded save size}{\quad save size@> | |
> end | |
4931c5826 | |
< In some cases a few integer-valued items are placed onto the | |
--- | |
> In some cases integer-valued items are placed onto the | |
4946,4947c5841,5842 | |
< save_type(save_ptr)←level_boundary; save_level(save_ptr)←cur_group; | |
< save_index(save_ptr)←cur_boundary; | |
--- | |
> save_type(save_ptr):=level_boundary; save_level(save_ptr):=cur_group; | |
> save_index(save_ptr):=cur_boundary; | |
4949,4951c5844,5847 | |
< max_quarterword-min_quarterword); | |
< {quit if |(cur_level+1)| is too big to be stored in |eqtb|} | |
< cur_boundary←save_ptr; incr(cur_level); incr(save_ptr); cur_group←c; | |
--- | |
> @:TeX capacity exceeded grouping levels}{\quad grouping levels@> | |
> max_quarterword-min_quarterword); | |
> {quit if |(cur_level+1)| is too big to be stored in |eqtb|} | |
> cur_boundary:=save_ptr; incr(cur_level); incr(save_ptr); cur_group:=c; | |
4956c5852 | |
< to keep in mind that reference counts in |m| include references from | |
--- | |
> to keep in mind that reference counts in |mem| include references from | |
4957a5854 | |
> @^reference counts@> | |
4964,4966c5861,5863 | |
< shape_ref: begin q←equiv_field(w); {we need to free a \.{\\parshape} block} | |
< if q≠null then free_node(q,link(q)+link(q)+1); | |
< end; | |
--- | |
> shape_ref: begin q:=equiv_field(w); {we need to free a \.{\\parshape} block} | |
> if q<>null then free_node(q,info(q)+info(q)+1); | |
> end; {such a block is |2n+1| words long, where |n=info(q)|} | |
4972c5869 | |
< @ To save a value of |eqtb[p]| that was defined at level |l|, we | |
--- | |
> @ To save a value of |eqtb[p]| that was established at level |l|, we | |
4977,4981c5874,5878 | |
< if l=level_zero then save_type(save_ptr)←restore_zero | |
< else begin save_stack[save_ptr]←eqtb[p]; incr(save_ptr); | |
< save_type(save_ptr)←restore_old_value; | |
< end; | |
< save_level(save_ptr)←l; save_index(save_ptr)←p; incr(save_ptr); | |
--- | |
> if l=level_zero then save_type(save_ptr):=restore_zero | |
> else begin save_stack[save_ptr]:=eqtb[p]; incr(save_ptr); | |
> save_type(save_ptr):=restore_old_value; | |
> end; | |
> save_level(save_ptr):=l; save_index(save_ptr):=p; incr(save_ptr); | |
4993c5890 | |
< {new data for |eqtb|} | |
--- | |
> {new data for |eqtb|} | |
4996c5893 | |
< eq_level(p)←cur_level; eq_type(p)←t; equiv(p)←e; | |
--- | |
> eq_level(p):=cur_level; eq_type(p):=t; equiv(p):=e; | |
5000c5897 | |
< |eqtb| is called |eq_word_define|. Since |xeq_level[p]≥level_one| for all | |
--- | |
> |eqtb| is called |eq_word_define|. Since |xeq_level[p]>=level_one| for all | |
5004,5007c5901,5904 | |
< begin if xeq_level[p]≠cur_level then | |
< begin eq_save(p,xeq_level[p]); xeq_level[p]←cur_level; | |
< end; | |
< eqtb[p].int←w; | |
--- | |
> begin if xeq_level[p]<>cur_level then | |
> begin eq_save(p,xeq_level[p]); xeq_level[p]:=cur_level; | |
> end; | |
> eqtb[p].int:=w; | |
5012c5909 | |
< Global defi\-ni\-tions are done in almost the same way, but there is no need | |
--- | |
> Global definitions are done in almost the same way, but there is no need | |
5016c5913 | |
< {global |eq_define|} | |
--- | |
> {global |eq_define|} | |
5018c5915 | |
< eq_level(p)←level_one; eq_type(p)←t; equiv(p)←e; | |
--- | |
> eq_level(p):=level_one; eq_type(p):=t; equiv(p):=e; | |
5022c5919 | |
< begin eqtb[p].int←w; xeq_level[p]←level_one; | |
--- | |
> begin eqtb[p].int:=w; xeq_level[p]:=level_one; | |
5025,5027c5922,5930 | |
< @ The |unsave| routine goes the other way, taking items off of |save_stack|; | |
< it is not used when |cur_group| is |true_group|, |false_group|, or |case_group|, | |
< since those groups are ``transparent'' with respect to their environment. | |
--- | |
> @ Subroutine |save_for_after| puts a token on the stack for save-keeping. | |
> | |
> @p procedure save_for_after(@!t:halfword); | |
> begin if cur_level>level_one then | |
> begin check_full_save_stack; | |
> save_type(save_ptr):=insert_token; save_level(save_ptr):=level_zero; | |
> save_index(save_ptr):=t; incr(save_ptr); | |
> end; | |
> end; | |
5028a5932 | |
> @ The |unsave| routine goes the other way, taking items off of |save_stack|. | |
5032c5936,5938 | |
< @p procedure unsave; {pops the top level off the save stack} | |
--- | |
> @p@t\4@>@<Declare the procedure called |restore_trace|@>@;@/ | |
> procedure@?back_input; forward; @t\2@> | |
> procedure unsave; {pops the top level off the save stack} | |
5035a5942 | |
> @!t:halfword; {saved value of |cur_tok|} | |
5037,5039c5944,5946 | |
< begin decr(cur_level); | |
< @<Clear off top level from |save_stack|@>; | |
< end | |
--- | |
> begin decr(cur_level); | |
> @<Clear off top level from |save_stack|@>; | |
> end | |
5041c5948 | |
< @:confusion curlevel}{\quad curlevel@> | |
--- | |
> @:this can't happen curlevel}{\quad curlevel@> | |
5046,5055c5953,5965 | |
< if save_type(save_ptr)=level_boundary then goto done; | |
< p←save_index(save_ptr); | |
< if save_type(save_ptr)=restore_old_value then | |
< begin l←save_level(save_ptr); decr(save_ptr); | |
< end | |
< else save_stack[save_ptr]←eqtb[undefined_control_sequence]; | |
< @<Store \(s)|save_stack[save_ptr]| in |eqtb[p]|, unless | |
< |eqtb[p]| holds a global value@>; | |
< end; | |
< done: cur_group←save_level(save_ptr); cur_boundary←save_index(save_ptr) | |
--- | |
> if save_type(save_ptr)=level_boundary then goto done; | |
> p:=save_index(save_ptr); | |
> if save_type(save_ptr)=insert_token then | |
> @<Insert token |p| into \TeX's input@> | |
> else begin if save_type(save_ptr)=restore_old_value then | |
> begin l:=save_level(save_ptr); decr(save_ptr); | |
> end | |
> else save_stack[save_ptr]:=eqtb[undefined_control_sequence]; | |
> @<Store \(s)|save_stack[save_ptr]| in |eqtb[p]|, unless | |
> |eqtb[p]| holds a global value@>; | |
> end; | |
> end; | |
> done: cur_group:=save_level(save_ptr); cur_boundary:=save_index(save_ptr) | |
5065,5090c5975,6018 | |
< if eq_level(p)=level_one then | |
< eq_destroy(save_stack[save_ptr]) {destroy the saved value} | |
< else begin eq_destroy(eqtb[p]); {destroy the current value} | |
< eqtb[p]←save_stack[save_ptr]; {restore the saved value} | |
< end | |
< else if xeq_level[p]≠level_one then | |
< begin eqtb[p]←save_stack[save_ptr]; xeq_level[p]←l; | |
< end | |
< | |
< @ When a |true_group| or one of its relatives comes to an end, we merely | |
< want to delete the top |level_boundary| word, restoring the former | |
< values of |cur_group| and |cur_boundary|. The |leave_transparent_group| | |
< routine does this. | |
< | |
< @p procedure leave_transparent_group; | |
< var j,@!k:0..save_size; {indices into |save_stack|} | |
< begin j←save_index(cur_boundary); cur_group←save_level(cur_boundary); | |
< if save_ptr>1 then | |
< for k←cur_boundary to save_ptr-2 do save_stack[k]←save_stack[k+1]; | |
< decr(save_ptr); cur_boundary←j; | |
< end; | |
< | |
< @ The magnification parameter should not be varied during a \TeX\ job, since | |
< a single magnification is applied to an entire run. The global variable | |
< |mag_set| is set to the current magnification whenever it becomes necessary | |
< to ``freeze'' the magnification at a particular value. | |
--- | |
> if eq_level(p)=level_one then | |
> begin eq_destroy(save_stack[save_ptr]); {destroy the saved value} | |
> @!stat if tracing_restores>0 then restore_trace(p,"retaining");@+tats@;@/ | |
> end | |
> else begin eq_destroy(eqtb[p]); {destroy the current value} | |
> eqtb[p]:=save_stack[save_ptr]; {restore the saved value} | |
> @!stat if tracing_restores>0 then restore_trace(p,"restoring");@+tats@;@/ | |
> end | |
> else if xeq_level[p]<>level_one then | |
> begin eqtb[p]:=save_stack[save_ptr]; xeq_level[p]:=l; | |
> @!stat if tracing_restores>0 then restore_trace(p,"restoring");@+tats@;@/ | |
> end | |
> else begin | |
> @!stat if tracing_restores>0 then restore_trace(p,"retaining");@+tats@;@/ | |
> end | |
> | |
> @ @<Declare the procedure called |restore_trace|@>= | |
> @!stat procedure restore_trace(@!p:pointer;@!s:str_number); | |
> {|eqtb[p]| has just been restored or retained} | |
> begin begin_diagnostic; print_char("{"); print(s); print_char(" "); | |
> show_eqtb(p); print_char("}"); | |
> end_diagnostic(false); | |
> end; | |
> tats | |
> | |
> @ When looking for possible pointers to a memory location, it is helpful | |
> to look for references from |eqtb| that might be waiting on the | |
> save stack. Of course, we might find spurious pointers too; but this | |
> routine is merely an aid when debugging, and at such times we are | |
> grateful for any scraps of information, even if they prove to be irrelevant. | |
> @^dirty \PASCAL@> | |
> | |
> @<Search |save_stack| for equivalents that point to |p|@>= | |
> if save_ptr>0 then for q:=0 to save_ptr-1 do | |
> begin if equiv_field(save_stack[q])=p then | |
> begin print_nl("SAVE("); print_int(q); print_char(")"); | |
> end; | |
> end | |
> | |
> @ Most of the parameters kept in |eqtb| can be changed freely, but there's | |
> an exception: The magnification should not be used with two different | |
> values during any \TeX\ job, since a single magnification is applied to an | |
> entire run. The global variable |mag_set| is set to the current magnification | |
> whenever it becomes necessary to ``freeze'' it at a particular value. | |
5096c6024 | |
< mag_set←0; | |
--- | |
> mag_set:=0; | |
5102,5103c6030,6031 | |
< begin if (mag_set>0)∧(mag≠mag_set) then | |
< begin print_nl("! Incompatible magnification ("); print_int(mag); | |
--- | |
> begin if (mag_set>0)and(mag<>mag_set) then | |
> begin print_err("Incompatible magnification ("); print_int(mag); | |
5105,5112c6033,6040 | |
< print("); the previous value will be retained"); | |
< help2("I can handle only one magnification ratio per job. So I've")@/ | |
< ("reverted to the magnification you used earlier on this run.");@/ | |
< int_error(mag_set); | |
< geq_word_define(int_base+mag_code,mag_set); {|mag←mag_set|} | |
< end; | |
< if (mag≤0)∨(mag>32768) then | |
< begin print_nl("! Illegal magnification has been changed to 1000");@/ | |
--- | |
> print(");"); print_nl(" the previous value will be retained"); | |
> help2("I can handle only one magnification ratio per job. So I've")@/ | |
> ("reverted to the magnification you used earlier on this run.");@/ | |
> int_error(mag_set); | |
> geq_word_define(int_base+mag_code,mag_set); {|mag:=mag_set|} | |
> end; | |
> if (mag<=0)or(mag>32768) then | |
> begin print_err("Illegal magnification has been changed to 1000");@/ | |
5114,5117c6042,6045 | |
< help1("The magnification ratio must be between 1 and 32768."); | |
< int_error(mag); geq_word_define(int_base+mag_code,1000); | |
< end; | |
< mag_set←mag; | |
--- | |
> help1("The magnification ratio must be between 1 and 32768."); | |
> int_error(mag); geq_word_define(int_base+mag_code,1000); | |
> end; | |
> mag_set:=mag; | |
5118a6047 | |
> | |
5122,5128c6051,6057 | |
< represented internally in one of two ways: (1)@@A character whose ascii code | |
< number is |c| and whose command code is |m| is represented as the | |
< number $2^8m+c$; the command code is in the range | |
< |1≤m≤14|. (2)@@A control sequence whose |eqtb| address is |p| is | |
< represented as the number |cs_token_flag+p|. Here |cs_token_flag=@t$2^{12}$@>| | |
< is larger than $2^8m+c$, yet it is small enough that |cs_token_flag+p< | |
< max_halfword|; thus, a token fits comfortably in a halfword. | |
--- | |
> represented internally in one of two ways: (1)~A character whose ASCII | |
> code number is |c| and whose command code is |m| is represented as the | |
> number $2^8m+c$; the command code is in the range |1<=m<=14|. (2)~A control | |
> sequence whose |eqtb| address is |p| is represented as the number | |
> |cs_token_flag+p|. Here |cs_token_flag=@t$2^{12}-1$@>| is larger than | |
> $2^8m+c$, yet it is small enough that |cs_token_flag+p< max_halfword|; | |
> thus, a token fits comfortably in a halfword. | |
5132,5133c6061,6062 | |
< we have |left_brace_limit≤t<right_brace_limit|; and it represents a |match| or | |
< |end_match| command if and only if |match_token≤t≤end_match_token|. | |
--- | |
> we have |left_brace_limit<=t<right_brace_limit|; and it represents a |match| or | |
> |end_match| command if and only if |match_token<=t<=end_match_token|. | |
5137,5138c6066,6067 | |
< @d cs_token_flag==@'10000 {amount added to the |eqtb| location in a | |
< token that stands for a control sequence} | |
--- | |
> @d cs_token_flag==@'7777 {amount added to the |eqtb| location in a | |
> token that stands for a control sequence; is a multiple of~256, less~1} | |
5143c6072,6073 | |
< @d math_delim_token=@'1400 {$2^8\cdot|math_delim|$} | |
--- | |
> @d math_shift_token=@'1400 {$2^8\cdot|math_shift|$} | |
> @d tab_token=@'2000 {$2^8\cdot|tab_mark|$} | |
5145d6074 | |
< @d endv_token=@'4400 {$2^8\cdot|endv|$} | |
5153c6082 | |
< if cs_token_flag+undefined_control_sequence>max_halfword then bad←21; | |
--- | |
> if cs_token_flag+undefined_control_sequence>max_halfword then bad:=21; | |
5157,5158c6086,6088 | |
< definitions, marks, and \.{\\send} texts are kept in \TeX's memory in the | |
< form of token lists, preceded by a node that has a reference count in its | |
--- | |
> definitions, marks, \.{\\write} texts, and a few other things | |
> are remembered by \TeX\ in the form | |
> of token lists, usually preceded by a node with a reference count in its | |
5180c6110 | |
< |letter|\,\.{\\b}, |end_match|,\cr | |
--- | |
> \.{\\b}, |end_match|,\cr | |
5185c6115 | |
< does the param\-eter matching. | |
--- | |
> does the parameter matching. | |
5208c6138 | |
< An additional parameter |q| is also given; this parameter is either zero | |
--- | |
> An additional parameter |q| is also given; this parameter is either null | |
5210c6140 | |
< takes place that will be explained later. (Basically, |q| is nonzero when | |
--- | |
> takes place that will be explained later. (Basically, |q| is non-null when | |
5222c6152 | |
< of printing exceeds a given limit@@|l|. Anomalous entries are printed in the | |
--- | |
> of printing exceeds a given limit~|l|. Anomalous entries are printed in the | |
5231,5239c6161,6170 | |
< @!match_chr:ascii_code; {character used in a `|match|'} | |
< @!n:ascii_code; {the highest parameter number, as an ascii digit} | |
< begin match_chr←"#"; n←"0"; tally←0; | |
< while (p≠null) and (tally<l) do | |
< begin if p=q then @<Do magic computation@>; | |
< @<Display token |p|, and |return| if there are problems@>; | |
< p←link(p); | |
< end; | |
< if p≠null then print_esc("ETC."); | |
--- | |
> @!match_chr:ASCII_code; {character used in a `|match|'} | |
> @!n:ASCII_code; {the highest parameter number, as an ASCII digit} | |
> begin match_chr:="#"; n:="0"; tally:=0; | |
> while (p<>null) and (tally<l) do | |
> begin if p=q then @<Do magic computation@>; | |
> @<Display token |p|, and |return| if there are problems@>; | |
> p:=link(p); | |
> end; | |
> if p<>null then print_esc("ETC."); | |
> @.ETC@> | |
5244,5251c6175,6184 | |
< if (p<hi_mem_base) or (p>mem_end) then | |
< begin print_esc("CLOBBERED."); return; | |
< end; | |
< if info(p)≥cs_token_flag then print_cs(info(p)-cs_token_flag) | |
< else begin m←info(p) div @'400; c←info(p) mod @'400; | |
< if (info(p)<0)∨(c>127) then print_esc("BAD.") | |
< else @<Display the token $(|m|,|c|)$@>; | |
< end | |
--- | |
> if (p<hi_mem_min) or (p>mem_end) then | |
> begin print_esc("CLOBBERED."); return; | |
> @.CLOBBERED@> | |
> end; | |
> if info(p)>=cs_token_flag then print_cs(info(p)-cs_token_flag) | |
> else begin m:=info(p) div @'400; c:=info(p) mod @'400; | |
> if info(p)<0 then print_esc("BAD.") | |
> @.BAD@> | |
> else @<Display the token $(|m|,|c|)$@>; | |
> end | |
5254c6187 | |
< param\-eters by seeing one in a |match| command before it runs into any | |
--- | |
> parameters by seeing one in a |match| command before it runs into any | |
5259,5266c6192,6193 | |
< right_brace,math_delim,tab_mark,sup_mark,sub_mark,spacer, | |
< letter,other_char: print(c); | |
< left_brace:begin if (link(p)≥hi_mem_base)∧(link(p)≤mem_end) then | |
< if info(link(p)) div @'400=end_match then | |
< print(match_chr); | |
< print(c); | |
< end; | |
< endv:print_esc("ENDTEMPLATE."); | |
--- | |
> left_brace,right_brace,math_shift,tab_mark,sup_mark,sub_mark,spacer, | |
> letter,other_char: print(c); | |
5268c6195 | |
< end; | |
--- | |
> end; | |
5270,5276c6197,6203 | |
< if c≤9 then print_char(c+"0") | |
< else begin print_char("!"); return; | |
< end; | |
< end; | |
< match: begin match_chr←c; print(c); incr(n); print_char(n); | |
< if n>"9" then return; | |
< end; | |
--- | |
> if c<=9 then print_char(c+"0") | |
> else begin print_char("!"); return; | |
> end; | |
> end; | |
> match: begin match_chr:=c; print(c); incr(n); print_char(n); | |
> if n>"9" then return; | |
> end; | |
5277a6205 | |
> @.->@> | |
5278a6207 | |
> @.BAD@> | |
5285,5286c6214,6228 | |
< begin if p=null then print("(null)") | |
< else show_token_list(link(p),null,1000); | |
--- | |
> begin if p<>null then show_token_list(link(p),null,10000000); | |
> end; | |
> | |
> @ The |print_meaning| subroutine displays |cur_cmd| and |cur_chr| in | |
> symbolic form, including the expansion of a macro or mark. | |
> | |
> @p procedure print_meaning; | |
> begin print_cmd_chr(cur_cmd,cur_chr); | |
> if cur_cmd>=call then | |
> begin print_char(":"); print_ln; token_show(cur_chr); | |
> end | |
> else if cur_cmd=top_bot_mark then | |
> begin print_char(":"); print_ln; | |
> token_show(cur_mark[cur_chr]); | |
> end; | |
5287a6230 | |
> | |
5303,5308c6246,6255 | |
< sets the value of two variables |cur_cmd| and |cur_chr|, representing | |
< the next input token. | |
< $$\lpile{\hbox{|cur_cmd| denotes a command code from the long list of codes | |
< given above;}\cr | |
< \hbox{|cur_chr| denotes a character code or other modifier of the command | |
< code.}\cr}$$ | |
--- | |
> sets the value of three variables |cur_cmd|, |cur_chr|, and |cur_cs|, | |
> representing the next input token. | |
> $$\vbox{\halign{#\hfil\cr | |
> \hbox{|cur_cmd| denotes a command code from the long list of codes | |
> given above;}\cr | |
> \hbox{|cur_chr| denotes a character code or other modifier of the command | |
> code;}\cr | |
> \hbox{|cur_cs| is the |eqtb| location of the current control sequence,}\cr | |
> \hbox{\qquad if the current token was a control sequence, | |
> otherwise it's zero.}\cr}}$$ | |
5331,5332c6278,6279 | |
< @<Globals...@>= | |
< @!cur_cmd : eight_bits; {current command set by |get_next|} | |
--- | |
> @<Glob...@>= | |
> @!cur_cmd: eight_bits; {current command set by |get_next|} | |
5334c6281,6282 | |
< @!cur_tok:halfword; {packed representative of |cur_cmd| and |cur_chr|} | |
--- | |
> @!cur_cs: pointer; {control sequence found here, zero if none found} | |
> @!cur_tok: halfword; {packed representative of |cur_cmd| and |cur_chr|} | |
5347,5348c6295,6296 | |
< @d chr_cmd(#)==begin print(#); print_ascii(chr_code); | |
< end | |
--- | |
> @d chr_cmd(#)==begin print(#); print_ASCII(chr_code); | |
> end | |
5350c6298,6299 | |
< @p procedure print_cmd_chr(@!cmd:quarterword;@!chr_code:halfword); | |
--- | |
> @<Declare the procedure called |print_cmd_chr|@>= | |
> procedure print_cmd_chr(@!cmd:quarterword;@!chr_code:halfword); | |
5354,5357c6303 | |
< math_delim: chr_cmd("math mode character "); | |
< tab_mark: if chr_code=128 then print_esc("span") {|span_code=128|} | |
< else chr_cmd("alignment tab character "); | |
< car_ret: print_esc("cr"); | |
--- | |
> math_shift: chr_cmd("math shift character "); | |
5362c6308 | |
< spacer: print("blank space"); | |
--- | |
> spacer: chr_cmd("blank space "); | |
5368a6315,6326 | |
> | |
> @ Here is a procedure that displays the current command. | |
> | |
> @p procedure show_cur_cmd_chr; | |
> begin begin_diagnostic; print_nl("{"); | |
> if mode<>shown_mode then | |
> begin print_mode(mode); print(": "); shown_mode:=mode; | |
> end; | |
> print_cmd_chr(cur_cmd,cur_chr); print_char("}"); | |
> end_diagnostic(false); | |
> end; | |
> | |
5369a6328 | |
> This implementation of | |
5373c6332 | |
< \yskip\hang 1) If there is frequent access to the top entry, and if the | |
--- | |
> \yskip\hangg 1) If there is frequent access to the top entry, and if the | |
5380c6339 | |
< \yskip\hang 2) If there is infrequent top access, the entire stack contents | |
--- | |
> \yskip\hangg 2) If there is infrequent top access, the entire stack contents | |
5388c6347 | |
< convention@@(1), so it is declared in the following way: | |
--- | |
> convention~(1), so it is declared in the following way: | |
5391,5394c6350,6353 | |
< @!in_state_record = record | |
< @!state_field, @!index_field: quarterword; | |
< @!start_field,@!loc_field, @!limit_field, @!name_field: halfword; | |
< end; | |
--- | |
> @!in_state_record = record | |
> @!state_field, @!index_field: quarterword; | |
> @!start_field,@!loc_field, @!limit_field, @!name_field: halfword; | |
> end; | |
5396c6355 | |
< @ @<Globals...@>= | |
--- | |
> @ @<Glob...@>= | |
5401c6360 | |
< {the ``top'' input state, according to convention (1)} | |
--- | |
> {the ``top'' input state, according to convention (1)} | |
5403c6362 | |
< @ We've already defined the special variables |@!loc==cur_input.loc_field| | |
--- | |
> @ We've already defined the special variable |loc==cur_input.loc_field| | |
5405c6364 | |
< the |cur_input| are defined in the same way: | |
--- | |
> |cur_input| are defined in the same way: | |
5413,5414c6372,6373 | |
< @ Let's look more closely now at the six control variables | |
< (|state|,@@|index|,@@|start|,@@|loc|,@@|limit|,@@|name|), | |
--- | |
> @ Let's look more closely now at the control variables | |
> (|state|,~|index|,~|start|,~|loc|,~|limit|,~|name|), | |
5419,5420c6378,6379 | |
< levels of the input stack that are not yet completed. We will return to | |
< the other lines when we are finished with the present input file. | |
--- | |
> levels of the input stack that are not yet completed. \TeX\ will return to | |
> the other lines when it is finished with the present input file. | |
5422c6381 | |
< (Incidentally, on a machine with byte-oriented addressing, it would be | |
--- | |
> (Incidentally, on a machine with byte-oriented addressing, it might be | |
5430,5431c6389,6390 | |
< the line has been completely read. Usually |buffer[limit]| is a | |
< |carriage_return| character, denoting the end of a line, but this is not | |
--- | |
> the line has been completely read. Usually |buffer[limit]| is the | |
> |end_line_char|, denoting the end of a line, but this is not | |
5433c6392 | |
< terminal in response to an error message. | |
--- | |
> terminal in response to an error message. | |
5436,5437c6395,6399 | |
< the current file, if we are reading a text file; it is zero if we | |
< are reading from the terminal. | |
--- | |
> the current file, if we are reading a text file. It is zero if we | |
> are reading from the terminal; it is |n+1| if we are reading from | |
> input stream |n|, where |0<=n<=16|. (Input stream 16 stands for | |
> an invalid stream number; in such cases the input is actually from | |
> the terminal, under control of the procedure |read_toks|.) | |
5463,5464c6425,6426 | |
< stack come from token lists. For example, the instruction `\.{\\input paper}' | |
< might occur in a token list. | |
--- | |
> stack may come from token lists. For example, the instruction `\.{\\input | |
> paper}' might occur in a token list. | |
5466c6428 | |
< The variable |in_open| is equal to the |index| | |
--- | |
> The global variable |in_open| is equal to the |index| | |
5471,5474c6433,6436 | |
< 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]|. | |
--- | |
> If we are not currently reading from the terminal, or from an input | |
> stream, we are reading from the file variable |input_file[index]|. We use | |
> the notation |terminal_input| as a convenient abbreviation for |name=0|, | |
> and |cur_file| as an abbreviation for |input_file[index]|. | |
5480c6442,6444 | |
< file has been read. | |
--- | |
> file has been read. Line numbers should never be negative, since the | |
> negative of the current line number is used to identify the user's output | |
> routine in the |mode_line| field of the semantic nest entries. | |
5486c6450 | |
< `\unskip|@!page_stack:array[0..max_in_open] of integer|' | |
--- | |
> `\ignorespaces|@!page_stack:array[1..max_in_open] of integer|\unskip' | |
5493c6457 | |
< @<Globals...@>= | |
--- | |
> @<Glob...@>= | |
5494a6459 | |
> @!open_parens : 0..max_in_open; {the number of open text files} | |
5497c6462 | |
< @!line_stack : array[0..max_in_open] of integer; | |
--- | |
> @!line_stack : array[1..max_in_open] of integer; | |
5505c6470 | |
< when a subfile ends. This variable has five possible values: | |
--- | |
> when a subfile ends. This variable has six possible values: | |
5520a6486,6488 | |
> \yskip\hang|absorbing|, means that a subfile shouldn't end now because we are | |
> reading a balanced token list for \.{\\message}, \.{\\write}, etc. | |
> | |
5529a6498 | |
> @d absorbing=5 {|scanner_status| when reading a balanced text} | |
5531,5532c6500,6501 | |
< @<Globals...@>= | |
< @!scanner_status : normal..aligning; {can a subfile end now?} | |
--- | |
> @<Glob...@>= | |
> @!scanner_status : normal..absorbing; {can a subfile end now?} | |
5533a6503 | |
> @!def_ref : pointer; {reference count of token list being defined} | |
5542,5552c6512,6525 | |
< begin print_nl("Runaway "); | |
< case scanner_status of | |
< defining: begin print("definition?"); p←temp_head; | |
< end; | |
< matching: begin print("argument?"); p←temp_head; | |
< end; | |
< aligning: begin print("preamble?"); p←hold_head; | |
< end; | |
< end; {there are no other cases} | |
< print_ln; show_token_list(link(p),null,error_line-10); | |
< end; | |
--- | |
> begin print_nl("Runaway "); | |
> @.Runaway...@> | |
> case scanner_status of | |
> defining: begin print("definition"); p:=def_ref; | |
> end; | |
> matching: begin print("argument"); p:=temp_head; | |
> end; | |
> aligning: begin print("preamble"); p:=hold_head; | |
> end; | |
> absorbing: begin print("text"); p:=def_ref; | |
> end; | |
> end; {there are no other cases} | |
> print_char("?");print_ln; show_token_list(link(p),null,error_line-10); | |
> end; | |
5585c6558 | |
< \hang|u_template|, if the \<u↓j> part of an alignment | |
--- | |
> \hang|u_template|, if the \<u_j> part of an alignment | |
5588c6561 | |
< \hang|v_template|, if the \<v↓j> part of an alignment | |
--- | |
> \hang|v_template|, if the \<v_j> part of an alignment | |
5590a6564,6566 | |
> \hang|backed_up|, if the token list being scanned has been inserted as | |
> `to be read again'. | |
> | |
5592,5593c6568 | |
< `to be read again' or as the text expansion of a \.{\\count} or similar | |
< variable; | |
--- | |
> the text expansion of a \.{\\count} or similar variable; | |
5601c6576,6582 | |
< \hang|mark_text|, if the text of a \.{\\mark} is being scanned. | |
--- | |
> \hang|every_math_text|, if the text of \.{\\everymath} is being scanned; | |
> | |
> \hang|every_display_text|, if the text of \.{\\everydisplay} is being scanned; | |
> | |
> \hang|every_hbox_text|, if the text of \.{\\everyhbox} is being scanned; | |
> | |
> \hang|every_vbox_text|, if the text of \.{\\everyvbox} is being scanned; | |
5603c6584,6590 | |
< \hang|send_text|, if the text of a \.{\\send} is being scanned. | |
--- | |
> \hang|every_job_text|, if the text of \.{\\everyjob} is being scanned; | |
> | |
> \hang|every_cr_text|, if the text of \.{\\everycr} is being scanned; | |
> | |
> \hang|mark_text|, if the text of a \.{\\mark} is being scanned; | |
> | |
> \hang|write_text|, if the text of a \.{\\write} is being scanned. | |
5606,5607c6593,6596 | |
< The token list begins with a reference count if and only if |token_type≥ | |
< macro|. | |
--- | |
> The codes for |output_text|, |every_par_text|, etc., are equal to a constant | |
> plus the corresponding codes for token list parameters |output_routine_loc|, | |
> |every_par_loc|, etc. The token list begins with a reference count if and | |
> only if |token_type>=macro|. | |
5614,5621c6603,6617 | |
< @d u_template=1 {|token_type| code for \<u↓j> template} | |
< @d v_template=2 {|token_type| code for \<v↓j> template} | |
< @d inserted=3 {|token_type| code for short inserted texts} | |
< @d macro=4 {|token_type| code for defined control sequences} | |
< @d output_text=5 {|token_type| code for output routines} | |
< @d every_par_text=6 {|token_type| code for \.{\\everypar}} | |
< @d mark_text=7 {|token_type| code for \.{\\topmark}, etc.} | |
< @d send_text=8 {|token_type| code for \.{\\send}} | |
--- | |
> @d u_template=1 {|token_type| code for \<u_j> template} | |
> @d v_template=2 {|token_type| code for \<v_j> template} | |
> @d backed_up=3 {|token_type| code for text to be reread} | |
> @d inserted=4 {|token_type| code for inserted texts} | |
> @d macro=5 {|token_type| code for defined control sequences} | |
> @d output_text=6 {|token_type| code for output routines} | |
> @d every_par_text=7 {|token_type| code for \.{\\everypar}} | |
> @d every_math_text=8 {|token_type| code for \.{\\everymath}} | |
> @d every_display_text=9 {|token_type| code for \.{\\everydisplay}} | |
> @d every_hbox_text=10 {|token_type| code for \.{\\everyhbox}} | |
> @d every_vbox_text=11 {|token_type| code for \.{\\everyvbox}} | |
> @d every_job_text=12 {|token_type| code for \.{\\everyjob}} | |
> @d every_cr_text=13 {|token_type| code for \.{\\everycr}} | |
> @d mark_text=14 {|token_type| code for \.{\\topmark}, etc.} | |
> @d write_text=15 {|token_type| code for \.{\\write}} | |
5628c6624 | |
< @<Globals...@>= | |
--- | |
> @<Glob...@>= | |
5630c6626 | |
< {token list pointers for parameters} | |
--- | |
> {token list pointers for parameters} | |
5633c6629 | |
< {largest value of |param_ptr|, will be |≤param_size+9|} | |
--- | |
> {largest value of |param_ptr|, will be |<=param_size+9|} | |
5638,5642c6634,6638 | |
< \<v↓j> template text in the scanner. This magic is accomplished by an | |
< |align_state| variable that is increased by@@1 when a `\.{\char'173}' is | |
< scanned and decreased by@@1 when a `\.{\char'175}' is scanned. The |align_state| | |
< is nonzero during the \<u↓j> template, after which it is set to zero; the | |
< \<v↓j> template begins when a tab mark or \.{\\cr} occurs at a time that | |
--- | |
> \<v_j> template text in the scanner. This magic is accomplished by an | |
> |align_state| variable that is increased by~1 when a `\.{\char'173}' is | |
> scanned and decreased by~1 when a `\.{\char'175}' is scanned. The |align_state| | |
> is nonzero during the \<u_j> template, after which it is set to zero; the | |
> \<v_j> template begins when a tab mark or \.{\\cr} occurs at a time that | |
5645c6641 | |
< @<Globals...@>= | |
--- | |
> @<Glob...@>= | |
5648c6644 | |
< @ Thus, the ``current input state'' can be very complicated indeed, since there | |
--- | |
> @ Thus, the ``current input state'' can be very complicated indeed; there | |
5663,5664c6659,6660 | |
< at most |error_line|. Input levels whose |token_type| is `|inserted|' | |
< are shown only if they have not been fully read. | |
--- | |
> at most |error_line|. Non-current input levels whose |token_type| is | |
> `|backed_up|' are shown only if they have not been fully read. | |
5668a6665,6666 | |
> @!nn:integer; {number of contexts shown so far, less one} | |
> @!bottom_line:boolean; {have we reached the final context to be shown?} | |
5670,5678c6668,6682 | |
< begin base_ptr←input_ptr; input_stack[base_ptr]←cur_input; | |
< {store current state} | |
< loop@+begin cur_input←input_stack[base_ptr]; {enter into the context} | |
< @<Display the current context@>; | |
< if (state≠token_list) then | |
< if (not terminal_input) or (base_ptr=0) then goto done; | |
< decr(base_ptr); | |
< end; | |
< done: cur_input←input_stack[input_ptr]; {restore original state} | |
--- | |
> begin base_ptr:=input_ptr; input_stack[base_ptr]:=cur_input; | |
> {store current state} | |
> nn:=-1; bottom_line:=false; | |
> loop@+begin cur_input:=input_stack[base_ptr]; {enter into the context} | |
> if (state<>token_list) then | |
> if (name>17) or (base_ptr=0) then bottom_line:=true; | |
> if (base_ptr=input_ptr)or bottom_line or(nn<error_context_lines) then | |
> @<Display the current context@> | |
> else if nn=error_context_lines then | |
> begin print_nl("..."); incr(nn); {omitted if |error_context_lines<0|} | |
> end; | |
> if bottom_line then goto done; | |
> decr(base_ptr); | |
> end; | |
> done: cur_input:=input_stack[input_ptr]; {restore original state} | |
5682,5695c6686,6702 | |
< if (state≠token_list) or (token_type≠inserted) or (loc≠null) then | |
< {we omit inserted token lists that have already been read} | |
< begin tally←0; {get ready to count characters} | |
< old_setting←selector; | |
< if state≠token_list then | |
< begin @<Print location of current line@>; | |
< @<Pseudoprint the line@>; | |
< end | |
< else begin @<Print type of token list@>; | |
< @<Pseudoprint the token list@>; | |
< end; | |
< selector←old_setting; {stop pseudoprinting} | |
< @<Print two lines using the tricky pseudoprinted information@>; | |
< end | |
--- | |
> begin if (base_ptr=input_ptr) or (state<>token_list) or | |
> (token_type<>backed_up) or (loc<>null) then | |
> {we omit backed-up token lists that have already been read} | |
> begin tally:=0; {get ready to count characters} | |
> old_setting:=selector; | |
> if state<>token_list then | |
> begin @<Print location of current line@>; | |
> @<Pseudoprint the line@>; | |
> end | |
> else begin @<Print type of token list@>; | |
> @<Pseudoprint the token list@>; | |
> end; | |
> selector:=old_setting; {stop pseudoprinting} | |
> @<Print two lines using the tricky pseudoprinted information@>; | |
> incr(nn); | |
> end; | |
> end | |
5703,5706c6710,6719 | |
< if terminal_input then | |
< if base_ptr=0 then print_nl("<*>") else print_nl("<**>") | |
< else begin print_nl("l."); print_int(line); | |
< end; | |
--- | |
> if name<=17 then | |
> if terminal_input then | |
> if base_ptr=0 then print_nl("<*>") else print_nl("<insert> ") | |
> else begin print_nl("<read "); | |
> if name=17 then print_char("*")@+else print_int(name-1); | |
> @.*\relax@> | |
> print_char(">"); | |
> end | |
> else begin print_nl("l."); print_int(line); | |
> end; | |
5713c6726,6728 | |
< inserted: print_nl("<to be read again> "); | |
--- | |
> backed_up: if loc=null then print_nl("<recently read> ") | |
> else print_nl("<to be read again> "); | |
> inserted: print_nl("<inserted text> "); | |
5715c6730 | |
< end; | |
--- | |
> end; | |
5717a6733,6738 | |
> every_math_text: print_nl("<everymath> "); | |
> every_display_text: print_nl("<everydisplay> "); | |
> every_hbox_text: print_nl("<everyhbox> "); | |
> every_vbox_text: print_nl("<everyvbox> "); | |
> every_job_text: print_nl("<everyjob> "); | |
> every_cr_text: print_nl("<everycr> "); | |
5719c6740 | |
< send_text: print_nl("<send> "); | |
--- | |
> write_text: print_nl("<write> "); | |
5728c6749 | |
< that stores char\-acters into a buffer of length |error_line|, where character | |
--- | |
> that stores characters into a buffer of length |error_line|, where character | |
5731c6752 | |
< |tally←0| and |trick_count←1000000|; then when we reach the | |
--- | |
> |tally:=0| and |trick_count:=1000000|; then when we reach the | |
5733c6754 | |
< set |first_count←tally| and |trick_count←@tmax@>(error_line, | |
--- | |
> set |first_count:=tally| and |trick_count:=@tmax@>(error_line, | |
5742c6763 | |
< gathered for line@@2 is $m=\min(|tally|, |trick_count|)-k$. If |l+k≤h|, | |
--- | |
> gathered for line~2 is $m=\min(|tally|, |trick_count|)-k$. If |l+k<=h|, | |
5744,5745c6765,6766 | |
< descriptive information on line@@1, and set |n←l+k|; here |n| is the | |
< length of line@@1. If $l+k>h$, some cropping is necessary, so we set |n←h| | |
--- | |
> descriptive information on line~1, and set |n:=l+k|; here |n| is the | |
> length of line~1. If $l+k>h$, some cropping is necessary, so we set |n:=h| | |
5749c6770 | |
< second line consists of |n|@@spaces followed by |trick_buf[k..(k+m-1)]|, | |
--- | |
> second line consists of |n|~spaces followed by |trick_buf[k..(k+m-1)]|, | |
5766,5768c6787,6789 | |
< begin l←tally; tally←0; selector←pseudo; | |
< trick_count←1000000; | |
< end | |
--- | |
> begin l:=tally; tally:=0; selector:=pseudo; | |
> trick_count:=1000000; | |
> end | |
5770,5773c6791,6794 | |
< begin first_count←tally; | |
< trick_count←tally+1+error_line-half_error_line; | |
< if trick_count<error_line then trick_count←error_line; | |
< end | |
--- | |
> begin first_count:=tally; | |
> trick_count:=tally+1+error_line-half_error_line; | |
> if trick_count<error_line then trick_count:=error_line; | |
> end | |
5779,5788c6800,6809 | |
< {|set_trick_count| must be performed} | |
< if tally<trick_count then m←tally-first_count | |
< else m←trick_count-first_count; {context on line 2} | |
< if l+first_count≤half_error_line then | |
< begin p←0; n←l+first_count; | |
< end | |
< else begin print("..."); p←l+first_count-half_error_line+3; | |
< n←half_error_line; | |
< end; | |
< for q←p to first_count-1 do print_char(trick_buf[q mod error_line]); | |
--- | |
> {|set_trick_count| must be performed} | |
> if tally<trick_count then m:=tally-first_count | |
> else m:=trick_count-first_count; {context on line 2} | |
> if l+first_count<=half_error_line then | |
> begin p:=0; n:=l+first_count; | |
> end | |
> else begin print("..."); p:=l+first_count-half_error_line+3; | |
> n:=half_error_line; | |
> end; | |
> for q:=p to first_count-1 do print_char(trick_buf[q mod error_line]); | |
5790,5792c6811,6813 | |
< for q←1 to n do print_char(" "); {print |n| spaces to begin line@@2} | |
< if m+n≤error_line then p←first_count+m else p←first_count+(error_line-n-3); | |
< for q←first_count to p-1 do print_char(trick_buf[q mod error_line]); | |
--- | |
> for q:=1 to n do print_char(" "); {print |n| spaces to begin line~2} | |
> if m+n<=error_line then p:=first_count+m else p:=first_count+(error_line-n-3); | |
> for q:=first_count to p-1 do print_char(trick_buf[q mod error_line]); | |
5801,5806c6822,6827 | |
< if buffer[limit]=carriage_return then j←limit | |
< else j←limit+1; {determine the effective end of the line} | |
< if j>0 then for i←start to j-1 do | |
< begin if i=loc then set_trick_count; | |
< print(buffer[i]); | |
< end | |
--- | |
> if buffer[limit]=end_line_char then j:=limit | |
> else j:=limit+1; {determine the effective end of the line} | |
> if j>0 then for i:=start to j-1 do | |
> begin if i=loc then set_trick_count; | |
> print(buffer[i]); | |
> end | |
5814c6835 | |
< token beginning line@@2 is about to be shown: | |
--- | |
> token beginning line~2 is about to be shown: | |
5816a6838 | |
> | |
5823,5830c6845,6853 | |
< @p procedure push_input; {enter a new input level, save the old} | |
< begin if input_ptr>max_in_stack then | |
< begin max_in_stack←input_ptr; | |
< if input_ptr=stack_size then overflow("input stack size",stack_size); | |
< end; | |
< input_stack[input_ptr]←cur_input; {stack the record} | |
< incr(input_ptr); | |
< end; | |
--- | |
> @d push_input==@t@> {enter a new input level, save the old} | |
> begin if input_ptr>max_in_stack then | |
> begin max_in_stack:=input_ptr; | |
> if input_ptr=stack_size then overflow("input stack size",stack_size); | |
> @:TeX capacity exceeded input stack size}{\quad input stack size@> | |
> end; | |
> input_stack[input_ptr]:=cur_input; {stack the record} | |
> incr(input_ptr); | |
> end | |
5834,5836c6857,6859 | |
< @p procedure pop_input; {leave an input level, re-enter the old} | |
< begin decr(input_ptr); cur_input←input_stack[input_ptr]; | |
< end; | |
--- | |
> @d pop_input==@t@> {leave an input level, re-enter the old} | |
> begin decr(input_ptr); cur_input:=input_stack[input_ptr]; | |
> end | |
5841a6865 | |
> @d back_list(#)==begin_token_list(#,backed_up) {backs up a simple token list} | |
5845,5850c6869,6885 | |
< begin push_input; state←token_list; start←p; token_type←t; | |
< if t≥macro then {the token list starts with a reference count} | |
< begin add_token_ref(p); | |
< if t=macro then param_start←param_ptr@+else loc←link(p); | |
< end | |
< else loc←p; | |
--- | |
> begin push_input; state:=token_list; start:=p; token_type:=t; | |
> if t>=macro then {the token list starts with a reference count} | |
> begin add_token_ref(p); | |
> if t=macro then param_start:=param_ptr | |
> else begin loc:=link(p); | |
> if tracing_macros>1 then | |
> begin begin_diagnostic; print_nl(""); | |
> case t of | |
> mark_text:print_esc("mark"); | |
> write_text:print_esc("write"); | |
> othercases print_cmd_chr(assign_toks,t-output_text+output_routine_loc) | |
> endcases;@/ | |
> print("->"); token_show(p); end_diagnostic(false); | |
> end; | |
> end; | |
> end | |
> else loc:=p; | |
5854c6889,6891 | |
< should be done as we leave that level of input. | |
--- | |
> should be done as we leave that level of input. The |token_type| tends | |
> to be equal to either |backed_up| or |inserted| about 2/3 of the time. | |
> @^inner loop@> | |
5857,5867c6894,6907 | |
< begin if token_type≥inserted then {token list to be deleted} | |
< begin if token_type=inserted then flush_list(start) | |
< else begin delete_token_ref(start); {update reference count} | |
< if token_type=macro then {parameters must be flushed} | |
< while param_ptr>param_start do | |
< begin decr(param_ptr); | |
< flush_list(param_stack[param_ptr]); | |
< end; | |
< end; | |
< end | |
< else if token_type=u_template then align_state←0; | |
--- | |
> begin if token_type>=backed_up then {token list to be deleted} | |
> begin if token_type<=inserted then flush_list(start) | |
> else begin delete_token_ref(start); {update reference count} | |
> if token_type=macro then {parameters must be flushed} | |
> while param_ptr>param_start do | |
> begin decr(param_ptr); | |
> flush_list(param_stack[param_ptr]); | |
> end; | |
> end; | |
> end | |
> else if token_type=u_template then | |
> if align_state>500000 then align_state:=0 | |
> else fatal_error("(interwoven alignment preambles are not allowed)"); | |
> @.interwoven alignment preambles...@> | |
5872c6912 | |
< @ Sometimes \TeX\ has read too far and it wants to ``unscan'' what it has | |
--- | |
> @ Sometimes \TeX\ has read too far and wants to ``unscan'' what it has | |
5876c6916,6918 | |
< replaced. | |
--- | |
> replaced. Some applications of \TeX\ use this procedure a lot, | |
> so it has been slightly optimized for speed. | |
> @^inner loop@> | |
5880c6922,6924 | |
< begin p←get_avail; info(p)←cur_tok; | |
--- | |
> begin while (state=token_list)and(loc=null)and(token_type<>v_template) do | |
> end_token_list; {conserve stack space} | |
> p:=get_avail; info(p):=cur_tok; | |
5882,5884c6926,6929 | |
< if cur_tok<left_brace_limit then decr(align_state) | |
< else incr(align_state); | |
< ins_list(p); | |
--- | |
> if cur_tok<left_brace_limit then decr(align_state) | |
> else incr(align_state); | |
> push_input; state:=token_list; start:=p; token_type:=backed_up; | |
> loc:=p; {that was |back_list(p)|, without procedure overhead} | |
5886a6932,6935 | |
> @ @<Insert token |p| into \TeX's input@>= | |
> begin t:=cur_tok; cur_tok:=p; back_input; cur_tok:=t; | |
> end | |
> | |
5889c6938,6939 | |
< requires that |cur_tok| has been set. | |
--- | |
> requires that |cur_tok| has been set. We disable interrupts during the | |
> call of |back_input| so that the help message won't be lost. | |
5892c6942,6947 | |
< begin back_input; error; | |
--- | |
> begin OK_to_interrupt:=false; back_input; OK_to_interrupt:=true; error; | |
> end; | |
> @# | |
> procedure ins_error; {back up one inserted token and call |error|} | |
> begin OK_to_interrupt:=false; back_input; token_type:=inserted; | |
> OK_to_interrupt:=true; error; | |
5902a6958 | |
> @:TeX capacity exceeded text input levels}{\quad text input levels@> | |
5904,5906c6960,6963 | |
< incr(in_open); push_input; index←in_open; | |
< line_stack[index]←line; start←first; state←mid_line; | |
< name←0; {|terminal_input| is now |true|} | |
--- | |
> @:TeX capacity exceeded buffer size}{\quad buffer size@> | |
> incr(in_open); push_input; index:=in_open; | |
> line_stack[index]:=line; start:=first; state:=mid_line; | |
> name:=0; {|terminal_input| is now |true|} | |
5913,5914c6970,6971 | |
< begin first←start; line←line_stack[index]; | |
< if not terminal_input then a_close(cur_file); {forget it} | |
--- | |
> begin first:=start; line:=line_stack[index]; | |
> if name>17 then a_close(cur_file); {forget it} | |
5923,5924c6980,6981 | |
< begin while (state≠token_list)∧ terminal_input ∧@| | |
< (input_ptr>0)∧(loc>limit) do end_file_reading; | |
--- | |
> begin while (state<>token_list)and terminal_input and@| | |
> (input_ptr>0)and(loc>limit) do end_file_reading; | |
5932,5937c6989,6996 | |
< begin input_ptr←0; max_in_stack←0; | |
< in_open←0; max_buf_stack←0; | |
< param_ptr←0; max_param_stack←0; | |
< scanner_status←normal; first←0; | |
< state←new_line; start←0; index←0; line←0; name←0; | |
< align_state←1000000;@/ | |
--- | |
> begin input_ptr:=0; max_in_stack:=0; | |
> in_open:=0; open_parens:=0; max_buf_stack:=0; | |
> param_ptr:=0; max_param_stack:=0; | |
> first:=buf_size; repeat buffer[first]:=0; decr(first); until first=0; | |
> scanner_status:=normal; warning_index:=null; first:=1; | |
> state:=new_line; start:=1; index:=0; line:=0; name:=0; | |
> force_eof:=false; | |
> align_state:=1000000;@/ | |
5939,5940c6998 | |
< {|init_terminal| sets |loc| and |last|} | |
< limit←last; first←last+1; | |
--- | |
> limit:=last; first:=last+1; {|init_terminal| has set |loc| and |last|} | |
5941a7000 | |
> | |
5944,5947c7003,7007 | |
< we shall develop in the next few paragraphs. Perhaps we shouldn't actually | |
< call it the ``heart,'' however, because it really acts as \TeX's eyes and | |
< mouth, reading the source files and gobbling them up. And it also helps | |
< \TeX\ to regurgitate stored token lists that are to be processed again. | |
--- | |
> we shall develop in the next few sections of the program. Perhaps we | |
> shouldn't actually call it the ``heart,'' however, because it really acts | |
> as \TeX's eyes and mouth, reading the source files and gobbling them up. | |
> And it also helps \TeX\ to regurgitate stored token lists that are to be | |
> processed again. | |
5953c7013 | |
< sequence is stored in |cs_ptr|; otherwise |cs_ptr| is set to zero. | |
--- | |
> sequence is stored in |cur_cs|; otherwise |cur_cs| is set to zero. | |
5956c7016 | |
< because of all the cases that need to be handled, as explained above. | |
--- | |
> because of all the cases that need to be handled. | |
5958a7019,7023 | |
> When |get_next| is asked to get the next token of a \.{\\read} line, | |
> it sets |cur_cmd=cur_chr=cur_cs=0| in the case that no more tokens | |
> appear on that line. (There might not be any tokens at all, if the | |
> |end_line_char| has |ignore| as its catcode.) | |
> | |
5961c7026 | |
< to the appearance of \.{\\par}; we must set |cs_ptr←par_loc| | |
--- | |
> to the appearance of \.{\\par}; we must set |cur_cs:=par_loc| | |
5964c7029 | |
< @<Globals...@>= | |
--- | |
> @<Glob...@>= | |
5966c7031 | |
< @!par_token:halfword; {token representing '\.{\\par}'} | |
--- | |
> @!par_token:halfword; {token representing `\.{\\par}'} | |
5969c7034 | |
< primitive("par",par_end,0); par_loc←cur_val; par_token←cs_token_flag+par_loc; | |
--- | |
> primitive("par",par_end,256); {cf.\ |scan_file_name|} | |
5970a7036 | |
> par_loc:=cur_val; par_token:=cs_token_flag+par_loc; | |
5978c7044 | |
< by |cs_ptr|, which is zero at the end of a file. | |
--- | |
> by |cur_cs|, which is zero at the end of a file. | |
5982,5991c7048,7079 | |
< begin if scanner_status≠normal then | |
< if scanner_status>skipping then @<Tell the user what has run away@> | |
< else if cs_ptr=0 then | |
< begin print_nl("! File ended in skipped conditional text"); | |
< @.File ended in skipped...text@> | |
< help3("This kind of error happens when you say something like")@/ | |
< ("`\if...{...' or `\else{...' and forget the matching `}'.")@/ | |
< ("You probably should type `I}' now."); error; | |
< end; | |
< end; | |
--- | |
> @!q:pointer; {auxiliary pointer} | |
> begin if scanner_status<>normal then | |
> begin deletions_allowed:=false; | |
> @<Back up an outer control sequence so that it can be reread@>; | |
> if scanner_status>skipping then | |
> @<Tell the user what has run away and try to recover@> | |
> else begin print_err("Incomplete "); print_cmd_chr(if_test,cur_if); | |
> @.Incomplete \\if...@> | |
> print("; all text was ignored after line "); print_int(skip_line); | |
> help3("A forbidden control sequence occurred in skipped text.")@/ | |
> ("This kind of error happens when you say `\if...' and forget")@/ | |
> ("the matching `\fi'. I've inserted a `\fi'; this might work."); | |
> if cur_cs<>0 then cur_cs:=0 | |
> else help_line[2]:=@| | |
> "The file ended while I was skipping conditional text."; | |
> cur_tok:=cs_token_flag+frozen_fi; ins_error; | |
> end; | |
> deletions_allowed:=true; | |
> end; | |
> end; | |
> | |
> @ An outer control sequence that occurs in a \.{\\read} will not be reread, | |
> since the error recovery for \.{\\read} is not very powerful. | |
> | |
> @<Back up an outer control sequence so that it can be reread@>= | |
> if cur_cs<>0 then | |
> begin if (state=token_list)or(name<1)or(name>17) then | |
> begin p:=get_avail; info(p):=cs_token_flag+cur_cs; | |
> back_list(p); {prepare to read the control sequence again} | |
> end; | |
> cur_cmd:=spacer; cur_chr:=" "; {replace it by a space} | |
> end | |
5993c7081 | |
< @ @<Tell the user what has run away@>= | |
--- | |
> @ @<Tell the user what has run away...@>= | |
5995c7083 | |
< if cs_ptr=0 then print_nl("! File ended") | |
--- | |
> if cur_cs=0 then print_err("File ended") | |
5997,6000c7085 | |
< else begin p←get_avail; info(p)←cs_token_flag+cs_ptr; | |
< ins_list(p); {prepare to read the control sequence again} | |
< cs_ptr←0; cur_cmd←spacer; cur_chr←" "; {replace it by a space} | |
< print_nl("! Forbidden control sequence found"); | |
--- | |
> else begin cur_cs:=0; print_err("Forbidden control sequence found"); | |
6002c7087 | |
< end; | |
--- | |
> end; | |
6004,6008c7089,7090 | |
< case scanner_status of | |
< defining:print("definition"); | |
< matching:print("use"); | |
< aligning:print("preamble"); | |
< end; {there are no other cases} | |
--- | |
> @<Print either `\.{definition}' or `\.{use}' or `\.{preamble}' or `\.{text}', | |
> and insert tokens that should lead to recovery@>; | |
6012,6014c7094,7096 | |
< ("Either type `I}' to try recovering,")@/ | |
< ("or type 'X' and fix your file.");@/ | |
< deletions_allowed←false; error; deletions_allowed←true; | |
--- | |
> ("I'll try to recover; but if the error is serious,")@/ | |
> ("you'd better type `E' or `X' now and fix your file.");@/ | |
> error; | |
6017c7099,7122 | |
< @ We need to mention two procedures here that may be called by |get_next|. | |
--- | |
> @ The recovery procedure can't be fully understood without knowing more | |
> about the \TeX\ routines that should be aborted, but we can sketch the | |
> ideas here: For a runaway definition we will insert a right brace; for a | |
> runaway preamble, we will insert a special \.{\\cr} token and a right | |
> brace; and for a runaway argument, we will set |long_state| to | |
> |outer_call| and insert \.{\\par}. | |
> | |
> @<Print either `\.{definition}' or ...@>= | |
> p:=get_avail; | |
> case scanner_status of | |
> defining:begin print("definition"); info(p):=right_brace_token+"}"; | |
> end; | |
> matching:begin print("use"); info(p):=par_token; long_state:=outer_call; | |
> end; | |
> aligning:begin print("preamble"); info(p):=right_brace_token+"}"; q:=p; | |
> p:=get_avail; link(p):=q; info(p):=cs_token_flag+frozen_cr; | |
> align_state:=-1000000; | |
> end; | |
> absorbing:begin print("text"); info(p):=right_brace_token+"}"; | |
> end; | |
> end; {there are no other cases} | |
> ins_list(p) | |
> | |
> @ We need to mention a procedure here that may be called by |get_next|. | |
6019,6020c7124 | |
< @p procedure@?open_err_file; forward;@t\2@> | |
< procedure@?firm_up_the_line; forward; | |
--- | |
> @p procedure@?firm_up_the_line; forward; | |
6022,6023c7126,7128 | |
< @ Now we're ready to take the plunge into |get_next| itself. | |
< @^mastication@> | |
--- | |
> @ Now we're ready to take the plunge into |get_next| itself. Parts of | |
> this routine are executed more often than any other instructions of \TeX. | |
> @^mastication@>@^inner loop@> | |
6028c7133 | |
< @p procedure get_next; {sets |cur_cmd|, |cur_chr|, |cs_ptr| to next token} | |
--- | |
> @p procedure get_next; {sets |cur_cmd|, |cur_chr|, |cur_cs| to next token} | |
6030,6033c7135,7139 | |
< switch, {go here to eat the next character from a file} | |
< reswitch, {go here to digest it again} | |
< start_cs, {go here to start looking for a control sequence} | |
< found; {go here when a control sequence has been found} | |
--- | |
> switch, {go here to eat the next character from a file} | |
> reswitch, {go here to digest it again} | |
> start_cs, {go here to start looking for a control sequence} | |
> found, {go here when a control sequence has been found} | |
> exit; {go here when the next input token has been got} | |
6036,6037c7142,7146 | |
< begin restart: cs_ptr←0; | |
< if state≠token_list then | |
--- | |
> @!cat:0..max_char_code; {|cat_code(cur_chr)|, usually} | |
> @!c,@!cc:ASCII_code; {constituents of a possible expanded code} | |
> @!d:2..3; {number of excess characters in an expanded code} | |
> begin restart: cur_cs:=0; | |
> if state<>token_list then | |
6040,6043c7149,7151 | |
< if a parameter needs to be expanded@>; | |
< if @<End of alignment entry sensed@> then | |
< @<Insert the \(v)\<v↓j> template and |goto restart|@>; | |
< end; | |
--- | |
> if a parameter needs to be expanded@>; | |
> @<If an alignment entry has just ended, take appropriate action@>; | |
> exit:end; | |
6048c7156,7157 | |
< returned to the value it had after the \<u↓j> template for that entry. | |
--- | |
> returned to the value it had after the \<u_j> template for that entry. | |
> @^inner loop@> | |
6050,6051c7159,7161 | |
< @<End of alignment entry sensed@>= | |
< (align_state=0)∧(cur_cmd≤car_ret)∧(cur_cmd≥tab_mark) | |
--- | |
> @<If an alignment entry has just ended, take appropriate action@>= | |
> if cur_cmd<=car_ret then if cur_cmd>=tab_mark then if align_state=0 then | |
> @<Insert the \(v)\<v_j> template and |goto restart|@> | |
6054,6066c7164,7179 | |
< begin switch: if loc≤limit then {current line not yet finished} | |
< begin cur_chr←buffer[loc]; incr(loc); | |
< reswitch: cur_cmd←ch_code(cur_chr); | |
< @<Change state if necessary, and |goto switch| if the | |
< current character should be ignored, | |
< or |goto reswitch| if the current character | |
< changes to another@>; | |
< end | |
< else begin @<Move to next line of file, | |
< or |goto restart| if there is no next line@>; | |
< check_interrupt; | |
< goto switch; | |
< end; | |
--- | |
> @^inner loop@> | |
> begin switch: if loc<=limit then {current line not yet finished} | |
> begin cur_chr:=buffer[loc]; incr(loc); | |
> reswitch: cur_cmd:=cat_code(cur_chr); | |
> @<Change state if necessary, and |goto switch| if the | |
> current character should be ignored, | |
> or |goto reswitch| if the current character | |
> changes to another@>; | |
> end | |
> else begin state:=new_line;@/ | |
> @<Move to next line of file, | |
> or |goto restart| if there is no next line, | |
> or |return| if a \.{\\read} line has finished@>; | |
> check_interrupt; | |
> goto switch; | |
> end; | |
6072c7185 | |
< |(max_char_code+1)| apart from each other, so we can add a character's | |
--- | |
> apart from each other by |max_char_code+1|, so we can add a character's | |
6081c7194 | |
< and set |state←skip_blanks|@>; | |
--- | |
> and set |state:=skip_blanks| or |mid_line|@>; | |
6083,6085c7196,7199 | |
< and set |state←mid_line|@>; | |
< any_state_plus(sup_mark): @<If this |sup_mark| starts a control character | |
< like@@\.{\^\^A}, then |goto reswitch|, otherwise set |state←mid_line|@>; | |
--- | |
> and set |state:=mid_line|@>; | |
> any_state_plus(sup_mark): @<If this |sup_mark| starts an expanded character | |
> like~\.{\^\^A} or~\.{\^\^df}, then |goto reswitch|, | |
> otherwise set |state:=mid_line|@>; | |
6087c7201 | |
< |goto switch|@>; | |
--- | |
> |goto restart|@>; | |
6095,6096c7209,7214 | |
< @ @<Decry the invalid...@>= | |
< begin print_nl("! Text line contains an invalid character"); | |
--- | |
> @ We go to |restart| instead of to |switch|, because |state| might equal | |
> |token_list| after the error has been dealt with | |
> (cf.\ |clear_for_error_prompt|). | |
> | |
> @<Decry the invalid...@>= | |
> begin print_err("Text line contains an invalid character"); | |
6099,6100c7217,7219 | |
< ("Continue, and I'll forget that it ever happened."); | |
< goto switch; | |
--- | |
> ("Continue, and I'll forget that it ever happened.");@/ | |
> deletions_allowed:=false; error; deletions_allowed:=true; | |
> goto restart; | |
6103,6104c7222,7223 | |
< @ @d add_delims_to(#)==#+math_delim,#+tab_mark,#+mac_param, | |
< #+sub_mark,#+letter,#+other_char | |
--- | |
> @ @d add_delims_to(#)==#+math_shift,#+tab_mark,#+mac_param, | |
> #+sub_mark,#+letter,#+other_char | |
6108,6110c7227,7229 | |
< mid_line+car_ret:@<Enter |new_line| state, finish line, emit a space@>; | |
< skip_blanks+car_ret,any_state_plus(end_line): | |
< @<Enter |new_line| state, finish line, |goto switch|@>; | |
--- | |
> mid_line+car_ret:@<Finish line, emit a space@>; | |
> skip_blanks+car_ret,any_state_plus(comment): | |
> @<Finish line, |goto switch|@>; | |
6114,6115c7233,7234 | |
< state←mid_line; incr(align_state); | |
< end; | |
--- | |
> state:=mid_line; incr(align_state); | |
> end; | |
6118,6120c7237,7239 | |
< state←mid_line; decr(align_state); | |
< end; | |
< add_delims_to(skip_blanks),add_delims_to(new_line): state←mid_line; | |
--- | |
> state:=mid_line; decr(align_state); | |
> end; | |
> add_delims_to(skip_blanks),add_delims_to(new_line): state:=mid_line; | |
6123c7242 | |
< changed to $\.{"\ "}=@'40$. This means that the ascii codes for tab and space, | |
--- | |
> changed to $\.{"\ "}=@'40$. This means that the ASCII codes for tab and space, | |
6128,6129c7247,7248 | |
< @<Enter |new_line| state, finish line, emit a space@>= | |
< begin state←new_line; loc←limit+1; cur_cmd←spacer; cur_chr←" "; | |
--- | |
> @<Finish line, emit a space@>= | |
> begin loc:=limit+1; cur_cmd:=spacer; cur_chr:=" "; | |
6135c7254 | |
< begin state←skip_blanks; cur_chr←" "; | |
--- | |
> begin state:=skip_blanks; cur_chr:=" "; | |
6138,6139c7257,7258 | |
< @ @<Enter |new_line| state, finish line, |goto switch|@>= | |
< begin state←new_line; loc←limit+1; goto switch; | |
--- | |
> @ @<Finish line, |goto switch|@>= | |
> begin loc:=limit+1; goto switch; | |
6143,6145c7262,7264 | |
< begin loc←limit+1; cs_ptr←par_loc; cur_cmd←eq_type(cs_ptr); | |
< cur_chr←equiv(cs_ptr); | |
< if cur_cmd≥outer_call then check_outer_validity; | |
--- | |
> begin loc:=limit+1; cur_cs:=par_loc; cur_cmd:=eq_type(cur_cs); | |
> cur_chr:=equiv(cur_cs); | |
> if cur_cmd>=outer_call then check_outer_validity; | |
6148,6155c7267,7288 | |
< @ @<If this |sup_mark| starts a control character...@>= | |
< begin if (cur_chr=buffer[loc])∧(loc<limit) then | |
< if (buffer[loc+1]≤"_")∧(buffer[loc+1]≥"?") then | |
< begin if buffer[loc+1]="?" then cur_chr←@'177 | |
< else cur_chr←buffer[loc+1]-"@@"; | |
< loc←loc+2; goto reswitch; | |
< end; | |
< state←mid_line; | |
--- | |
> @ Notice that a code like \.{\^\^8} becomes \.x if not followed by a hex digit. | |
> | |
> @d is_hex(#)==(((#>="0")and(#<="9"))or((#>="a")and(#<="f"))) | |
> @d hex_to_cur_chr== | |
> if c<="9" then cur_chr:=c-"0" @+else cur_chr:=c-"a"+10; | |
> if cc<="9" then cur_chr:=16*cur_chr+cc-"0" | |
> else cur_chr:=16*cur_chr+cc-"a"+10 | |
> | |
> @<If this |sup_mark| starts an expanded character...@>= | |
> begin if cur_chr=buffer[loc] then if loc<limit then | |
> begin c:=buffer[loc+1]; @+if c<@'200 then {yes we have an expanded char} | |
> begin loc:=loc+2; | |
> if is_hex(c) then if loc<=limit then | |
> begin cc:=buffer[loc]; @+if is_hex(cc) then | |
> begin incr(loc); hex_to_cur_chr; goto reswitch; | |
> end; | |
> end; | |
> if c<@'100 then cur_chr:=c+@'100 @+else cur_chr:=c-@'100; | |
> goto reswitch; | |
> end; | |
> end; | |
> state:=mid_line; | |
6157c7290 | |
< | |
--- | |
> | |
6159,6161c7292,7294 | |
< begin cs_ptr←cur_chr+active_base; | |
< cur_cmd←eq_type(cs_ptr); cur_chr←equiv(cs_ptr); state←mid_line; | |
< if cur_cmd≥outer_call then check_outer_validity; | |
--- | |
> begin cur_cs:=cur_chr+active_base; | |
> cur_cmd:=eq_type(cur_cs); cur_chr:=equiv(cur_cs); state:=mid_line; | |
> if cur_cmd>=outer_call then check_outer_validity; | |
6171c7304 | |
< user tried something like `\.{\\chcode\'15=0}'. The algorithm might | |
--- | |
> user tried something like `\.{\\catcode\'15=0}'. The algorithm might | |
6174c7307,7308 | |
< If expanded control characters like `\.{\^\^A}' appear in or just following | |
--- | |
> If expanded characters like `\.{\^\^A}' or `\.{\^\^df}' | |
> appear in or just following | |
6179,6192c7313,7329 | |
< begin if loc>limit then cs_ptr←single_base+null_code | |
< else begin start_cs: k←loc; cur_chr←buffer[k]; incr(k); | |
< if (ch_code(cur_chr)=letter)∧(k≤limit) then | |
< @<Scan ahead in the buffer until finding a nonletter; | |
< if an expanded control code is encountered, reduce it | |
< and |goto start_cs|; otherwise if a multiletter control | |
< sequence is found, adjust |cs_ptr| and |loc|, and | |
< |goto found|@> | |
< else @<If an expanded control code is present, reduce it | |
< and |goto start_cs|@>; | |
< cs_ptr←single_base+buffer[loc]; incr(loc); | |
< end; | |
< found: cur_cmd←eq_type(cs_ptr); cur_chr←equiv(cs_ptr); state←skip_blanks; | |
< if cur_cmd≥outer_call then check_outer_validity; | |
--- | |
> begin if loc>limit then cur_cs:=null_cs {|state| is irrelevant in this case} | |
> else begin start_cs: k:=loc; cur_chr:=buffer[k]; cat:=cat_code(cur_chr); | |
> incr(k); | |
> if cat=letter then state:=skip_blanks | |
> else if cat=spacer then state:=skip_blanks | |
> else state:=mid_line; | |
> if (cat=letter)and(k<=limit) then | |
> @<Scan ahead in the buffer until finding a nonletter; | |
> if an expanded code is encountered, reduce it | |
> and |goto start_cs|; otherwise if a multiletter control | |
> sequence is found, adjust |cur_cs| and |loc|, and | |
> |goto found|@> | |
> else @<If an expanded code is present, reduce it and |goto start_cs|@>; | |
> cur_cs:=single_base+buffer[loc]; incr(loc); | |
> end; | |
> found: cur_cmd:=eq_type(cur_cs); cur_chr:=equiv(cur_cs); | |
> if cur_cmd>=outer_call then check_outer_validity; | |
6196,6198c7333,7337 | |
< |cur_chr=buffer[k-1]| and |k≤limit+1|. If an expanded control code like | |
< \.{\^\^A} appears in |buffer[(k-1)..(k+1)]|, we will store the corresponding | |
< code in |buffer[k-1]| and shift the rest of the buffer left two places. | |
--- | |
> |cur_chr=buffer[k-1]| and |k<=limit+1| and |cat=cat_code(cur_chr)|. If an | |
> expanded code like \.{\^\^A} or \.{\^\^df} appears in |buffer[(k-1)..(k+1)]| | |
> or |buffer[(k-1)..(k+2)]|, we | |
> will store the corresponding code in |buffer[k-1]| and shift the rest of | |
> the buffer left two or three places. | |
6201,6213c7340,7357 | |
< begin if (buffer[k]=cur_chr)∧(ch_code(cur_chr)=sup_mark)∧@| | |
< (k<limit) then | |
< begin cur_chr←buffer[k+1]; | |
< if (cur_chr≤"_")∧(cur_chr≥"?") then | |
< begin if cur_chr>"?" then buffer[k-1]←cur_chr-"@@" | |
< else buffer[k-1]←@'177; | |
< limit←limit-2; first←first-2; | |
< while k≤limit do | |
< begin buffer[k]←buffer[k+2]; incr(k); | |
< end; | |
< goto start_cs; | |
< end; | |
< end; | |
--- | |
> begin if buffer[k]=cur_chr then @+if cat=sup_mark then @+if k<limit then | |
> begin c:=buffer[k+1]; @+if c<@'200 then {yes, one is indeed present} | |
> begin d:=2; | |
> if is_hex(c) then @+if k+2<=limit then | |
> begin cc:=buffer[k+2]; @+if is_hex(cc) then incr(d); | |
> end; | |
> if d>2 then | |
> begin hex_to_cur_chr; buffer[k-1]:=cur_chr; | |
> end | |
> else if c<@'100 then buffer[k-1]:=c+@'100 | |
> else buffer[k-1]:=c-@'100; | |
> limit:=limit-d; first:=first-d; | |
> while k<=limit do | |
> begin buffer[k]:=buffer[k+d]; incr(k); | |
> end; | |
> goto start_cs; | |
> end; | |
> end; | |
6217,6218c7361,7362 | |
< begin repeat cur_chr←buffer[k]; incr(k); | |
< until (ch_code(cur_chr)≠letter)∨(k>limit); | |
--- | |
> begin repeat cur_chr:=buffer[k]; cat:=cat_code(cur_chr); incr(k); | |
> until (cat<>letter)or(k>limit); | |
6220,6224c7364,7368 | |
< if ch_code(buffer[k-1])≠letter then decr(k); | |
< {now |k| points to first nonletter} | |
< if k>loc+1 then {multi-letter control sequence has been scanned} | |
< begin cs_ptr←id_lookup(loc,k-loc); loc←k; goto found; | |
< end; | |
--- | |
> if cat<>letter then decr(k); | |
> {now |k| points to first nonletter} | |
> if k>loc+1 then {multiletter control sequence has been scanned} | |
> begin cur_cs:=id_lookup(loc,k-loc); loc:=k; goto found; | |
> end; | |
6230,6249c7374,7411 | |
< if a parameter needs to be expanded@>= | |
< if loc≠null then {list not exhausted} | |
< begin t←info(loc); loc←link(loc); {move to next} | |
< if t≥cs_token_flag then {a control sequence token} | |
< begin cs_ptr←t-cs_token_flag; | |
< cur_cmd←eq_type(cs_ptr); cur_chr←equiv(cs_ptr); | |
< if cur_cmd≥outer_call then check_outer_validity; | |
< end | |
< else begin cur_cmd←t div @'400; cur_chr←t mod @'400; | |
< case cur_cmd of | |
< left_brace: incr(align_state); | |
< right_brace: decr(align_state); | |
< out_param: @<Insert macro parameter and |goto restart|@>; | |
< othercases do_nothing | |
< endcases; | |
< end; | |
< end | |
< else begin {we are done with this token list} | |
< end_token_list; goto restart; {resume previous level} | |
< end | |
--- | |
> if a parameter needs to be expanded@>= | |
> if loc<>null then {list not exhausted} | |
> @^inner loop@> | |
> begin t:=info(loc); loc:=link(loc); {move to next} | |
> if t>=cs_token_flag then {a control sequence token} | |
> begin cur_cs:=t-cs_token_flag; | |
> cur_cmd:=eq_type(cur_cs); cur_chr:=equiv(cur_cs); | |
> if cur_cmd>=outer_call then | |
> if cur_cmd=dont_expand then | |
> @<Get the next token, suppressing expansion@> | |
> else check_outer_validity; | |
> end | |
> else begin cur_cmd:=t div @'400; cur_chr:=t mod @'400; | |
> case cur_cmd of | |
> left_brace: incr(align_state); | |
> right_brace: decr(align_state); | |
> out_param: @<Insert macro parameter and |goto restart|@>; | |
> othercases do_nothing | |
> endcases; | |
> end; | |
> end | |
> else begin {we are done with this token list} | |
> end_token_list; goto restart; {resume previous level} | |
> end | |
> | |
> @ The present point in the program is reached only when the |expand| | |
> routine has inserted a special marker into the input. In this special | |
> case, |info(loc)| is known to be a control sequence token, and |link(loc)=null|. | |
> | |
> @d no_expand_flag=257 {this characterizes a special variant of |relax|} | |
> | |
> @<Get the next token, suppressing expansion@>= | |
> begin cur_cs:=info(loc)-cs_token_flag; loc:=null;@/ | |
> cur_cmd:=eq_type(cur_cs); cur_chr:=equiv(cur_cs); | |
> if cur_cmd>max_command then | |
> begin cur_cmd:=relax; cur_chr:=no_expand_flag; | |
> end; | |
> end | |
6259,6274c7421,7447 | |
< @<Move to next line of file, or |goto restart| if there is no next line@>= | |
< if not terminal_input then @<Read next line of file into |buffer|, or | |
< |goto restart| if the file has ended@> | |
< else begin if input_ptr>0 then {text was inserted during error recovery} | |
< begin end_file_reading; goto restart; {resume previous level} | |
< end; | |
< if selector<err_only then open_err_file; | |
< if interaction>nonstop_mode then | |
< begin if limit=start then {previous line was empty} | |
< print_nl("(Type a command or say `\end')"); | |
< print_ln; first←start; | |
< prompt_input("*"); {input on-line into |buffer|} | |
< limit←last; buffer[limit]←carriage_return; first←last+1; | |
< loc←start; | |
< end | |
< else fatal_error("*** (job aborted, no legal \end found)"); | |
--- | |
> @d end_line_char_inactive == (end_line_char<0)or(end_line_char>255) | |
> | |
> @<Move to next line of file, or |goto restart|...@>= | |
> if name>17 then @<Read next line of file into |buffer|, or | |
> |goto restart| if the file has ended@> | |
> else begin if not terminal_input then {\.{\\read} line has ended} | |
> begin cur_cmd:=0; cur_chr:=0; return; | |
> end; | |
> if input_ptr>0 then {text was inserted during error recovery} | |
> begin end_file_reading; goto restart; {resume previous level} | |
> end; | |
> if selector<log_only then open_log_file; | |
> if interaction>nonstop_mode then | |
> begin if end_line_char_inactive then incr(limit); | |
> if limit=start then {previous line was empty} | |
> print_nl("(Please type a command or say `\end')"); | |
> @.Please type...@> | |
> print_ln; first:=start; | |
> prompt_input("*"); {input on-line into |buffer|} | |
> @.*\relax@> | |
> limit:=last; | |
> if end_line_char_inactive then decr(limit) | |
> else buffer[limit]:=end_line_char; | |
> first:=limit+1; | |
> loc:=start; | |
> end | |
> else fatal_error("*** (job aborted, no legal \end found)"); | |
6276,6278c7449,7457 | |
< {nonstop mode, which is intended for overnight batch processing, | |
< never waits for on-line input} | |
< end | |
--- | |
> {nonstop mode, which is intended for overnight batch processing, | |
> never waits for on-line input} | |
> end | |
> | |
> @ The global variable |force_eof| is normally |false|; it is set |true| | |
> by an \.{\\endinput} command. | |
> | |
> @<Glob...@>= | |
> @!force_eof:boolean; {should the next \.{\\input} be aborted early?} | |
6281,6290c7460,7476 | |
< |goto restart| if the file has ended@>= | |
< begin incr(line); first←start; | |
< if input_ln(cur_file) then {not end of file} | |
< firm_up_the_line {this sets |limit|} | |
< else if limit≠start then limit←start {insert empty line at end of file} | |
< else begin check_outer_validity; | |
< print_char(")"); update_terminal; {show user that file has been read} | |
< end_file_reading; goto restart; {resume previous level} | |
< end; | |
< buffer[limit]←carriage_return; first←limit+1; loc←start; {ready to read} | |
--- | |
> |goto restart| if the file has ended@>= | |
> begin incr(line); first:=start; | |
> if not force_eof then | |
> begin if input_ln(cur_file,true) then {not end of file} | |
> firm_up_the_line {this sets |limit|} | |
> else force_eof:=true; | |
> end; | |
> if force_eof then | |
> begin print_char(")"); decr(open_parens); | |
> update_terminal; {show user that file has been read} | |
> force_eof:=false; | |
> end_file_reading; {resume previous level} | |
> check_outer_validity; goto restart; | |
> end; | |
> if end_line_char_inactive then decr(limit) | |
> else buffer[limit]:=end_line_char; | |
> first:=limit+1; loc:=start; {ready to read} | |
6293c7479 | |
< @ If the user has set the |pause| parameter to some nonzero value, | |
--- | |
> @ If the user has set the |pausing| parameter to some positive value, | |
6302,6312c7488,7499 | |
< begin limit←last; | |
< if (pause≠0)∧(interaction>nonstop_mode) then | |
< begin print_ln; | |
< if start<limit then for k←start to limit-1 do print(buffer[k]); | |
< first←limit; prompt_input("=>"); {wait for user response} | |
< if last>first then | |
< begin for k←first to last-1 do {move line down in buffer} | |
< buffer[k+start-first]←buffer[k]; | |
< limit←start+last-first; | |
< end; | |
< end; | |
--- | |
> begin limit:=last; | |
> if pausing>0 then if interaction>nonstop_mode then | |
> begin wake_up_terminal; print_ln; | |
> if start<limit then for k:=start to limit-1 do print(buffer[k]); | |
> first:=limit; prompt_input("=>"); {wait for user response} | |
> @.=>@> | |
> if last>first then | |
> begin for k:=first to last-1 do {move line down in buffer} | |
> buffer[k+start-first]:=buffer[k]; | |
> limit:=start+last-first; | |
> end; | |
> end; | |
6321c7508 | |
< \yskip\hang|get_nc_token|, meaning ``get the non-|call| token,'' is like | |
--- | |
> \yskip\hang|get_x_token|, meaning ``get an expanded token,'' is like | |
6323,6324c7510,7513 | |
< control sequence (i.e., a macro call), or something like \.{\\topmark}, | |
< it is eliminated from the input by beginning the expansion of the macro. | |
--- | |
> control sequence (i.e., a macro call), or a conditional, | |
> or something like \.{\\topmark} or \.{\\expandafter} or \.{\\csname}, | |
> it is eliminated from the input by beginning the expansion of the macro | |
> or the evaluation of the conditional. | |
6326c7515 | |
< \yskip\hang|nc_token| is like |get_nc_token| except that it assumes that | |
--- | |
> \yskip\hang|x_token| is like |get_x_token| except that it assumes that | |
6330,6331c7519 | |
< In fact, these three procedures account for {\sl all\/} uses of |get_next|, | |
< except for one place in the ``inner loop'' when |cur_tok| need not be set. | |
--- | |
> In fact, these three procedures account for almost every use of |get_next|. | |
6333,6344c7521,7523 | |
< @ The |get_token| routine also has a special test built into it to make | |
< sure that the token found is not `|endv|', i.e., the end of a template, | |
< since this would be a bad case of misalignment. We wouldn't want an |endv| | |
< to be deleted or to infiltrate another token list, and |get_token| is used | |
< only in the |error| routine or when building token lists, or in a few | |
< other very special cases. The |endv| problem | |
< hardly ever arises in a form where recovery is feasible, so no recovery | |
< mechanism has been provided. | |
< | |
< No new control sequences will be defined except during a call of | |
< |get_token|, because |no_new_control_sequence| is always |true| at | |
< other times. | |
--- | |
> @ No new control sequences will be defined except during a call of | |
> |get_token|, or when \.{\\csname} compresses a token list, because | |
> |no_new_control_sequence| is always |true| at other times. | |
6347,6373c7526,7574 | |
< begin no_new_control_sequence←false; get_next; no_new_control_sequence←true; | |
< if cs_ptr=0 then | |
< begin if cur_cmd=endv then | |
< fatal_error("(alignment is fouled up somehow)"); | |
< @.alignment is fouled up@> | |
< cur_tok←(cur_cmd*@'400)+cur_chr; | |
< end | |
< else cur_tok←cs_token_flag+cs_ptr; | |
< end; | |
< | |
< @ The only command codes |>max_command| that can be returned by the | |
< |get_next| routine are |undefined_cs|, |top_bot_mark|, |call|, |long_call|, | |
< |outer_call|, and |long_outer_call|, in increasing numerical order. | |
< | |
< @p@t\4@>@<Declare the procedure called |macro_call|@> | |
< procedure get_nc_token; {sets |cur_cmd|, |cur_chr|, |cur_tok|, | |
< and expands macros} | |
< label done; | |
< begin loop begin get_next; | |
< if cur_cmd≤max_command then goto done; | |
< if cur_cmd≥call then macro_call | |
< else if cur_cmd=top_bot_mark then | |
< @<Insert the \(a)appropriate mark text into the scanner@> | |
< else @<Complain about an undefined macro@>; | |
< end; | |
< done: if cs_ptr=0 then cur_tok←(cur_cmd*@'400)+cur_chr | |
< else cur_tok←cs_token_flag+cs_ptr; | |
--- | |
> begin no_new_control_sequence:=false; get_next; no_new_control_sequence:=true; | |
> @^inner loop@> | |
> if cur_cs=0 then cur_tok:=(cur_cmd*@'400)+cur_chr | |
> else cur_tok:=cs_token_flag+cur_cs; | |
> end; | |
> | |
> @* \[25] Expanding the next token. | |
> Only a dozen or so command codes |>max_command| can possibly be returned by | |
> |get_next|; in increasing order, they are |undefined_cs|, |expand_after|, | |
> |no_expand|, |input|, |if_test|, |fi_or_else|, |cs_name|, |convert|, |the|, | |
> |top_bot_mark|, |call|, |long_call|, |outer_call|, |long_outer_call|, and | |
> |end_template|.{\emergencystretch=40pt\par} | |
> | |
> The |expand| subroutine is used when |cur_cmd>max_command|. It removes a | |
> ``call'' or a conditional or one of the other special operations just | |
> listed. It follows that |expand| might invoke itself recursively. In all | |
> cases, |expand| destroys the current token, but it sets things up so that | |
> the next |get_next| will deliver the appropriate next token. The value of | |
> |cur_tok| need not be known when |expand| is called. | |
> | |
> Since several of the basic scanning routines communicate via global variables, | |
> their values are saved as local variables of |expand| so that | |
> recursive calls don't invalidate them. | |
> @^recursion@> | |
> | |
> @p@t\4@>@<Declare the procedure called |macro_call|@>@;@/ | |
> @t\4@>@<Declare the procedure called |insert_relax|@>@;@/ | |
> procedure@?pass_text; forward;@t\2@> | |
> procedure@?start_input; forward;@t\2@> | |
> procedure@?conditional; forward;@t\2@> | |
> procedure@?get_x_token; forward;@t\2@> | |
> procedure@?conv_toks; forward;@t\2@> | |
> procedure@?ins_the_toks; forward;@t\2@> | |
> procedure expand; | |
> var t:halfword; {token that is being ``expanded after''} | |
> @!p,@!q,@!r:pointer; {for list manipulation} | |
> @!j:0..buf_size; {index into |buffer|} | |
> @!cv_backup:integer; {to save the global quantity |cur_val|} | |
> @!cvl_backup,@!radix_backup,@!co_backup:small_number; | |
> {to save |cur_val_level|, etc.} | |
> @!backup_backup:pointer; {to save |link(backup_head)|} | |
> @!save_scanner_status:small_number; {temporary storage of |scanner_status|} | |
> begin cv_backup:=cur_val; cvl_backup:=cur_val_level; radix_backup:=radix; | |
> co_backup:=cur_order; backup_backup:=link(backup_head); | |
> if cur_cmd<call then @<Expand a nonmacro@> | |
> else if cur_cmd<end_template then macro_call | |
> else @<Insert a token containing |frozen_endv|@>; | |
> cur_val:=cv_backup; cur_val_level:=cvl_backup; radix:=radix_backup; | |
> cur_order:=co_backup; link(backup_head):=backup_backup; | |
6375a7577,7618 | |
> @ @<Expand a nonmacro@>= | |
> begin if tracing_commands>1 then show_cur_cmd_chr; | |
> case cur_cmd of | |
> top_bot_mark:@<Insert the \(a)appropriate mark text into the scanner@>; | |
> expand_after:@<Expand the token after the next token@>; | |
> no_expand:@<Suppress expansion of the next token@>; | |
> cs_name:@<Manufacture a control sequence name@>; | |
> convert:conv_toks; {this procedure is discussed in Part 27 below} | |
> the:ins_the_toks; {this procedure is discussed in Part 27 below} | |
> if_test:conditional; {this procedure is discussed in Part 28 below} | |
> fi_or_else:@<Terminate the current conditional and skip to \.{\\fi}@>; | |
> input:@<Initiate or terminate input from a file@>; | |
> othercases @<Complain about an undefined macro@> | |
> endcases; | |
> end | |
> | |
> @ It takes only a little shuffling to do what \TeX\ calls \.{\\expandafter}. | |
> | |
> @<Expand the token after...@>= | |
> begin get_token; t:=cur_tok; get_token; | |
> if cur_cmd>max_command then expand@+else back_input; | |
> cur_tok:=t; back_input; | |
> end | |
> | |
> @ The implementation of \.{\\noexpand} is a bit trickier, because it is | |
> necessary to insert a special `|dont_expand|' marker into \TeX's reading | |
> mechanism. This special marker is processed by |get_next|, but it does | |
> not slow down the inner loop. | |
> | |
> Since \.{\\outer} macros might arise here, we must also | |
> clear the |scanner_status| temporarily. | |
> | |
> @<Suppress expansion...@>= | |
> begin save_scanner_status:=scanner_status; scanner_status:=normal; | |
> get_token; scanner_status:=save_scanner_status; t:=cur_tok; | |
> back_input; {now |start| and |loc| point to the backed-up token |t|} | |
> if t>=cs_token_flag then | |
> begin p:=get_avail; info(p):=cs_token_flag+frozen_dont_expand; | |
> link(p):=loc; start:=p; loc:=p; | |
> end; | |
> end | |
> | |
6377c7620 | |
< begin print_nl("! Undefined control sequence"); | |
--- | |
> begin print_err("Undefined control sequence"); | |
6387,6388c7630,7632 | |
< @ The |get_nc_token| procedure is equivalent to two consecutive | |
< procedure calls: |get_next; nc_token|. | |
--- | |
> @ The |expand| procedure and some other routines that construct token | |
> lists find it convenient to use the following macros, which are valid only if | |
> the variables |p| and |q| are reserved for token-list building. | |
6390,6400c7634,7747 | |
< @p procedure nc_token; {|get_nc_token| without the initial |get_next|} | |
< label done; | |
< begin loop begin if cur_cmd≤max_command then goto done; | |
< if cur_cmd≥call then macro_call | |
< else if cur_cmd=top_bot_mark then | |
< @<Insert the \(a)appropriate mark text into the scanner@> | |
< else @<Complain about an undefined macro@>; | |
< get_next; | |
< end; | |
< done: if cs_ptr=0 then cur_tok←(cur_cmd*@'400)+cur_chr | |
< else cur_tok←cs_token_flag+cs_ptr; | |
--- | |
> @d store_new_token(#)==begin q:=get_avail; link(p):=q; info(q):=#; | |
> p:=q; {|link(p)| is |null|} | |
> end | |
> @d fast_store_new_token(#)==begin fast_get_avail(q); link(p):=q; info(q):=#; | |
> p:=q; {|link(p)| is |null|} | |
> end | |
> | |
> @ @<Manufacture a control...@>= | |
> begin r:=get_avail; p:=r; {head of the list of characters} | |
> repeat get_x_token; | |
> if cur_cs=0 then store_new_token(cur_tok); | |
> until cur_cs<>0; | |
> if cur_cmd<>end_cs_name then @<Complain about missing \.{\\endcsname}@>; | |
> @<Look up the characters of list |r| in the hash table, and set |cur_cs|@>; | |
> flush_list(r); | |
> if eq_type(cur_cs)=undefined_cs then | |
> begin eq_define(cur_cs,relax,256); {N.B.: The |save_stack| might change} | |
> end; {the control sequence will now match `\.{\\relax}'} | |
> cur_tok:=cur_cs+cs_token_flag; back_input; | |
> end | |
> | |
> @ @<Complain about missing \.{\\endcsname}@>= | |
> begin print_err("Missing "); print_esc("endcsname"); print(" inserted"); | |
> @.Missing \\endcsname...@> | |
> help2("The control sequence marked <to be read again> should")@/ | |
> ("not appear between \csname and \endcsname."); | |
> back_error; | |
> end | |
> | |
> @ @<Look up the characters of list |r| in the hash table...@>= | |
> j:=first; p:=link(r); | |
> while p<>null do | |
> begin if j>=max_buf_stack then | |
> begin max_buf_stack:=j+1; | |
> if max_buf_stack=buf_size then | |
> overflow("buffer size",buf_size); | |
> @:TeX capacity exceeded buffer size}{\quad buffer size@> | |
> end; | |
> buffer[j]:=info(p) mod @'400; incr(j); p:=link(p); | |
> end; | |
> if j>first+1 then | |
> begin no_new_control_sequence:=false; cur_cs:=id_lookup(first,j-first); | |
> no_new_control_sequence:=true; | |
> end | |
> else if j=first then cur_cs:=null_cs {the list is empty} | |
> else cur_cs:=single_base+buffer[first] {the list has length one} | |
> | |
> @ An |end_template| command is effectively changed to an |endv| command | |
> by the following code. (The reason for this is discussed below; the | |
> |frozen_end_template| at the end of the template has passed the | |
> |check_outer_validity| test, so its mission of error detection has been | |
> accomplished.) | |
> | |
> @<Insert a token containing |frozen_endv|@>= | |
> begin cur_tok:=cs_token_flag+frozen_endv; back_input; | |
> end | |
> | |
> @ The processing of \.{\\input} involves the |start_input| subroutine, | |
> which will be declared later; the processing of \.{\\endinput} is trivial. | |
> | |
> @<Put each...@>= | |
> primitive("input",input,0);@/ | |
> @!@:input_}{\.{\\input} primitive@> | |
> primitive("endinput",input,1);@/ | |
> @!@:end_input_}{\.{\\endinput} primitive@> | |
> | |
> @ @<Cases of |print_cmd_chr|...@>= | |
> input: if chr_code=0 then print_esc("input")@+else print_esc("endinput"); | |
> | |
> @ @<Initiate or terminate input...@>= | |
> if cur_chr>0 then force_eof:=true | |
> else if name_in_progress then insert_relax | |
> else start_input | |
> | |
> @ Sometimes the expansion looks too far ahead, so we want to insert | |
> a harmless \.{\\relax} into the user's input. | |
> | |
> @<Declare the procedure called |insert_relax|@>= | |
> procedure insert_relax; | |
> begin cur_tok:=cs_token_flag+cur_cs; back_input; | |
> cur_tok:=cs_token_flag+frozen_relax; back_input; token_type:=inserted; | |
> end; | |
> | |
> @ Here is a recursive procedure that is \TeX's usual way to get the | |
> next token of input. It has been slightly optimized to take account of | |
> common cases. | |
> | |
> @p procedure get_x_token; {sets |cur_cmd|, |cur_chr|, |cur_tok|, | |
> and expands macros} | |
> label restart,done; | |
> begin restart: get_next; | |
> @^inner loop@> | |
> if cur_cmd<=max_command then goto done; | |
> if cur_cmd>=call then | |
> if cur_cmd<end_template then macro_call | |
> else begin cur_cs:=frozen_endv; cur_cmd:=endv; | |
> goto done; {|cur_chr=null_list|} | |
> end | |
> else expand; | |
> goto restart; | |
> done: if cur_cs=0 then cur_tok:=(cur_cmd*@'400)+cur_chr | |
> else cur_tok:=cs_token_flag+cur_cs; | |
> end; | |
> | |
> @ The |get_x_token| procedure is equivalent to two consecutive | |
> procedure calls: |get_next; x_token|. | |
> | |
> @p procedure x_token; {|get_x_token| without the initial |get_next|} | |
> begin while cur_cmd>max_command do | |
> begin expand; | |
> get_next; | |
> end; | |
> if cur_cs=0 then cur_tok:=(cur_cmd*@'400)+cur_chr | |
> else cur_tok:=cs_token_flag+cur_cs; | |
6402,6403c7749,7750 | |
< @* \[25] Expanding user macros. | |
< A control sequence that has been \.{\\def}'ed by the user is expanded by | |
--- | |
> | |
> @ A control sequence that has been \.{\\def}'ed by the user is expanded by | |
6426c7773 | |
< {token lists for marks} | |
--- | |
> {token lists for marks} | |
6429,6430c7776,7777 | |
< top_mark←null; first_mark←null; bot_mark←null; | |
< split_first_mark←null; split_bot_mark←null; | |
--- | |
> top_mark:=null; first_mark:=null; bot_mark:=null; | |
> split_first_mark:=null; split_bot_mark:=null; | |
6446,6451c7793,7798 | |
< first_mark_code: print_esc("firstmark"); | |
< bot_mark_code: print_esc("botmark"); | |
< split_first_mark_code: print_esc("splitfirstmark"); | |
< split_bot_mark_code: print_esc("splitbotmark"); | |
< othercases print_esc("topmark") | |
< endcases; | |
--- | |
> first_mark_code: print_esc("firstmark"); | |
> bot_mark_code: print_esc("botmark"); | |
> split_first_mark_code: print_esc("splitfirstmark"); | |
> split_bot_mark_code: print_esc("splitbotmark"); | |
> othercases print_esc("topmark") | |
> endcases; | |
6457,6458c7804,7805 | |
< begin if cur_mark[cur_chr]≠null then | |
< begin_token_list(cur_mark[cur_chr],mark_text); | |
--- | |
> begin if cur_mark[cur_chr]<>null then | |
> begin_token_list(cur_mark[cur_chr],mark_text); | |
6461,6464c7808,7821 | |
< @ Now let's consider |macro_call| itself, which is invoked when |cur_cmd| | |
< is either |call|, |long_call|, |outer_call|, or |long_outer_call|. The | |
< control sequence definition appears in the token list whose reference count | |
< is in location |cur_chr| of |mem|. | |
--- | |
> @ Now let's consider |macro_call| itself, which is invoked when \TeX\ is | |
> scanning a control sequence whose |cur_cmd| is either |call|, |long_call|, | |
> |outer_call|, or |long_outer_call|. The control sequence definition | |
> appears in the token list whose reference count is in location |cur_chr| | |
> of |mem|. | |
> | |
> The global variable |long_state| will be set to |call| or to |long_call|, | |
> depending on whether or not the control sequence disallows \.{\\par} | |
> in its parameters. The |get_next| routine will set |long_state| to | |
> |outer_call| and emit \.{\\par}, if a file ends or if an \.{\\outer} | |
> control sequence occurs in the midst of an argument. | |
> | |
> @<Glob...@>= | |
> @!long_state:call..long_outer_call; {governs the acceptance of \.{\\par}} | |
6466,6467c7823,7824 | |
< The parameters, if any, must be scanned before the macro is expanded. | |
< Pa\-ram\-eters are token lists without reference counts. They are placed on | |
--- | |
> @ The parameters, if any, must be scanned before the macro is expanded. | |
> Parameters are token lists without reference counts. They are placed on | |
6480c7837 | |
< top of the \TeX's input stack, so that |get_next| will proceed to read it | |
--- | |
> top of\/ \TeX's input stack, so that |get_next| will proceed to read it | |
6483c7840 | |
< The global variable |cs_ptr| contains the |eqtb| address of the control sequence | |
--- | |
> The global variable |cur_cs| contains the |eqtb| address of the control sequence | |
6504d7860 | |
< @!non_long:boolean; {is \.{\\par} forbidden in parameters?} | |
6507,6512c7863,7869 | |
< begin save_scanner_status←scanner_status; save_warning_index←warning_index; | |
< warning_index←cs_ptr; ref_count←cur_chr; r←link(ref_count); n←0; | |
< if tracing_macros≠0 then @<Show the text of the macro being expanded@>; | |
< if info(r)≠end_match_token then | |
< @<Scan the parameters and make |link(r)| point to the macro body; but | |
< |return| if an illegal \.{\\par} is detected@>; | |
--- | |
> @!match_chr:ASCII_code; {character used in parameter} | |
> begin save_scanner_status:=scanner_status; save_warning_index:=warning_index; | |
> warning_index:=cur_cs; ref_count:=cur_chr; r:=link(ref_count); n:=0; | |
> if tracing_macros>0 then @<Show the text of the macro being expanded@>; | |
> if info(r)<>end_match_token then | |
> @<Scan the parameters and make |link(r)| point to the macro body; but | |
> |return| if an illegal \.{\\par} is detected@>; | |
6514c7871 | |
< exit:scanner_status←save_scanner_status; warning_index←save_warning_index; | |
--- | |
> exit:scanner_status:=save_scanner_status; warning_index:=save_warning_index; | |
6522,6523c7879,7881 | |
< while (state=token_list)∧(loc=null) do end_token_list; {conserve stack space} | |
< begin_token_list(ref_count,macro); name←warning_index; loc←link(r); | |
--- | |
> while (state=token_list)and(loc=null)and(token_type<>v_template) do | |
> end_token_list; {conserve stack space} | |
> begin_token_list(ref_count,macro); name:=warning_index; loc:=link(r); | |
6525,6540c7883,7891 | |
< begin if param_ptr+n>max_param_stack then | |
< begin max_param_stack←param_ptr+n; | |
< if max_param_stack>param_size then | |
< overflow("parameter stack size",param_size); | |
< end; | |
< for m←0 to n-1 do param_stack[param_ptr+m]←pstack[m]; | |
< param_ptr←param_ptr+n; | |
< end | |
< | |
< @ The |macro_call| procedure and some other routines that construct token lists | |
< find it convenient to use the following macro, which is valid only if | |
< the variables |p| and |q| are reserved for token-list building. | |
< | |
< @d store_new_token(#)==begin q←get_avail; link(p)←q; info(q)←#; | |
< p←q; {|link(p)| is |null|} | |
< end | |
--- | |
> begin if param_ptr+n>max_param_stack then | |
> begin max_param_stack:=param_ptr+n; | |
> if max_param_stack>param_size then | |
> overflow("parameter stack size",param_size); | |
> @:TeX capacity exceeded parameter stack size}{\quad parameter stack size@> | |
> end; | |
> for m:=0 to n-1 do param_stack[param_ptr+m]:=pstack[m]; | |
> param_ptr:=param_ptr+n; | |
> end | |
6553,6558c7904,7911 | |
< begin scanner_status←matching; unbalance←0; | |
< if (eq_type(cs_ptr)=call)∨(eq_type(cs_ptr)=outer_call) then non_long←true | |
< else non_long←false; | |
< repeat if (info(r)>match_token+255)∨(info(r)<match_token) then s←null | |
< else begin s←link(r); r←s; p←temp_head; link(p)←null; m←0; | |
< end; | |
--- | |
> begin scanner_status:=matching; unbalance:=0; | |
> long_state:=eq_type(cur_cs); | |
> if long_state>=outer_call then long_state:=long_state-2; | |
> repeat link(temp_head):=null; | |
> if (info(r)>match_token+255)or(info(r)<match_token) then s:=null | |
> else begin match_chr:=info(r)-match_token; s:=link(r); r:=s; | |
> p:=temp_head; m:=0; | |
> end; | |
6560c7913 | |
< simply scan the delimiter string@>;@/ | |
--- | |
> simply scan the delimiter string@>;@/ | |
6566c7919 | |
< any token found by |get_token|. Therefore an undelimiter parameter---i.e., | |
--- | |
> any token found by |get_token|. Therefore an undelimited parameter---i.e., | |
6573,6574c7926,7927 | |
< @<Advance \(r)|r|; |goto found| if the parameter delimiter has been | |
< fully matched, otherwise |goto continue|@>; | |
--- | |
> @<Advance \(r)|r|; |goto found| if the parameter delimiter has been | |
> fully matched, otherwise |goto continue|@>; | |
6576,6578c7929,7932 | |
< |goto continue| if a partial match is still in effect; | |
< but abort if |s=null|@>; | |
< if (cur_tok=par_token)∧non_long then @<Report a runaway argument and abort@>; | |
--- | |
> |goto continue| if a partial match is still in effect; | |
> but abort if |s=null|@>; | |
> if cur_tok=par_token then if long_state<>long_call then | |
> @<Report a runaway argument and abort@>; | |
6580,6583c7934,7938 | |
< if cur_tok<left_brace_limit then | |
< @<Contribute an entire group to the current parameter@> | |
< else @<Report an extra right brace and |goto continue|@> | |
< else store_new_token(cur_tok); | |
--- | |
> if cur_tok<left_brace_limit then | |
> @<Contribute an entire group to the current parameter@> | |
> else @<Report an extra right brace and |goto continue|@> | |
> else @<Store the current token, but |goto continue| if it is | |
> a blank space that would become an undelimited parameter@>; | |
6585,6586c7940,7949 | |
< if (info(r)<match_token)∨(info(r)>end_match_token) then goto continue; | |
< found: if s≠null then @<Tidy up the parameter just scanned, and tuck it away@> | |
--- | |
> if info(r)>end_match_token then goto continue; | |
> if info(r)<match_token then goto continue; | |
> found: if s<>null then @<Tidy up the parameter just scanned, and tuck it away@> | |
> | |
> @ @<Store the current token, but |goto continue| if it is...@>= | |
> begin if cur_tok=space_token then | |
> if info(r)<=end_match_token then | |
> if info(r)>=match_token then goto continue; | |
> store_new_token(cur_tok); | |
> end | |
6594,6598c7957,7961 | |
< begin r←link(r); | |
< if (info(r)≥match_token)∧(info(r)≤end_match_token) then | |
< begin if cur_tok<left_brace_limit then decr(align_state); | |
< goto found; | |
< end | |
--- | |
> begin r:=link(r); | |
> if (info(r)>=match_token)and(info(r)<=end_match_token) then | |
> begin if cur_tok<left_brace_limit then decr(align_state); | |
> goto found; | |
> end | |
6603c7966,7967 | |
< begin print_nl("Argument of "); sprint_cs(warning_index); | |
--- | |
> begin back_input; print_err("Argument of "); sprint_cs(warning_index); | |
> @.Argument of \\x has...@> | |
6605,6611c7969,7979 | |
< help5("I've deleted a `}' that doesn't seem to match anything.")@/ | |
< ("For example, `\def\a#1{...}' and `\a}' would produce this")@/ | |
< ("error. If your `}' was spurious, just proceed. Otherwise,")@/ | |
< ("type `I\par}' (including the `}') and I'll tell you about")@/ | |
< ("a runaway argument that might be the root of the problem."); | |
< incr(align_state); non_long←true; error; | |
< end | |
--- | |
> help6("I've run across a `}' that doesn't seem to match anything.")@/ | |
> ("For example, `\def\a#1{...}' and `\a}' would produce")@/ | |
> ("this error. If you simply proceed now, the `\par' that")@/ | |
> ("I've just inserted will cause me to report a runaway")@/ | |
> ("argument that might be the root of the problem. But if")@/ | |
> ("your `}' was spurious, just type `2' and it will go away."); | |
> incr(align_state); long_state:=call; cur_tok:=par_token; ins_error; | |
> goto continue; | |
> end {a white lie; the \.{\\par} won't always trigger a runaway} | |
> | |
> @ If |long_state=outer_call|, a runaway argument has already been reported. | |
6613,6614c7981,7983 | |
< @ @<Report a runaway argument and abort@>= | |
< begin runaway; print_nl("! Paragraph ended before "); sprint_cs(warning_index); | |
--- | |
> @<Report a runaway argument and abort@>= | |
> begin if long_state=call then | |
> begin runaway; print_err("Paragraph ended before "); | |
6616,6622c7985,7993 | |
< print(" was complete"); | |
< help3("I suspect you've forgotten a `}', causing me to apply this")@/ | |
< ("control sequence to too much text. How can we recover?")@/ | |
< ("My plan is to forget the whole thing and hope for the best."); | |
< pstack[n]←link(temp_head); align_state←align_state-unbalance; | |
< for m←0 to n do flush_list(pstack[m]); | |
< back_error; return; | |
--- | |
> sprint_cs(warning_index); print(" was complete"); | |
> help3("I suspect you've forgotten a `}', causing me to apply this")@/ | |
> ("control sequence to too much text. How can we recover?")@/ | |
> ("My plan is to forget the whole thing and hope for the best."); | |
> back_error; | |
> end; | |
> pstack[n]:=link(temp_head); align_state:=align_state-unbalance; | |
> for m:=0 to n do flush_list(pstack[m]); | |
> return; | |
6626c7997 | |
< the predecessor of |r|, and we have found that |cur_tok≠info(r)|. An | |
--- | |
> the predecessor of |r|, and we have found that |cur_tok<>info(r)|. An | |
6642,6655c8013,8027 | |
< if s≠r then | |
< if s=null then @<Report an improper use of the macro and abort@> | |
< else begin t←s; | |
< repeat store_new_token(info(t)); incr(m); u←link(t); v←s; | |
< loop@+ begin if u=r then | |
< if cur_tok≠info(v) then goto done | |
< else begin r←link(v); goto continue; | |
< end; | |
< if info(u)≠info(v) then goto done; | |
< u←link(u); v←link(v); | |
< end; | |
< done: t←link(t); | |
< until t=r; | |
< end | |
--- | |
> if s<>r then | |
> if s=null then @<Report an improper use of the macro and abort@> | |
> else begin t:=s; | |
> repeat store_new_token(info(t)); incr(m); u:=link(t); v:=s; | |
> loop@+ begin if u=r then | |
> if cur_tok<>info(v) then goto done | |
> else begin r:=link(v); goto continue; | |
> end; | |
> if info(u)<>info(v) then goto done; | |
> u:=link(u); v:=link(v); | |
> end; | |
> done: t:=link(t); | |
> until t=r; | |
> r:=s; {at this point, no tokens are recently matched} | |
> end | |
6658c8030 | |
< begin print_nl("! Use of "); sprint_cs(warning_index); | |
--- | |
> begin print_err("Use of "); sprint_cs(warning_index); | |
6662,6664c8034,8036 | |
< ("put `1' after `\a', since control sequence names are")@/ | |
< ("made up of letters only. The macro here has not been")@/ | |
< ("followed by the required stuff, so I'm ignoring it."); | |
--- | |
> ("put `1' after `\a', since control sequence names are")@/ | |
> ("made up of letters only. The macro here has not been")@/ | |
> ("followed by the required stuff, so I'm ignoring it."); | |
6669,6679c8041,8052 | |
< begin unbalance←1; | |
< loop@+ begin store_new_token(cur_tok); get_token; | |
< if (cur_tok=par_token)∧ non_long then | |
< @<Report a runaway argument and abort@>; | |
< if cur_tok<right_brace_limit then | |
< if cur_tok<left_brace_limit then incr(unbalance) | |
< else begin decr(unbalance); | |
< if unbalance=0 then goto done1; | |
< end; | |
< end; | |
< done1: rbrace_ptr←p; store_new_token(cur_tok); | |
--- | |
> begin unbalance:=1; | |
> @^inner loop@> | |
> loop@+ begin fast_store_new_token(cur_tok); get_token; | |
> if cur_tok=par_token then if long_state<>long_call then | |
> @<Report a runaway argument and abort@>; | |
> if cur_tok<right_brace_limit then | |
> if cur_tok<left_brace_limit then incr(unbalance) | |
> else begin decr(unbalance); | |
> if unbalance=0 then goto done1; | |
> end; | |
> end; | |
> done1: rbrace_ptr:=p; store_new_token(cur_tok); | |
6686,6690c8059,8063 | |
< begin if (m=1)∧(info(p)<right_brace_limit)∧(p≠temp_head) then | |
< begin link(rbrace_ptr)←null; free_avail(p); | |
< p←link(temp_head); pstack[n]←link(p); free_avail(p); | |
< end | |
< else pstack[n]←link(temp_head); | |
--- | |
> begin if (m=1)and(info(p)<right_brace_limit)and(p<>temp_head) then | |
> begin link(rbrace_ptr):=null; free_avail(p); | |
> p:=link(temp_head); pstack[n]:=link(p); free_avail(p); | |
> end | |
> else pstack[n]:=link(temp_head); | |
6692,6696c8065,8069 | |
< if tracing_macros≠0 then | |
< begin begin_diagnostic; print_nl("#"); print_int(n); | |
< print("<-"); show_token_list(pstack[n-1],null,1000); | |
< end_diagnostic; | |
< end; | |
--- | |
> if tracing_macros>0 then | |
> begin begin_diagnostic; print_nl(match_chr); print_int(n); | |
> print("<-"); show_token_list(pstack[n-1],null,1000); | |
> end_diagnostic(false); | |
> end; | |
6701c8074 | |
< token_show(ref_count); end_diagnostic; | |
--- | |
> token_show(ref_count); end_diagnostic(false); | |
6702a8076 | |
> | |
6706c8080,8081 | |
< some are quite elaborate. | |
--- | |
> some are quite elaborate. Almost all of the routines call |get_x_token|, | |
> which can cause them to be invoked recursively. | |
6707a8083 | |
> @^recursion@> | |
6711c8087,8088 | |
< a character whose chcode is |left_brace|.) | |
--- | |
> a character whose catcode is |left_brace|.) \TeX\ allows \.{\\relax} to | |
> appear before the |left_brace|. | |
6714,6729c8091,8106 | |
< begin @<Get the next non-blank non-call token@>; | |
< if cur_cmd≠left_brace then | |
< begin print_nl("! Missing { inserted"); | |
< @.Missing {\{} inserted@> | |
< help4("A left brace was mandatory here, so I've put one in.")@/ | |
< ("You might want to delete and/or insert some corrections")@/ | |
< ("so that I will find a matching right brace soon.")@/ | |
< ("If you're confused by all this, try typing `I}' now."); | |
< back_error; cur_tok←left_brace_token+"{"; cur_cmd←left_brace; | |
< cur_chr←"{"; incr(align_state); | |
< end; | |
< end; | |
< | |
< @ @<Get the next non-blank non-call...@>= | |
< repeat get_nc_token; | |
< until cur_cmd≠spacer | |
--- | |
> begin @<Get the next non-blank non-relax non-call token@>; | |
> if cur_cmd<>left_brace then | |
> begin print_err("Missing { inserted"); | |
> @.Missing \{ inserted@> | |
> help4("A left brace was mandatory here, so I've put one in.")@/ | |
> ("You might want to delete and/or insert some corrections")@/ | |
> ("so that I will find a matching right brace soon.")@/ | |
> ("(If you're confused by all this, try typing `I}' now.)"); | |
> back_error; cur_tok:=left_brace_token+"{"; cur_cmd:=left_brace; | |
> cur_chr:="{"; incr(align_state); | |
> end; | |
> end; | |
> | |
> @ @<Get the next non-blank non-relax non-call token@>= | |
> repeat get_x_token; | |
> until (cur_cmd<>spacer)and(cur_cmd<>relax) | |
6732c8109 | |
< by optional spaces. | |
--- | |
> by optional spaces; `\.{\\relax}' is not ignored here. | |
6735,6759c8112,8113 | |
< begin @<Get the next non-blank non-call...@>; | |
< if cur_tok≠other_token+"=" then back_input; | |
< end; | |
< | |
< @ Here is a procedure that ignores text until coming to a right brace at | |
< level zero, assuming that we start at a given level |l| of nested braces. | |
< The closing right brace is followed by an optional space. | |
< | |
< @p procedure pass_block(@!l:integer); | |
< label done; | |
< begin scanner_status←skipping; | |
< loop@+ begin get_token; | |
< if cur_cmd=right_brace then | |
< begin l←l-1; | |
< if l≤0 then goto done; | |
< end | |
< else if cur_cmd=left_brace then l←l+1; | |
< end; | |
< done: if l<0 then | |
< begin incr(align_state); print_nl("! Missing { inserted"); | |
< @.Missing {\{} inserted@> | |
< help2("There should have been a `{' before the `}' that")@/ | |
< ("I just looked at. So I put one in."); error; | |
< end; | |
< scanner_status←normal; @<Scan an optional space@>; | |
--- | |
> begin @<Get the next non-blank non-call token@>; | |
> if cur_tok<>other_token+"=" then back_input; | |
6762,6764c8116,8118 | |
< @ @<Scan an optional space@>= | |
< begin get_nc_token; if cur_cmd≠spacer then back_input; | |
< end | |
--- | |
> @ @<Get the next non-blank non-call token@>= | |
> repeat get_x_token; | |
> until cur_cmd<>spacer | |
6767,6768c8121,8122 | |
< Given a string of lower case letters, like `\.{pt}' or `\.{plus}' or | |
< `\.{after}', the |scan_keyword| routine checks to see whether the next | |
--- | |
> Given a string of lowercase letters, like `\.{pt}' or `\.{plus}' or | |
> `\.{width}', the |scan_keyword| routine checks to see whether the next | |
6770c8124 | |
< upper case letters will match their lower case counterparts; upper case | |
--- | |
> uppercase letters will match their lowercase counterparts; uppercase | |
6779c8133 | |
< | |
--- | |
> @^inner loop@> | |
6786c8140 | |
< begin p←scan_head; link(p)←null; k←str_start[s]; | |
--- | |
> begin p:=backup_head; link(p):=null; k:=str_start[s]; | |
6788,6798c8142,8154 | |
< begin get_nc_token; | |
< if (cur_cmd=letter)∧@| | |
< ((cur_chr=str_pool[k])∨(cur_chr=str_pool[k]-"a"+"A")) then | |
< begin store_new_token(cur_tok); incr(k) | |
< end | |
< else begin back_input; | |
< if p≠scan_head then ins_list(link(scan_head)); | |
< scan_keyword←false; return; | |
< end; | |
< end; | |
< flush_list(link(scan_head)); scan_keyword←true; | |
--- | |
> begin get_x_token; {recursion is possible here} | |
> @^recursion@> | |
> if (cur_cs=0)and@| | |
> ((cur_chr=so(str_pool[k]))or(cur_chr=so(str_pool[k])-"a"+"A")) then | |
> begin store_new_token(cur_tok); incr(k); | |
> end | |
> else if (cur_cmd<>spacer)or(p<>backup_head) then | |
> begin back_input; | |
> if p<>backup_head then back_list(link(backup_head)); | |
> scan_keyword:=false; return; | |
> end; | |
> end; | |
> flush_list(link(backup_head)); scan_keyword:=true; | |
6801,6802c8157,8169 | |
< @ The next routine `|scan_the|' is used to handle the `\.{\\the}' in | |
< constructions like `\.{\\the\\month}' and `\.{\\the\\hsize}' and | |
--- | |
> @ Here is a procedure that sounds an alarm when mu and non-mu units | |
> are being switched. | |
> | |
> @p procedure mu_error; | |
> begin print_err("Incompatible glue units"); | |
> @.Incompatible glue units@> | |
> help1("I'm going to assume that 1mu=1pt when they're mixed."); | |
> error; | |
> end; | |
> | |
> @ The next routine `|scan_something_internal|' is used to fetch internal | |
> numeric quantities like `\.{\\hsize}', and also to handle the `\.{\\the}' | |
> when expanding constructions like `\.{\\the\\toks0}' and | |
6804,6807c8171,8175 | |
< procedure, which calls |scan_the|; on the other hand, |scan_the| also | |
< calls |scan_int|, for constructions like `\.{\\the\\chcode\`\\\$}' or | |
< `\.{\\the\\texinfo 20 3}'. So we have to declare |scan_int| as a | |
< |forward| procedure. | |
--- | |
> procedure, which calls |scan_something_internal|; on the other hand, | |
> |scan_something_internal| also calls |scan_int|, for constructions like | |
> `\.{\\catcode\`\\\$}' or `\.{\\fontdimen} \.3 \.{\\ff}'. So we | |
> have to declare |scan_int| as a |forward| procedure. A few other | |
> procedures are also declared at this point. | |
6810c8178,8179 | |
< @t\4\4@>@<Declare procedures that scan restricted classes of integers@> | |
--- | |
> @t\4\4@>@<Declare procedures that scan restricted classes of integers@>@; | |
> @t\4\4@>@<Declare procedures that scan font-related stuff@> | |
6812,6815c8181,8183 | |
< @ A single word `\.{\\the}' is used for integers, dimensions, and glue | |
< speci\-fi\-ca\-tions, so \TeX\ doesn't know exactly what to expect when | |
< |scan_the| begins. For example, any of the three types could occur | |
< immediately after `\.{\\hskip\\the}'; and one can even use \.{\\the} with | |
--- | |
> @ \TeX\ doesn't know exactly what to expect when |scan_something_internal| | |
> begins. For example, an integer or dimension or glue value could occur | |
> immediately after `\.{\\hskip}'; and one can even say \.{\\the} with | |
6818,6830c8186,8201 | |
< allowed after a construction like `\.{\\count\\the}'. To handle the | |
< various possibilities, |scan_the| has a |level| parameter, which tells the | |
< ``highest'' kind of quantity that |scan_the| is allowed to produce. Five | |
< levels are distinguished, namely |int_val|, |dimen_val|, |glue_val|, | |
< |mu_val|, and |tok_val|. | |
< | |
< The output of |scan_the| (and of the other routines |scan_int|, |scan_dimen|, | |
< and |scan_glue| below) is put into the global variable |cur_val|, and its | |
< level is put into |cur_val_level|. The highest values of |cur_val_level| are | |
< special: |mu_val| is used only when |cur_val| points to one of the three | |
< parameters \.{\\thinmskip}, \.{\\midmskip}, \.{\\thickmskip}, and |tok_val| | |
< is used only in cases that `\.{\\the\\output}' and `\.{\\the\\everypar}' | |
< are legitimate. | |
--- | |
> allowed after a construction like `\.{\\count}'. To handle the various | |
> possibilities, |scan_something_internal| has a |level| parameter, which | |
> tells the ``highest'' kind of quantity that |scan_something_internal| is | |
> allowed to produce. Six levels are distinguished, namely |int_val|, | |
> |dimen_val|, |glue_val|, |mu_val|, |ident_val|, and |tok_val|. | |
> | |
> The output of |scan_something_internal| (and of the other routines | |
> |scan_int|, |scan_dimen|, and |scan_glue| below) is put into the global | |
> variable |cur_val|, and its level is put into |cur_val_level|. The highest | |
> values of |cur_val_level| are special: |mu_val| is used only when | |
> |cur_val| points to something in a ``muskip'' register, or to one of the | |
> three parameters \.{\\thinmuskip}, \.{\\medmuskip}, \.{\\thickmuskip}; | |
> |ident_val| is used only when |cur_val| points to a font identifier; | |
> |tok_val| is used only when |cur_val| points to |null| or to the reference | |
> count of a token list. The last two cases are allowed only when | |
> |scan_something_internal| is called with |level=tok_val|. | |
6834,6835c8205,8206 | |
< reference; if the output is a token list, |cur_val| will point to its | |
< reference count, but in this case the count will not have been updated. | |
--- | |
> reference; if the output is a nonempty token list, |cur_val| will point to | |
> its reference count, but in this case the count will not have been updated. | |
6842c8213,8214 | |
< @d tok_val=4 {token lists} | |
--- | |
> @d ident_val=4 {font identifier} | |
> @d tok_val=5 {token lists} | |
6848,6854c8220,8223 | |
< @ The hash table is initialized with `\.{\\count}', `\.{\\dimen}', and | |
< `\.{\\skip}' all having |register| as their command code; they are distinguished | |
< by the |chr_code|, which is either |int_val|, |dimen_val|, or |glue_val|. | |
< The `\.{\\hangindent}' primitive is constructed so that |scan_the| can | |
< treat it exactly like a dimension parameter. The two primitives whose | |
< command code is `|the|' are different solely because the |equiv| is | |
< zero for `\.{\\the}' and nonzero for `\.{\\minus}'. | |
--- | |
> @ The hash table is initialized with `\.{\\count}', `\.{\\dimen}', `\.{\\skip}', | |
> and `\.{\\muskip}' all having |register| as their command code; they are | |
> distinguished by the |chr_code|, which is either |int_val|, |dimen_val|, | |
> |glue_val|, or |mu_val|. | |
6863,6868c8232,8233 | |
< primitive("hangindent",hang_indent,hanging_indent_code); | |
< @!@:hangindent_}{\.{\\hangindent} primitive@> | |
< primitive("the",the,0); | |
< @!@:the_}{\.{\\the} primitive@> | |
< primitive("minus",the,1); | |
< @!@:minus_}{\.{\\minus} primitive@> | |
--- | |
> primitive("muskip",register,mu_val); | |
> @!@:mu_skip_}{\.{\\muskip} primitive@> | |
6872,6879c8237,8245 | |
< else if chr_code=dimen_val then print_esc("dimen") | |
< else print_esc("skip"); | |
< hang_indent:print_esc("hangindent"); | |
< the: if chr_code=0 then print_esc("the")@+else print_esc("minus"); | |
< | |
< @ OK, we're ready for |scan_the| itself. A second parameter, |negative|, | |
< is set |true| if we want the value to be negated (e.g., if `\.{\\minus}' | |
< has appeared instead of `\.{\\the}'). | |
--- | |
> else if chr_code=dimen_val then print_esc("dimen") | |
> else if chr_code=glue_val then print_esc("skip") | |
> else print_esc("muskip"); | |
> | |
> @ OK, we're ready for |scan_something_internal| itself. A second parameter, | |
> |negative|, is set |true| if the value that is found should be negated. | |
> It is assumed that |cur_cmd| and |cur_chr| represent the first token of | |
> the internal quantity to be scanned; an error will be signalled if | |
> |cur_cmd<min_internal| or |cur_cmd>max_internal|. | |
6881,6882c8247,8248 | |
< @d scanned_result_end(#)==cur_val_level←#; end | |
< @d scanned_result(#)==@+begin cur_val←#;scanned_result_end | |
--- | |
> @d scanned_result_end(#)==cur_val_level:=#;@+end | |
> @d scanned_result(#)==@+begin cur_val:=#;scanned_result_end | |
6884,6886c8250,8251 | |
< @p procedure scan_the(@!level:small_number;@!negative:boolean); | |
< {fetch an internal parameter} | |
< label restart; | |
--- | |
> @p procedure scan_something_internal(@!level:small_number;@!negative:boolean); | |
> {fetch an internal parameter} | |
6888c8253,8254 | |
< begin restart: get_nc_token; m←cur_chr; | |
--- | |
> @!p:0..nest_size; {index into |nest|} | |
> begin m:=cur_chr; | |
6891,6895c8257,8262 | |
< assign_toks: @<Fetch a token list, provided that |level=tok_val|@>; | |
< assign_int: scanned_result(int_par(m))(int_val); | |
< assign_dimen,hang_indent: scanned_result(dimen_par(m))(dimen_val); | |
< assign_glue: if m≥thin_mskip then scanned_result(glue_par(m))(mu_val) | |
< else scanned_result(glue_par(m))(glue_val); | |
--- | |
> toks_register,assign_toks,def_family,set_font,def_font: @<Fetch a token list or | |
> font identifier, provided that |level=tok_val|@>; | |
> assign_int: scanned_result(eqtb[m].int)(int_val); | |
> assign_dimen: scanned_result(eqtb[m].sc)(dimen_val); | |
> assign_glue: scanned_result(equiv(m))(glue_val); | |
> assign_mu_glue: scanned_result(equiv(m))(mu_val); | |
6897,6898c8264,8271 | |
< set_family: scanned_result(cur_fam)(int_val); | |
< assign_tex_info: @<Fetch a font parameter@>; | |
--- | |
> set_prev_graf: @<Fetch the |prev_graf|@>; | |
> set_page_int:@<Fetch the |dead_cycles| or the |insert_penalties|@>; | |
> set_page_dimen: @<Fetch something on the |page_so_far|@>; | |
> set_shape: @<Fetch the |par_shape| size@>; | |
> set_box_dimen: @<Fetch a box dimension@>; | |
> char_given,math_given: scanned_result(cur_chr)(int_val); | |
> assign_font_dimen: @<Fetch a font dimension@>; | |
> assign_font_int: @<Fetch a font integer@>; | |
6900,6905c8273 | |
< last_skip: @<Fetch the glue in the current node, if any@>; | |
< set_font: scanned_result(font_code[cur_font])(int_val); | |
< def_family: @<Fetch a math font code@>; | |
< the: begin if m>0 then negative←¬ negative; | |
< goto restart; | |
< end; | |
--- | |
> last_item: @<Fetch an item in the current node, if appropriate@>; | |
6913,6914c8281,8283 | |
< begin scan_seven_bit_int; | |
< if m<del_code_base then scanned_result(equiv(m+cur_val))(int_val) | |
--- | |
> begin scan_char_num; | |
> if m=math_code_base then scanned_result(ho(math_code(cur_val)))(int_val) | |
> else if m<math_code_base then scanned_result(equiv(m+cur_val))(int_val) | |
6918,6925c8287,8314 | |
< @ @<Fetch a token list, provided that |level=tok_val|@>= | |
< if (level≠tok_val)∨ negative then | |
< begin print_nl("! Improper use of \the"); | |
< @.Improper use of \\the@> | |
< help1("I'm forgetting what you said and using zero for this \the."); | |
< back_error; scanned_result(0)(dimen_val); | |
< end | |
< else scanned_result(equiv(m))(tok_val) | |
--- | |
> @ @<Fetch a token list...@>= | |
> if level<>tok_val then | |
> begin print_err("Missing number, treated as zero"); | |
> @.Missing number...@> | |
> help3("A number should have been here; I inserted `0'.")@/ | |
> ("(If you can't figure out why I needed to see a number,")@/ | |
> ("look up `weird error' in the index to The TeXbook.)"); | |
> @:TeXbook}{\sl The \TeX book@> | |
> back_error; scanned_result(0)(dimen_val); | |
> end | |
> else if cur_cmd<=assign_toks then | |
> begin if cur_cmd<assign_toks then {|cur_cmd=toks_register|} | |
> begin scan_eight_bit_int; m:=toks_base+cur_val; | |
> end; | |
> scanned_result(equiv(m))(tok_val); | |
> end | |
> else begin back_input; scan_font_ident; | |
> scanned_result(font_id_base+cur_val)(ident_val); | |
> end | |
> | |
> @ Users refer to `\.{\\the\\spacefactor}' only in horizontal | |
> mode, and to `\.{\\the\\prevdepth}' only in vertical mode; so we put the | |
> associated mode in the modifier part of the |set_aux| command. | |
> The |set_page_int| command has modifier 0 or 1, for `\.{\\deadcycles}' and | |
> `\.{\\insertpenalties}', respectively. The |set_box_dimen| command is | |
> modified by either |width_offset|, |height_offset|, or |depth_offset|. | |
> And the |last_item| command is modified by either |int_val|, |dimen_val|, | |
> |glue_val|, |input_line_no_code|, or |badness_code|. | |
6927,6928c8316,8317 | |
< @ A user is allowed to refer to `\.{\\the\\spacefactor}' only in horizontal | |
< mode, and to `\.{\\the\\prevdepth}' only in vertical mode. | |
--- | |
> @d input_line_no_code=glue_val+1 {code for \.{\\inputlineno}} | |
> @d badness_code=glue_val+2 {code for \.{\\badness}} | |
6933c8322 | |
< primitive("prevdepth",set_aux,vmode); | |
--- | |
> primitive("prevdepth",set_aux,vmode);@/ | |
6934a8324,8343 | |
> primitive("deadcycles",set_page_int,0); | |
> @!@:dead_cycles_}{\.{\\deadcycles} primitive@> | |
> primitive("insertpenalties",set_page_int,1); | |
> @!@:insert_penalties_}{\.{\\insertpenalties} primitive@> | |
> primitive("wd",set_box_dimen,width_offset); | |
> @!@:wd_}{\.{\\wd} primitive@> | |
> primitive("ht",set_box_dimen,height_offset); | |
> @!@:ht_}{\.{\\ht} primitive@> | |
> primitive("dp",set_box_dimen,depth_offset); | |
> @!@:dp_}{\.{\\dp} primitive@> | |
> primitive("lastpenalty",last_item,int_val); | |
> @!@:last_penalty_}{\.{\\lastpenalty} primitive@> | |
> primitive("lastkern",last_item,dimen_val); | |
> @!@:last_kern_}{\.{\\lastkern} primitive@> | |
> primitive("lastskip",last_item,glue_val); | |
> @!@:last_skip_}{\.{\\lastskip} primitive@> | |
> primitive("inputlineno",last_item,input_line_no_code); | |
> @!@:input_line_no_}{\.{\\inputlineno} primitive@> | |
> primitive("badness",last_item,badness_code); | |
> @!@:badness_}{\.{\\badness} primitive@> | |
6938c8347,8359 | |
< else print_esc("spacefactor"); | |
--- | |
> @+else print_esc("spacefactor"); | |
> set_page_int: if chr_code=0 then print_esc("deadcycles") | |
> @+else print_esc("insertpenalties"); | |
> set_box_dimen: if chr_code=width_offset then print_esc("wd") | |
> else if chr_code=height_offset then print_esc("ht") | |
> else print_esc("dp"); | |
> last_item: case chr_code of | |
> int_val: print_esc("lastpenalty"); | |
> dimen_val: print_esc("lastkern"); | |
> glue_val: print_esc("lastskip"); | |
> input_line_no_code: print_esc("inputlineno"); | |
> othercases print_esc("badness") | |
> endcases; | |
6941,6965c8362,8385 | |
< if abs(mode)≠m then | |
< begin print_nl("! Improper use of \the"); | |
< @.Improper use of \\the@> | |
< help4("You can say \the\spacefactor only in horizontal mode,")@/ | |
< ("and \the\prevdepth only in vertical mode; and")@/ | |
< ("neither of these is meaningful inside \send. So")@/ | |
< ("I'm forgetting what you said and using zero for this \the."); | |
< back_error; scanned_result(0)(dimen_val); | |
< end | |
< else begin cur_val←aux; | |
< if m=vmode then cur_val_level←dimen_val@+else cur_val_level←int_val; | |
< end | |
< | |
< @ Here is where \.{\\lastskip} is implemented. The reference count will be | |
< updated later. | |
< @:last_skip_}{\.{\\lastskip} primitive@> | |
< | |
< @<Fetch the glue in the current node, if any@>= | |
< begin cur_val←zero_glue; | |
< if not is_char_node(tail)∧(mode≠0) then | |
< begin if type(tail)=glue_node then cur_val←glue_ptr(tail); | |
< end | |
< else if (mode=vmode)∧(tail=head)∧(last_page_glue≠max_halfword) then | |
< cur_val←last_page_glue; | |
< cur_val_level←glue_val; | |
--- | |
> if abs(mode)<>m then | |
> begin print_err("Improper "); print_cmd_chr(set_aux,m); | |
> @.Improper \\spacefactor@> | |
> @.Improper \\prevdepth@> | |
> help4("You can refer to \spacefactor only in horizontal mode;")@/ | |
> ("you can refer to \prevdepth only in vertical mode; and")@/ | |
> ("neither of these is meaningful inside \write. So")@/ | |
> ("I'm forgetting what you said and using zero instead."); | |
> error; | |
> if level<>tok_val then scanned_result(0)(dimen_val) | |
> else scanned_result(0)(int_val); | |
> end | |
> else if m=vmode then scanned_result(prev_depth)(dimen_val) | |
> else scanned_result(space_factor)(int_val) | |
> | |
> @ @<Fetch the |dead_cycles| or the |insert_penalties|@>= | |
> begin if m=0 then cur_val:=dead_cycles@+else cur_val:=insert_penalties; | |
> cur_val_level:=int_val; | |
> end | |
> | |
> @ @<Fetch a box dimension@>= | |
> begin scan_eight_bit_int; | |
> if box(cur_val)=null then cur_val:=0 @+else cur_val:=mem[box(cur_val)+m].sc; | |
> cur_val_level:=dimen_val; | |
6968,6969c8388,8445 | |
< @ @<Fetch a font parameter@>= | |
< begin scan_tex_info(false); font_info[fmem_ptr].sc←0; | |
--- | |
> @ Inside an \.{\\output} routine, a user may wish to look at the page totals | |
> that were present at the moment when output was triggered. | |
> | |
> @d max_dimen==@'7777777777 {$2^{30}-1$} | |
> | |
> @<Fetch something on the |page_so_far|@>= | |
> begin if (page_contents=empty) and (not output_active) then | |
> if m=0 then cur_val:=max_dimen@+else cur_val:=0 | |
> else cur_val:=page_so_far[m]; | |
> cur_val_level:=dimen_val; | |
> end | |
> | |
> @ @<Fetch the |prev_graf|@>= | |
> if mode=0 then scanned_result(0)(int_val) {|prev_graf=0| within \.{\\write}} | |
> else begin nest[nest_ptr]:=cur_list; p:=nest_ptr; | |
> while abs(nest[p].mode_field)<>vmode do decr(p); | |
> scanned_result(nest[p].pg_field)(int_val); | |
> end | |
> | |
> @ @<Fetch the |par_shape| size@>= | |
> begin if par_shape_ptr=null then cur_val:=0 | |
> else cur_val:=info(par_shape_ptr); | |
> cur_val_level:=int_val; | |
> end | |
> | |
> @ Here is where \.{\\lastpenalty}, \.{\\lastkern}, and \.{\\lastskip} are | |
> implemented. The reference count for \.{\\lastskip} will be updated later. | |
> | |
> We also handle \.{\\inputlineno} and \.{\\badness} here, because they are | |
> legal in similar contexts. | |
> | |
> @<Fetch an item in the current node...@>= | |
> if cur_chr>glue_val then | |
> begin if cur_chr=input_line_no_code then cur_val:=line | |
> else cur_val:=last_badness; {|cur_chr=badness_code|} | |
> cur_val_level:=int_val; | |
> end | |
> else begin if cur_chr=glue_val then cur_val:=zero_glue@+else cur_val:=0; | |
> cur_val_level:=cur_chr; | |
> if not is_char_node(tail)and(mode<>0) then | |
> case cur_chr of | |
> int_val: if type(tail)=penalty_node then cur_val:=penalty(tail); | |
> dimen_val: if type(tail)=kern_node then cur_val:=width(tail); | |
> glue_val: if type(tail)=glue_node then | |
> begin cur_val:=glue_ptr(tail); | |
> if subtype(tail)=mu_glue then cur_val_level:=mu_val; | |
> end; | |
> end {there are no other cases} | |
> else if (mode=vmode)and(tail=head) then | |
> case cur_chr of | |
> int_val: cur_val:=last_penalty; | |
> dimen_val: cur_val:=last_kern; | |
> glue_val: if last_glue<>max_halfword then cur_val:=last_glue; | |
> end; {there are no other cases} | |
> end | |
> | |
> @ @<Fetch a font dimension@>= | |
> begin find_font_dimen(false); font_info[fmem_ptr].sc:=0; | |
6972a8449,8454 | |
> @ @<Fetch a font integer@>= | |
> begin scan_font_ident; | |
> if m=0 then scanned_result(hyphen_char[cur_val])(int_val) | |
> else scanned_result(skew_char[cur_val])(int_val); | |
> end | |
> | |
6976,6978c8458,8461 | |
< int_val:cur_val←count(cur_val); | |
< dimen_val:cur_val←dimen(cur_val); | |
< glue_val:cur_val←skip(cur_val); | |
--- | |
> int_val:cur_val:=count(cur_val); | |
> dimen_val:cur_val:=dimen(cur_val); | |
> glue_val: cur_val:=skip(cur_val); | |
> mu_val: cur_val:=mu_skip(cur_val); | |
6980,6984c8463 | |
< cur_val_level←m; | |
< end | |
< | |
< @ @<Fetch a math font code@>= | |
< begin scan_four_bit_int; scanned_result(font_code[equiv(m+cur_val)])(int_val); | |
--- | |
> cur_val_level:=m; | |
6988,6992c8467,8473 | |
< begin print_nl("! You can't use "); print_cmd_chr(cur_cmd,cur_chr); | |
< @.You can't use x after \\the@> | |
< print(" after \the"); | |
< help1("I'm forgetting what you said and using zero for this \the."); | |
< back_error; scanned_result(0)(dimen_val); | |
--- | |
> begin print_err("You can't use `"); print_cmd_chr(cur_cmd,cur_chr); | |
> @.You can't use x after ...@> | |
> print("' after "); print_esc("the"); | |
> help1("I'm forgetting what you said and using zero instead."); | |
> error; | |
> if level<>tok_val then scanned_result(0)(dimen_val) | |
> else scanned_result(0)(int_val); | |
7002c8483,8484 | |
< begin if cur_val_level=glue_val then cur_val←width(cur_val); | |
--- | |
> begin if cur_val_level=glue_val then cur_val:=width(cur_val) | |
> else if cur_val_level=mu_val then mu_error; | |
7007a8490 | |
> If |negative| is |true|, |cur_val_level| is known to be |<=mu_val|. | |
7011,7017c8494,8506 | |
< if cur_val_level≥glue_val then | |
< begin cur_val←new_spec(cur_val); | |
< @<Negate all three glue components of |cur_val|@>; | |
< end | |
< else cur_val←-cur_val | |
< else if (cur_val_level≥glue_val)∧(cur_val_level≠tok_val) then | |
< add_glue_ref(cur_val) | |
--- | |
> if cur_val_level>=glue_val then | |
> begin cur_val:=new_spec(cur_val); | |
> @<Negate all three glue components of |cur_val|@>; | |
> end | |
> else negate(cur_val) | |
> else if (cur_val_level>=glue_val)and(cur_val_level<=mu_val) then | |
> add_glue_ref(cur_val) | |
> | |
> @ @<Negate all three...@>= | |
> begin negate(width(cur_val)); | |
> negate(stretch(cur_val)); | |
> negate(shrink(cur_val)); | |
> end | |
7021,7032c8510,8511 | |
< applications of |scan_int| that have already been made inside of |scan_the|: | |
< | |
< @<Declare procedures that scan restricted classes of integers@>= | |
< procedure scan_seven_bit_int; | |
< begin scan_int; | |
< if (cur_val<0)∨(cur_val>127) then | |
< begin print_nl("! Bad character code"); | |
< @.Bad character code@> | |
< help2("The numeric code for a character must be between 0 and 127.")@/ | |
< ("I changed this one to zero."); int_error(cur_val); cur_val←0; | |
< end; | |
< end; | |
--- | |
> applications of |scan_int| that have already been made inside of | |
> |scan_something_internal|. | |
7037,7038c8516,8517 | |
< if (cur_val<0)∨(cur_val>255) then | |
< begin print_nl("! Bad register code"); | |
--- | |
> if (cur_val<0)or(cur_val>255) then | |
> begin print_err("Bad register code"); | |
7040,7042c8519,8521 | |
< help2("Boxes, counts, dimens, and skips must be between 0 and 255.")@/ | |
< ("I changed this one to zero."); int_error(cur_val); cur_val←0; | |
< end; | |
--- | |
> help2("A register number must be between 0 and 255.")@/ | |
> ("I changed this one to zero."); int_error(cur_val); cur_val:=0; | |
> end; | |
7046c8525 | |
< procedure scan_four_bit_int; | |
--- | |
> procedure scan_char_num; | |
7048,7053c8527,8532 | |
< if (cur_val<0)∨(cur_val>15) then | |
< begin print_nl("! Bad number"); | |
< @.Bad number@> | |
< help2("Since I expected to read a number between 0 and 15,")@/ | |
< ("I changed this one to zero."); int_error(cur_val); cur_val←0; | |
< end; | |
--- | |
> if (cur_val<0)or(cur_val>255) then | |
> begin print_err("Bad character code"); | |
> @.Bad character code@> | |
> help2("A character number must be between 0 and 255.")@/ | |
> ("I changed this one to zero."); int_error(cur_val); cur_val:=0; | |
> end; | |
7060c8539 | |
< procedure scan_char_num; | |
--- | |
> procedure scan_four_bit_int; | |
7062,7067c8541,8546 | |
< if (cur_val<0)∨(cur_val>255) then | |
< begin print_nl("! Bad \char code"); | |
< @.Bad \\char code@> | |
< help2("The numeric code following \char must be between 0 and 255.")@/ | |
< ("I changed this one to zero."); int_error(cur_val); cur_val←0; | |
< end; | |
--- | |
> if (cur_val<0)or(cur_val>15) then | |
> begin print_err("Bad number"); | |
> @.Bad number@> | |
> help2("Since I expected to read a number between 0 and 15,")@/ | |
> ("I changed this one to zero."); int_error(cur_val); cur_val:=0; | |
> end; | |
7073,7078c8552,8557 | |
< if (cur_val<0)∨(cur_val>@'77777) then | |
< begin print_nl("! Bad \mathchar code"); | |
< @.Bad \\mathchar code@> | |
< help2("A numeric \mathchar code must be between 0 and 32767.")@/ | |
< ("I changed this one to zero."); int_error(cur_val); cur_val←0; | |
< end; | |
--- | |
> if (cur_val<0)or(cur_val>@'77777) then | |
> begin print_err("Bad mathchar"); | |
> @.Bad mathchar@> | |
> help2("A mathchar number must be between 0 and 32767.")@/ | |
> ("I changed this one to zero."); int_error(cur_val); cur_val:=0; | |
> end; | |
7084,7085c8563,8564 | |
< if (cur_val<0)∨(cur_val>@'777777777) then | |
< begin print_nl("! Bad delimiter code"); | |
--- | |
> if (cur_val<0)or(cur_val>@'777777777) then | |
> begin print_err("Bad delimiter code"); | |
7087,7089c8566,8568 | |
< help2("A numeric delimiter code must be between 0 and 2^{27}-1.")@/ | |
< ("I changed this one to zero."); int_error(cur_val); cur_val←0; | |
< end; | |
--- | |
> help2("A numeric delimiter code must be between 0 and 2^{27}-1.")@/ | |
> ("I changed this one to zero."); int_error(cur_val); cur_val:=0; | |
> end; | |
7094,7097c8573,8575 | |
< octal constant (i.e., radix 8, preceded by@@\.\'), a hexadecimal constant | |
< (radix 16, preceded by@@\."), an alphabetic constant (preceded by@@\.\`), or | |
< an internal variable obtained by prefixing \.{\\the}. (The `\.{\\the}' | |
< can be omitted before `\.{\\count}'.) After scanning is complete, | |
--- | |
> octal constant (i.e., radix 8, preceded by~\.\'), a hexadecimal constant | |
> (radix 16, preceded by~\."), an alphabetic constant (preceded by~\.\`), or | |
> an internal variable. After scanning is complete, | |
7101c8579 | |
< otherwise |radix| is set to zero. An optional space follows the number. | |
--- | |
> otherwise |radix| is set to zero. An optional space follows a constant. | |
7103,7106d8580 | |
< @d plus_token=other_token+"+" {plus sign} | |
< @d minus_token=other_token+"-" {minus sign} | |
< @d zero_token=other_token+"0" {zero, the smallest digit} | |
< @d A_token=letter_token+"A" {the smallest special hex digit} | |
7110a8585 | |
> @d continental_point_token=other_token+"," {decimal point, Eurostyle} | |
7114a8590,8596 | |
> @ We initialize the following global variables just in case |expand| | |
> comes into action before any of the basic scanning routines has assigned | |
> them a value. | |
> | |
> @<Set init...@>= | |
> cur_val:=0; cur_val_level:=int_val; radix:=0; cur_order:=normal; | |
> | |
7128c8610 | |
< begin radix←0; OK_so_far←true;@/ | |
--- | |
> begin radix:=0; OK_so_far:=true;@/ | |
7131c8613,8614 | |
< else if (cur_cmd=the)∨(cur_cmd=register) then @<Fetch an internal integer@> | |
--- | |
> else if (cur_cmd>=min_internal)and(cur_cmd<=max_internal) then | |
> scan_something_internal(int_val,false) | |
7133c8616 | |
< if negative then cur_val←-cur_val; | |
--- | |
> if negative then negate(cur_val); | |
7137c8620 | |
< negative←false; | |
--- | |
> negative:=false; | |
7139,7142c8622,8625 | |
< if cur_tok=minus_token then | |
< begin negative ← ¬ negative; cur_tok←plus_token; | |
< end; | |
< until cur_tok≠plus_token | |
--- | |
> if cur_tok=other_token+"-" then | |
> begin negative := not negative; cur_tok:=other_token+"+"; | |
> end; | |
> until cur_tok<>other_token+"+" | |
7149,7154c8632,8642 | |
< if cur_tok<cs_token_flag then cur_val←cur_chr | |
< else if cur_tok<cs_token_flag+active_base then | |
< cur_val←cur_tok-cs_token_flag-single_base | |
< else cur_val←cur_tok-cs_token_flag-active_base; | |
< if cur_val>127 then | |
< begin print_nl("! Improper alphabetic constant"); | |
--- | |
> if cur_tok<cs_token_flag then | |
> begin cur_val:=cur_chr; | |
> if cur_cmd<=right_brace then | |
> if cur_cmd=right_brace then incr(align_state) | |
> else decr(align_state); | |
> end | |
> else if cur_tok<cs_token_flag+single_base then | |
> cur_val:=cur_tok-cs_token_flag-active_base | |
> else cur_val:=cur_tok-cs_token_flag-single_base; | |
> if cur_val>255 then | |
> begin print_err("Improper alphabetic constant"); | |
7156,7159c8644,8647 | |
< help2("A one-character control sequence belongs after a ` mark.")@/ | |
< ("So I'm essentially inserting \0 here."); | |
< cur_val←"0"; back_error; | |
< end | |
--- | |
> help2("A one-character control sequence belongs after a ` mark.")@/ | |
> ("So I'm essentially inserting \0 here."); | |
> cur_val:="0"; back_error; | |
> end | |
7163,7166c8651,8652 | |
< @ @<Fetch an internal integer@>= | |
< begin if cur_cmd=register then back_input {implied `\.{\\the}'} | |
< else if cur_chr≠0 then negative ← ¬ negative; {handle `\.{\\minus}'} | |
< scan_the(int_val,false); | |
--- | |
> @ @<Scan an optional space@>= | |
> begin get_x_token; if cur_cmd<>spacer then back_input; | |
7170c8656 | |
< begin radix←10; m←214748364; | |
--- | |
> begin radix:=10; m:=214748364; | |
7172,7173c8658,8659 | |
< begin radix←8; m←@'2000000000; get_nc_token; | |
< end | |
--- | |
> begin radix:=8; m:=@'2000000000; get_x_token; | |
> end | |
7175,7177c8661,8663 | |
< begin radix←16; m←@'1000000000; get_nc_token; | |
< end; | |
< vacuous←true; cur_val←0;@/ | |
--- | |
> begin radix:=16; m:=@'1000000000; get_x_token; | |
> end; | |
> vacuous:=true; cur_val:=0;@/ | |
7179,7180c8665,8666 | |
< if vacuous then @<Express astonishment that no number was here@>; | |
< if cur_cmd≠spacer then back_input; | |
--- | |
> if vacuous then @<Express astonishment that no number was here@> | |
> else if cur_cmd<>spacer then back_input; | |
7183a8670,8672 | |
> @d zero_token=other_token+"0" {zero, the smallest digit} | |
> @d A_token=letter_token+"A" {the smallest special hex digit} | |
> @d other_A_token=other_token+"A" {special hex digit of type |other_char|} | |
7186,7194c8675,8686 | |
< loop@+ begin if (cur_tok<zero_token+radix)∧(cur_tok≥zero_token)∧ | |
< (cur_tok≤zero_token+9) then d←cur_tok-zero_token | |
< else if (radix=16)∧(cur_tok≤A_token+5)∧(cur_tok≥A_token) then | |
< d←cur_tok-A_token+10 | |
< else goto done; | |
< vacuous←false; | |
< if (cur_val≥m)∧((cur_val>m)∨(d>7)∨(radix≠10)) then | |
< begin if OK_so_far then | |
< begin print_nl("! Number too big"); | |
--- | |
> loop@+ begin if (cur_tok<zero_token+radix)and(cur_tok>=zero_token)and | |
> (cur_tok<=zero_token+9) then d:=cur_tok-zero_token | |
> else if radix=16 then | |
> if (cur_tok<=A_token+5)and(cur_tok>=A_token) then d:=cur_tok-A_token+10 | |
> else if (cur_tok<=other_A_token+5)and(cur_tok>=other_A_token) then | |
> d:=cur_tok-other_A_token+10 | |
> else goto done | |
> else goto done; | |
> vacuous:=false; | |
> if (cur_val>=m)and((cur_val>m)or(d>7)or(radix<>10)) then | |
> begin if OK_so_far then | |
> begin print_err("Number too big"); | |
7196,7203c8688,8695 | |
< help2("I can only go up to 2147483647='17777777777=""7FFFFFFF,")@/ | |
< ("so I'm using that number instead of yours."); | |
< error; cur_val←infinity; OK_so_far←false; | |
< end; | |
< end | |
< else cur_val←cur_val*radix+d; | |
< get_nc_token; | |
< end; | |
--- | |
> help2("I can only go up to 2147483647='17777777777=""7FFFFFFF,")@/ | |
> ("so I'm using that number instead of yours."); | |
> error; cur_val:=infinity; OK_so_far:=false; | |
> end; | |
> end | |
> else cur_val:=cur_val*radix+d; | |
> get_x_token; | |
> end; | |
7207,7208c8699,8700 | |
< begin print_nl("! Missing number"); | |
< @.Missing number@> | |
--- | |
> begin print_err("Missing number, treated as zero"); | |
> @.Missing number...@> | |
7210,7212c8702,8705 | |
< ("(If you can't figure out why I needed to see a number,")@/ | |
< ("look up `weird error' in the TeX manual index.)"); | |
< error; | |
--- | |
> ("(If you can't figure out why I needed to see a number,")@/ | |
> ("look up `weird error' in the index to The TeXbook.)"); | |
> @:TeXbook}{\sl The \TeX book@> | |
> back_error; | |
7243a8737 | |
> @d scan_normal_dimen==scan_dimen(false,false,false) | |
7246,7247c8740,8741 | |
< {sets |cur_val| to a dimension} | |
< label done, found, not_found, attach_fraction, attach_sign; | |
--- | |
> {sets |cur_val| to a dimension} | |
> label done, done1, done2, found, not_found, attach_fraction, attach_sign; | |
7251c8745 | |
< begin f←0; arith_error←false; cur_order←normal; negative←false; | |
--- | |
> begin f:=0; arith_error:=false; cur_order:=normal; negative:=false; | |
7253,7266c8747,8762 | |
< begin @<Get the next non-blank non-sign...@>; | |
< if (cur_cmd=the)∨(cur_cmd=register) then | |
< @<Fetch an internal dimension and |goto attach_sign|, | |
< or fetch an internal integer@> | |
< else begin back_input; | |
< if cur_tok≠point_token then scan_int | |
< else begin radix←10; cur_val←0; | |
< end; | |
< if (radix=10)∧(cur_tok=point_token) then @<Scan decimal fraction@>; | |
< end; | |
< end; | |
< if cur_val<0 then {in this case |f<0|} | |
< begin negative ← ¬ negative; cur_val←-cur_val; | |
< end; | |
--- | |
> begin @<Get the next non-blank non-sign...@>; | |
> if (cur_cmd>=min_internal)and(cur_cmd<=max_internal) then | |
> @<Fetch an internal dimension and |goto attach_sign|, | |
> or fetch an internal integer@> | |
> else begin back_input; | |
> if cur_tok=continental_point_token then cur_tok:=point_token; | |
> if cur_tok<>point_token then scan_int | |
> else begin radix:=10; cur_val:=0; | |
> end; | |
> if cur_tok=continental_point_token then cur_tok:=point_token; | |
> if (radix=10)and(cur_tok=point_token) then @<Scan decimal fraction@>; | |
> end; | |
> end; | |
> if cur_val<0 then {in this case |f=0|} | |
> begin negative := not negative; negate(cur_val); | |
> end; | |
7268,7271c8764 | |
< are $x$ units per sp@>; | |
< attach_sign: if negative then cur_val←-cur_val; | |
< if arith_error ∨(abs(cur_val)≥@'10000000000) then | |
< @<Report that this dimension is out of range@>; | |
--- | |
> are |x| sp per unit; |goto attach_sign| if the units are internal@>; | |
7272a8766,8768 | |
> attach_sign: if arith_error or(abs(cur_val)>=@'10000000000) then | |
> @<Report that this dimension is out of range@>; | |
> if negative then negate(cur_val); | |
7276,7280c8772,8780 | |
< begin if cur_cmd=register then back_input {implied `\.{\\the}'} | |
< else if cur_chr≠0 then negative ← ¬ negative; {handle `\.{\\minus}'} | |
< scan_the(dimen_val,false); | |
< if cur_val_level=dimen_val then goto attach_sign; | |
< end | |
--- | |
> if mu then | |
> begin scan_something_internal(mu_val,false); | |
> @<Coerce glue to a dimension@>; | |
> if cur_val_level=mu_val then goto attach_sign; | |
> if cur_val_level<>int_val then mu_error; | |
> end | |
> else begin scan_something_internal(dimen_val,false); | |
> if cur_val_level=dimen_val then goto attach_sign; | |
> end | |
7284,7285c8784,8785 | |
< @!k:small_number; {number of digits in a decimal fraction} | |
< @!j:small_number; {index into a box node} | |
--- | |
> @!k,@!kk:small_number; {number of digits in a decimal fraction} | |
> @!p,@!q:pointer; {top of decimal digit stack} | |
7287c8787,8796 | |
< @!save_cur_val:scaled; {temporary storage of |cur_val|} | |
--- | |
> @!save_cur_val:integer; {temporary storage of |cur_val|} | |
> | |
> @ The following code is executed when |scan_something_internal| was | |
> called asking for |mu_val|, when we really wanted a ``mudimen'' instead | |
> of ``muglue.'' | |
> | |
> @<Coerce glue to a dimension@>= | |
> if cur_val_level>=glue_val then | |
> begin v:=width(cur_val); delete_glue_ref(cur_val); cur_val:=v; | |
> end | |
7296,7303c8805,8817 | |
< begin k←0; get_token; {|point_token| is being re-scanned} | |
< loop@+ begin get_nc_token; | |
< if (cur_tok>zero_token+9)∨(cur_tok<zero_token) then goto done; | |
< if k<16 then {digits for |k≥16| cannot affect the result} | |
< begin dig[k]←cur_tok-zero_token; incr(k); | |
< end; | |
< end; | |
< done: f←round_decimals(k); back_input; | |
--- | |
> begin k:=0; p:=null; get_token; {|point_token| is being re-scanned} | |
> loop@+ begin get_x_token; | |
> if (cur_tok>zero_token+9)or(cur_tok<zero_token) then goto done1; | |
> if k<17 then {digits for |k>=17| cannot affect the result} | |
> begin q:=get_avail; link(q):=p; info(q):=cur_tok-zero_token; | |
> p:=q; incr(k); | |
> end; | |
> end; | |
> done1: for kk:=k downto 1 do | |
> begin dig[kk-1]:=info(p); q:=p; p:=link(p); free_avail(q); | |
> end; | |
> f:=round_decimals(k); | |
> if cur_cmd<>spacer then back_input; | |
7311,7312c8825 | |
< does not overflow. This section of the program is followed by the label | |
< |attach_sign|. | |
--- | |
> does not overflow. | |
7315,7318c8828,8831 | |
< if inf then @<Scan for \.{fil} units; |goto attach_fraction| if found@>; | |
< if mu then @<Scan for \.{mu} units and |goto attach_fraction|@>; | |
< @<Scan for units that are internal dimensions, | |
< and |goto attach_sign| if found@>; | |
--- | |
> if inf then @<Scan for \(f)\.{fil} units; |goto attach_fraction| if found@>; | |
> @<Scan for \(u)units that are internal dimensions; | |
> |goto attach_sign| with |cur_val| set if found@>; | |
> if mu then @<Scan for \(m)\.{mu} units and |goto attach_fraction|@>; | |
7319a8833 | |
> @.true@> | |
7321,7323c8835,8840 | |
< @<Scan for all other units and adjust |cur_val| and |f| accordingly@>; | |
< attach_fraction: if cur_val≥@'40000 then arith_error←true | |
< else cur_val←cur_val*unity+f | |
--- | |
> @.pt@> | |
> @<Scan for \(a)all other units and adjust |cur_val| and |f| accordingly; | |
> |goto done| in the case of scaled points@>; | |
> attach_fraction: if cur_val>=@'40000 then arith_error:=true | |
> else cur_val:=cur_val*unity+f; | |
> done: | |
7325c8842,8845 | |
< @ @<Scan for \.{fil} units...@>= | |
--- | |
> @ A specification like `\.{filllll}' or `\.{fill L L L}' will lead to two | |
> error messages (one for each additional keyword \.{"l"}). | |
> | |
> @<Scan for \(f)\.{fil} units...@>= | |
7327,7331c8847,8851 | |
< begin cur_order←fil; | |
< while scan_keyword("l") do | |
< begin if cur_order=filll then | |
< begin help1("I dddon't go any higher than filll."); | |
< print_nl("! Illegal unit of measure ("); | |
--- | |
> @.fil@> | |
> begin cur_order:=fil; | |
> while scan_keyword("l") do | |
> begin if cur_order=filll then | |
> begin print_err("Illegal unit of measure ("); | |
7333,7338c8853,8859 | |
< print("replaced by filll)"); error; | |
< end | |
< else incr(cur_order); | |
< end; | |
< goto attach_fraction; | |
< end | |
--- | |
> print("replaced by filll)"); | |
> help1("I dddon't go any higher than filll."); error; | |
> end | |
> else incr(cur_order); | |
> end; | |
> goto attach_fraction; | |
> end | |
7340,7360c8861,8876 | |
< @ @<Scan for \.{mu} units and |goto attach_fraction|@>= | |
< if scan_keyword("mu") then goto attach_fraction | |
< else begin print_nl("! Illegal unit of measure ("); print("mu inserted)"); | |
< @.Illegal unit of measure@> | |
< help4("The unit of measurement in \mskip glue must be mu.")@/ | |
< ("To recover gracefully from this error, it's best to")@/ | |
< ("delete the erroneous units; e.g., type `2' to delete")@/ | |
< ("two letters. (See Chapter 27 of the manual.)"); | |
< error; goto attach_fraction; | |
< end | |
< | |
< @ @d set_internal_dimen(#)==begin v←#; goto found; | |
< end | |
< | |
< @<Scan for units that are internal dimensions...@>= | |
< if scan_keyword("em") then set_internal_dimen(@<The em width for |cur_font|@>); | |
< if scan_keyword("ex") then set_internal_dimen(@<The x-height for |cur_font|@>); | |
< if scan_keyword("vu") then set_internal_dimen(var_unit); | |
< if scan_keyword("wd") then j←width_offset | |
< else if scan_keyword("dp") then j←depth_offset | |
< else if scan_keyword("ht") then j←height_offset | |
--- | |
> @ @<Scan for \(u)units that are internal dimensions...@>= | |
> save_cur_val:=cur_val; | |
> @<Get the next non-blank non-call...@>; | |
> if (cur_cmd<min_internal)or(cur_cmd>max_internal) then back_input | |
> else begin if mu then | |
> begin scan_something_internal(mu_val,false); @<Coerce glue...@>; | |
> if cur_val_level<>mu_val then mu_error; | |
> end | |
> else scan_something_internal(dimen_val,false); | |
> v:=cur_val; goto found; | |
> end; | |
> if mu then goto not_found; | |
> if scan_keyword("em") then v:=(@<The em width for |cur_font|@>) | |
> @.em@> | |
> else if scan_keyword("ex") then v:=(@<The x-height for |cur_font|@>) | |
> @.ex@> | |
7362,7365c8878,8879 | |
< save_cur_val←cur_val; scan_eight_bit_int; | |
< if box(cur_val)=null then v←0@+else v←mem[box(cur_val)+j].sc; | |
< cur_val←save_cur_val; | |
< found:cur_val←nx_plus_y(cur_val,v,xn_over_d(v,f,@'200000)); | |
--- | |
> @<Scan an optional space@>; | |
> found:cur_val:=nx_plus_y(save_cur_val,v,xn_over_d(v,f,@'200000)); | |
7369,7377c8883,8894 | |
< @ @<Adjust \(f)for the magnification ratio@>= | |
< begin @<Scan an optional space@>; | |
< prepare_mag; | |
< if mag≠1000 then | |
< begin cur_val←xn_over_d(cur_val,1000,mag); | |
< f←(1000*f+@'200000*remainder) div mag; | |
< cur_val←cur_val+(f div @'200000); f←f mod @'200000; | |
< end; | |
< end | |
--- | |
> @ @<Scan for \(m)\.{mu} units and |goto attach_fraction|@>= | |
> if scan_keyword("mu") then goto attach_fraction | |
> @.mu@> | |
> else begin print_err("Illegal unit of measure ("); print("mu inserted)"); | |
> @.Illegal unit of measure@> | |
> help4("The unit of measurement in math glue must be mu.")@/ | |
> ("To recover gracefully from this error, it's best to")@/ | |
> ("delete the erroneous units; e.g., type `2' to delete")@/ | |
> ("two letters. (See Chapter 27 of The TeXbook.)"); | |
> @:TeXbook}{\sl The \TeX book@> | |
> error; goto attach_fraction; | |
> end | |
7379,7380c8896,8910 | |
< @ All of the necessary conversion factors can be specified exactly as a | |
< fraction whose numerator and denominator are 65536 or less. | |
--- | |
> @ @<Adjust \(f)for the magnification ratio@>= | |
> begin prepare_mag; | |
> if mag<>1000 then | |
> begin cur_val:=xn_over_d(cur_val,1000,mag); | |
> f:=(1000*f+@'200000*remainder) div mag; | |
> cur_val:=cur_val+(f div @'200000); f:=f mod @'200000; | |
> end; | |
> end | |
> | |
> @ The necessary conversion factors can all be specified exactly as | |
> fractions whose numerator and denominator sum to 32768 or less. | |
> According to the definitions here, $\rm2660\,dd\approx1000.33297\,mm$; | |
> this agrees well with the value $\rm1000.333\,mm$ cited by Bosshard | |
> @^Bosshard, Hans Rudolf@> | |
> in {\sl Technische Grundlagen zur Satzherstellung\/} (Bern, 1980). | |
7382,7383c8912,8913 | |
< @d set_conversion_end(#)== denom←#; end | |
< @d set_conversion(#)==@+begin num←#; set_conversion_end | |
--- | |
> @d set_conversion_end(#)== denom:=#; end | |
> @d set_conversion(#)==@+begin num:=#; set_conversion_end | |
7385c8915 | |
< @<Scan for all other units and adjust |cur_val| and |f| accordingly@>= | |
--- | |
> @<Scan for \(a)all other units and adjust |cur_val| and |f|...@>= | |
7386a8917 | |
> @.in@> | |
7387a8919 | |
> @.pc@> | |
7388a8921 | |
> @.cm@> | |
7389a8923 | |
> @.mm@> | |
7391,7397c8925,8936 | |
< else if scan_keyword("dd") then set_conversion(215)(201) | |
< else if scan_keyword("cc") then set_conversion(2580)(201) | |
< else if scan_keyword("sp") then goto attach_sign | |
< else @<Complain about unknown unit and |goto attach_fraction|@>; | |
< cur_val←xn_over_d(cur_val,num,denom); | |
< f←(num*f+@'200000*remainder) div denom;@/ | |
< cur_val←cur_val+(f div @'200000); f←f mod @'200000 | |
--- | |
> @.bp@> | |
> else if scan_keyword("dd") then set_conversion(1238)(1157) | |
> @.dd@> | |
> else if scan_keyword("cc") then set_conversion(14856)(1157) | |
> @.cc@> | |
> else if scan_keyword("sp") then goto done | |
> @.sp@> | |
> else @<Complain about unknown unit and |goto done2|@>; | |
> cur_val:=xn_over_d(cur_val,num,denom); | |
> f:=(num*f+@'200000*remainder) div denom;@/ | |
> cur_val:=cur_val+(f div @'200000); f:=f mod @'200000; | |
> done2: | |
7400c8939 | |
< begin print_nl("! Illegal unit of measure ("); print("pt inserted)"); | |
--- | |
> begin print_err("Illegal unit of measure ("); print("pt inserted)"); | |
7402,7408c8941,8948 | |
< help6("Dimensions can be in units of em, ex, vu, wd, dp, ht, in,")@/ | |
< ("pt, pc, cm, mm, bp, dd, cc, or sp, but yours is a new one.")@/ | |
< ("I'll assume that you meant to say pt, for printers' points.")@/ | |
< ("To recover gracefully from this error, it's best to")@/ | |
< ("delete the erroneous units; e.g., type `2' to delete")@/ | |
< ("two letters. (See Chapter 27 of the manual.)"); | |
< error; goto attach_fraction; | |
--- | |
> help6("Dimensions can be in units of em, ex, in, pt, pc,")@/ | |
> ("cm, mm, dd, cc, bp, or sp; but yours is a new one!")@/ | |
> ("I'll assume that you meant to say pt, for printer's points.")@/ | |
> ("To recover gracefully from this error, it's best to")@/ | |
> ("delete the erroneous units; e.g., type `2' to delete")@/ | |
> ("two letters. (See Chapter 27 of The TeXbook.)"); | |
> @:TeXbook}{\sl The \TeX book@> | |
> error; goto done2; | |
7411d8950 | |
< @ @d max_dimen==@'7777777777 {$2^{30}-1$} | |
7413,7414c8952,8953 | |
< @<Report that this dimension is out of range@>= | |
< begin print_nl("! Dimension too large"); | |
--- | |
> @ @<Report that this dimension is out of range@>= | |
> begin print_err("Dimension too large"); | |
7417,7418c8956,8957 | |
< ("Continue and I'll use the largest value I can.");@/ | |
< error; cur_val←max_dimen; | |
--- | |
> ("Continue and I'll use the largest value I can.");@/ | |
> error; cur_val:=max_dimen; arith_error:=false; | |
7423c8962 | |
< glue spec will take account of the fact that |cur_val| is pointing to it. | |
--- | |
> glue spec will take account of the fact that |cur_val| is pointing to~it. | |
7425,7426c8964 | |
< As before, the |mu| parameter is |true| if the glue is supposed to be | |
< an \.{\\mskip}. | |
--- | |
> The |level| parameter should be either |glue_val| or |mu_val|. | |
7430c8968 | |
< most of the work has already been done for us. | |
--- | |
> most of the work has already been done. | |
7432c8970,8971 | |
< @p procedure scan_glue(@!mu:boolean); {sets |cur_val| to a glue spec pointer} | |
--- | |
> @p procedure scan_glue(@!level:small_number); | |
> {sets |cur_val| to a glue spec pointer} | |
7436,7445c8975,8988 | |
< begin @<Get the next non-blank non-sign...@>; | |
< if (cur_cmd=the)∨(cur_cmd=register) then | |
< begin if cur_cmd=register then back_input {implied `\.{\\the}'} | |
< else if cur_chr≠0 then negative ← ¬ negative; {handle `\.{\\minus}'} | |
< scan_the(glue_val,negative); negative←false; | |
< if cur_val_level=glue_val then return; | |
< if cur_val_level=int_val then scan_dimen(mu,false,true); | |
< end | |
< else begin back_input; scan_dimen(mu,false,false); | |
< end; | |
--- | |
> @!mu:boolean; {does |level=mu_val|?} | |
> begin mu:=(level=mu_val); @<Get the next non-blank non-sign...@>; | |
> if (cur_cmd>=min_internal)and(cur_cmd<=max_internal) then | |
> begin scan_something_internal(level,negative); | |
> if cur_val_level>=glue_val then | |
> begin if cur_val_level<>level then mu_error; | |
> return; | |
> end; | |
> if cur_val_level=int_val then scan_dimen(mu,false,true) | |
> else if level=mu_val then mu_error; | |
> end | |
> else begin back_input; scan_dimen(mu,false,false); | |
> if negative then negate(cur_val); | |
> end; | |
7447,7448c8990 | |
< stretch and shrink components@>; | |
< if negative then @<Negate all three glue components of |cur_val|@>; | |
--- | |
> stretch and shrink components@>; | |
7452c8994 | |
< q←new_spec(zero_glue); width(q)←cur_val; | |
--- | |
> q:=new_spec(zero_glue); width(q):=cur_val; | |
7454,7456c8996,8999 | |
< begin scan_dimen(mu,true,false); | |
< stretch(q)←cur_val; stretch_order(q)←cur_order; | |
< end; | |
--- | |
> @.plus@> | |
> begin scan_dimen(mu,true,false); | |
> stretch(q):=cur_val; stretch_order(q):=cur_order; | |
> end; | |
7458,7467c9001,9005 | |
< begin scan_dimen(mu,true,false); | |
< shrink(q)←cur_val; shrink_order(q)←cur_order; | |
< end; | |
< cur_val←q | |
< | |
< @ @<Negate all three...@>= | |
< begin width(cur_val)←-width(cur_val); | |
< stretch(cur_val)←-stretch(cur_val); | |
< shrink(cur_val)←-shrink(cur_val); | |
< end | |
--- | |
> @.minus@> | |
> begin scan_dimen(mu,true,false); | |
> shrink(q):=cur_val; shrink_order(q):=cur_order; | |
> end; | |
> cur_val:=q | |
7476c9014 | |
< @d default_rule=26215 {.40001 pt} | |
--- | |
> @d default_rule=26214 {0.4\thinspace pt} | |
7481,7484c9019,9022 | |
< begin q←new_rule; {|width|, |depth|, and |height| all equal |null_flag| now} | |
< if cur_cmd=vrule then width(q)←default_rule | |
< else begin height(q)←default_rule; depth(q)←0; | |
< end; | |
--- | |
> begin q:=new_rule; {|width|, |depth|, and |height| all equal |null_flag| now} | |
> if cur_cmd=vrule then width(q):=default_rule | |
> else begin height(q):=default_rule; depth(q):=0; | |
> end; | |
7486,7487c9024,9026 | |
< begin scan_dimen(false,false,false); width(q)←cur_val; goto reswitch; | |
< end; | |
--- | |
> @.width@> | |
> begin scan_normal_dimen; width(q):=cur_val; goto reswitch; | |
> end; | |
7489,7490c9028,9030 | |
< begin scan_dimen(false,false,false); height(q)←cur_val; goto reswitch; | |
< end; | |
--- | |
> @.height@> | |
> begin scan_normal_dimen; height(q):=cur_val; goto reswitch; | |
> end; | |
7492,7494c9032,9035 | |
< begin scan_dimen(false,false,false); depth(q)←cur_val; goto reswitch; | |
< end; | |
< scan_rule_spec←q; | |
--- | |
> @.depth@> | |
> begin scan_normal_dimen; depth(q):=cur_val; goto reswitch; | |
> end; | |
> scan_rule_spec:=q; | |
7495a9037 | |
> | |
7498,7506c9040 | |
< and \.{\\send} are produced by a procedure called |scan_toks|. | |
< | |
< Before we get into the details of |scan_toks|, let's consider a much simpler | |
< task, that of converting the current string into a token list. The |str_toks| | |
< function does this; it classifies spaces as type |spacer|, characters |≥"a"| | |
< as type |letter|, and everything else as type |other_char|. (These | |
< three categories are sufficient, since |str_toks| is used only with the | |
< special strings that can occur when \.{\\the} or \.{\\number} constructions | |
< are being expanded.) | |
--- | |
> and \.{\\write} are produced by a procedure called |scan_toks|. | |
7507a9042,9045 | |
> Before we get into the details of |scan_toks|, let's consider a much | |
> simpler task, that of converting the current string into a token list. | |
> The |str_toks| function does this; it classifies spaces as type |spacer| | |
> and everything else as type |other_char|. | |
7512c9050,9051 | |
< @p function str_toks:pointer; {changes the current string to a token list} | |
--- | |
> @p function str_toks(@!b:pool_pointer):pointer; | |
> {changes the string |str_pool[b..pool_ptr]| to a token list} | |
7518c9057 | |
< p←temp_head; link(p)←null; k←str_start[str_ptr]; | |
--- | |
> p:=temp_head; link(p):=null; k:=b; | |
7520,7527c9059,9065 | |
< begin t←str_pool[k]; | |
< if t=" " then t←space_token | |
< else if t≥"a" then t←letter_token+t | |
< else t←other_token+t; | |
< store_new_token(t); | |
< incr(k); | |
< end; | |
< pool_ptr←str_start[str_ptr]; str_toks←p; | |
--- | |
> begin t:=so(str_pool[k]); | |
> if t=" " then t:=space_token | |
> else t:=other_token+t; | |
> fast_store_new_token(t); | |
> incr(k); | |
> end; | |
> pool_ptr:=b; str_toks:=p; | |
7531a9070 | |
> | |
7533,7535c9072,9073 | |
< i.e., whatever can follow `\.{\\the}' or `\.{\\minus}', and it | |
< constructs a token list containing something like `\.{-3.0pt | |
< minus 0.5fill}'. | |
--- | |
> i.e., whatever can follow `\.{\\the}', and it constructs a token list | |
> containing something like `\.{-3.0pt minus 0.5fill}'. | |
7537c9075 | |
< @p function the_toks(@!negative:boolean):pointer; | |
--- | |
> @p function the_toks:pointer; | |
7540,7553c9078,9092 | |
< begin scan_the(tok_val,negative); | |
< if cur_val_level=tok_val then @<Copy the token list@> | |
< else begin old_setting←selector; selector←new_string; | |
< case cur_val_level of | |
< int_val:print_int(cur_val); | |
< dimen_val:begin print_scaled(cur_val); print("pt"); | |
< end; | |
< glue_val: begin print_spec(cur_val,"pt"); delete_glue_ref(cur_val); | |
< end; | |
< mu_val: begin print_spec(cur_val,"mu"); delete_glue_ref(cur_val); | |
< end; | |
< end; {there are no other cases} | |
< selector←old_setting; the_toks←str_toks; | |
< end; | |
--- | |
> @!b:pool_pointer; {base of temporary string} | |
> begin get_x_token; scan_something_internal(tok_val,false); | |
> if cur_val_level>=ident_val then @<Copy the token list@> | |
> else begin old_setting:=selector; selector:=new_string; b:=pool_ptr; | |
> case cur_val_level of | |
> int_val:print_int(cur_val); | |
> dimen_val:begin print_scaled(cur_val); print("pt"); | |
> end; | |
> glue_val: begin print_spec(cur_val,"pt"); delete_glue_ref(cur_val); | |
> end; | |
> mu_val: begin print_spec(cur_val,"mu"); delete_glue_ref(cur_val); | |
> end; | |
> end; {there are no other cases} | |
> selector:=old_setting; the_toks:=str_toks(b); | |
> end; | |
7557,7562c9096,9135 | |
< begin r←link(cur_val); p←temp_head; link(p)←null; | |
< while r≠null do | |
< begin store_new_token(info(r)); r←link(r); | |
< end; | |
< the_toks←p; | |
< end | |
--- | |
> begin p:=temp_head; link(p):=null; | |
> if cur_val_level=ident_val then store_new_token(cs_token_flag+cur_val) | |
> else if cur_val<>null then | |
> begin r:=link(cur_val); {do not copy the reference count} | |
> while r<>null do | |
> begin fast_store_new_token(info(r)); r:=link(r); | |
> end; | |
> end; | |
> the_toks:=p; | |
> end | |
> | |
> @ Here's part of the |expand| subroutine that we are now ready to complete: | |
> | |
> @p procedure ins_the_toks; | |
> begin link(garbage):=the_toks; ins_list(link(temp_head)); | |
> end; | |
> | |
> @ The primitives \.{\\number}, \.{\\romannumeral}, \.{\\string}, \.{\\meaning}, | |
> \.{\\fontname}, and \.{\\jobname} are defined as follows. | |
> | |
> @d number_code=0 {command code for \.{\\number}} | |
> @d roman_numeral_code=1 {command code for \.{\\romannumeral}} | |
> @d string_code=2 {command code for \.{\\string}} | |
> @d meaning_code=3 {command code for \.{\\meaning}} | |
> @d font_name_code=4 {command code for \.{\\fontname}} | |
> @d job_name_code=5 {command code for \.{\\jobname}} | |
> | |
> @<Put each...@>= | |
> primitive("number",convert,number_code);@/ | |
> @!@:number_}{\.{\\number} primitive@> | |
> primitive("romannumeral",convert,roman_numeral_code);@/ | |
> @!@:roman_numeral_}{\.{\\romannumeral} primitive@> | |
> primitive("string",convert,string_code);@/ | |
> @!@:string_}{\.{\\string} primitive@> | |
> primitive("meaning",convert,meaning_code);@/ | |
> @!@:meaning_}{\.{\\meaning} primitive@> | |
> primitive("fontname",convert,font_name_code);@/ | |
> @!@:font_name_}{\.{\\fontname} primitive@> | |
> primitive("jobname",convert,job_name_code);@/ | |
> @!@:job_name_}{\.{\\jobname} primitive@> | |
7564,7565c9137,9149 | |
< @ Similarly, we have |num_toks|, which prepares the token list | |
< following `\.{\\number}': | |
--- | |
> @ @<Cases of |print_cmd_chr|...@>= | |
> convert: case chr_code of | |
> number_code: print_esc("number"); | |
> roman_numeral_code: print_esc("romannumeral"); | |
> string_code: print_esc("string"); | |
> meaning_code: print_esc("meaning"); | |
> font_name_code: print_esc("fontname"); | |
> othercases print_esc("jobname") | |
> endcases; | |
> | |
> @ The procedure |conv_toks| uses |str_toks| to insert the token list | |
> for |convert| functions into the scanner; `\.{\\outer}' control sequences | |
> are allowed to follow `\.{\\string}' and `\.{\\meaning}'. | |
7567c9151 | |
< @p function num_toks:pointer; | |
--- | |
> @p procedure conv_toks; | |
7569,7572c9153,9159 | |
< begin old_setting←selector; | |
< scan_the(int_val,false); selector←new_string; | |
< if cur_val≥0 then print_int(cur_val)@+else print_roman_int(-cur_val); | |
< selector←old_setting; num_toks←str_toks; | |
--- | |
> @!c:number_code..job_name_code; {desired type of conversion} | |
> @!save_scanner_status:small_number; {|scanner_status| upon entry} | |
> @!b:pool_pointer; {base of temporary string} | |
> begin c:=cur_chr; @<Scan the argument for command |c|@>; | |
> old_setting:=selector; selector:=new_string; b:=pool_ptr; | |
> @<Print the result of command |c|@>; | |
> selector:=old_setting; link(garbage):=str_toks(b); ins_list(link(temp_head)); | |
7574a9162,9187 | |
> @ @<Scan the argument for command |c|@>= | |
> case c of | |
> number_code,roman_numeral_code: scan_int; | |
> string_code, meaning_code: begin save_scanner_status:=scanner_status; | |
> scanner_status:=normal; get_token; scanner_status:=save_scanner_status; | |
> end; | |
> font_name_code: scan_font_ident; | |
> job_name_code: if job_name=0 then open_log_file; | |
> end {there are no other cases} | |
> | |
> @ @<Print the result of command |c|@>= | |
> case c of | |
> number_code: print_int(cur_val); | |
> roman_numeral_code: print_roman_int(cur_val); | |
> string_code:if cur_cs<>0 then sprint_cs(cur_cs) | |
> else print_char(cur_chr); | |
> meaning_code: print_meaning; | |
> font_name_code: begin print(font_name[cur_val]); | |
> if font_size[cur_val]<>font_dsize[cur_val] then | |
> begin print(" at "); print_scaled(font_size[cur_val]); | |
> print("pt"); | |
> end; | |
> end; | |
> job_name_code: print(job_name); | |
> end {there are no other cases} | |
> | |
7577,7578c9190,9191 | |
< list, and it also makes |cur_val| point to the reference count at the head | |
< of that list. | |
--- | |
> list, and it also makes |def_ref| point to the reference count at the | |
> head of that list. | |
7584,7585c9197,9198 | |
< \.{\\uppercase}, \.{\\message}, \.{\\errmessage}, \.{\\send}, or | |
< \.{\\xsend}. In the latter cases a left brace must be scanned next; this | |
--- | |
> \.{\\uppercase}, \.{\\message}, \.{\\errmessage}, \.{\\write}, or | |
> \.{\\special}. In the latter cases a left brace must be scanned next; this | |
7588,7593c9201,9206 | |
< simply be copied from the input using |get_token|. Otherwise all macros | |
< and occurrences of `\.{\\the}' and `\.{\\minus}' and `\.{\\number}' will | |
< be expanded, unless they are preceded by some control sequence like | |
< `\.{\\def}' whose command code is |def|. If both |macro_def| and |xpand| | |
< are true, the expansion applies only to the macro body (i.e., to the | |
< material following the first |left_brace| character). | |
--- | |
> simply be copied from the input using |get_token|. Otherwise all expandable | |
> tokens will be expanded until unexpandable tokens are left, except that | |
> the results of expanding `\.{\\the}' are not expanded further. | |
> If both |macro_def| and |xpand| are true, the expansion applies | |
> only to the macro body (i.e., to the material following the first | |
> |left_brace| character). | |
7595c9208 | |
< The value of |cs_ptr| when |scan_toks| begins should be the |eqtb| | |
--- | |
> The value of |cur_cs| when |scan_toks| begins should be the |eqtb| | |
7599,7600d9211 | |
< After the closing right brace, this routine will remove a space. % (rhymes) | |
< | |
7603,7604c9214 | |
< var r: pointer; {reference count location} | |
< @!t:halfword; {token representing the highest parameter number} | |
--- | |
> var t:halfword; {token representing the highest parameter number} | |
7610,7611c9220,9223 | |
< begin scanner_status←defining; warning_index←cs_ptr; r←get_avail; info(r)←0; | |
< p←r; hash_brace←0; | |
--- | |
> begin if macro_def then scanner_status:=defining | |
> @+else scanner_status:=absorbing; | |
> warning_index:=cur_cs; def_ref:=get_avail; token_ref_count(def_ref):=null; | |
> p:=def_ref; hash_brace:=0; t:=zero_token; | |
7615,7617c9227,9229 | |
< found: scanner_status←normal; @<Scan an optional space@>; | |
< if hash_brace≠0 then store_new_token(hash_brace); | |
< cur_val←r; scan_toks←p; | |
--- | |
> found: scanner_status:=normal; | |
> if hash_brace<>0 then store_new_token(hash_brace); | |
> scan_toks:=p; | |
7621,7629c9233,9240 | |
< begin t←zero_token; {this represents |"0"|} | |
< loop@+ begin get_token; {set |cur_cmd|, |cur_chr|, |cur_tok|} | |
< if cur_cmd≤right_brace then goto done1; | |
< if cur_cmd=mac_param then | |
< @<If the next character is a parameter number, make |cur_tok| | |
< a |match| token; but if it is a left brace, store | |
< `|left_brace|, |end_match|' and |goto done|@>; | |
< store_new_token(cur_tok); | |
< end; | |
--- | |
> begin loop begin get_token; {set |cur_cmd|, |cur_chr|, |cur_tok|} | |
> if cur_tok<right_brace_limit then goto done1; | |
> if cur_cmd=mac_param then | |
> @<If the next character is a parameter number, make |cur_tok| | |
> a |match| token; but if it is a left brace, store | |
> `|left_brace|, |end_match|', set |hash_brace|, and |goto done|@>; | |
> store_new_token(cur_tok); | |
> end; | |
7632c9243 | |
< @<Express shock at the missing left brace; |goto found|@>; | |
--- | |
> @<Express shock at the missing left brace; |goto found|@>; | |
7636,7637c9247,9248 | |
< begin print_nl("! Missing { inserted"); incr(align_state); | |
< @.Missing {\{} inserted@> | |
--- | |
> begin print_err("Missing { inserted"); incr(align_state); | |
> @.Missing \{ inserted@> | |
7639c9250 | |
< ("which I'm going to interpret as `\def\a{}'."); error; goto found; | |
--- | |
> ("which I'm going to interpret as `\def\a{}'."); error; goto found; | |
7643c9254 | |
< begin s←match_token+cur_chr; get_token; | |
--- | |
> begin s:=match_token+cur_chr; get_token; | |
7645,7647c9256,9259 | |
< begin store_new_token(cur_tok); store_new_token(end_match_token); | |
< goto done; | |
< end; | |
--- | |
> begin hash_brace:=cur_tok; | |
> store_new_token(cur_tok); store_new_token(end_match_token); | |
> goto done; | |
> end; | |
7649c9261 | |
< begin print_nl("! You already have nine parameters"); | |
--- | |
> begin print_err("You already have nine parameters"); | |
7651,7655c9263,9267 | |
< help1("I'm going to ignore the # sign you just used."); error; | |
< end | |
< else begin incr(t); | |
< if cur_tok≠t then | |
< begin print_nl("! Parameters must be numbered consecutively"); | |
--- | |
> help1("I'm going to ignore the # sign you just used."); error; | |
> end | |
> else begin incr(t); | |
> if cur_tok<>t then | |
> begin print_err("Parameters must be numbered consecutively"); | |
7657,7661c9269,9273 | |
< help2("I've inserted the digit you should have used after the #.")@/ | |
< ("Type `1' to delete what you did use."); back_error; | |
< end; | |
< cur_tok←s; | |
< end; | |
--- | |
> help2("I've inserted the digit you should have used after the #.")@/ | |
> ("Type `1' to delete what you did use."); back_error; | |
> end; | |
> cur_tok:=s; | |
> end; | |
7665,7685c9277,9303 | |
< unbalance←1; | |
< loop@+ begin if xpand ∧(cur_cmd≠def) then | |
< @<Expand the next part of the input@> | |
< else get_token; | |
< if cur_cmd≤right_brace then | |
< if cur_cmd<right_brace then incr(unbalance) | |
< else begin decr(unbalance); | |
< if unbalance=0 then goto found; | |
< end | |
< else if cur_cmd=mac_param then @<Look for parameter number or \.{\#\#}@>; | |
< store_new_token(cur_tok); | |
< end | |
< | |
< @ @<Expand the next part of the input@>= | |
< begin loop begin get_nc_token; | |
< if cur_cmd=the then q←the_toks(cur_chr>0) | |
< else if cur_cmd=number then q←num_toks | |
< else goto done2; | |
< link(p)←link(temp_head); p←q; | |
< end; | |
< done2: | |
--- | |
> unbalance:=1; | |
> loop@+ begin if xpand then @<Expand the next part of the input@> | |
> else get_token; | |
> if cur_tok<right_brace_limit then | |
> if cur_cmd<right_brace then incr(unbalance) | |
> else begin decr(unbalance); | |
> if unbalance=0 then goto found; | |
> end | |
> else if cur_cmd=mac_param then | |
> if macro_def then @<Look for parameter number or \.{\#\#}@>; | |
> store_new_token(cur_tok); | |
> end | |
> | |
> @ Here we insert an entire token list created by |the_toks| without | |
> expanding it further. | |
> | |
> @<Expand the next part of the input@>= | |
> begin loop begin get_next; | |
> if cur_cmd<=max_command then goto done2; | |
> if cur_cmd<>the then expand | |
> else begin q:=the_toks; | |
> if link(temp_head)<>null then | |
> begin link(p):=link(temp_head); p:=q; | |
> end; | |
> end; | |
> end; | |
> done2: x_token | |
7689,7692c9307,9311 | |
< begin s←cur_tok; get_token; | |
< if cur_cmd≠mac_param then | |
< if (cur_chr<"1")∨(cur_chr>t-zero_token+"0")∨@|(cur_cmd≠other_char) then | |
< begin print_nl("! Illegal parameter number in definition of "); | |
--- | |
> begin s:=cur_tok; | |
> if xpand then get_x_token else get_token; | |
> if cur_cmd<>mac_param then | |
> if (cur_tok<=zero_token)or(cur_tok>t) then | |
> begin print_err("Illegal parameter number in definition of "); | |
7694,7709c9313,9327 | |
< sprint_cs(warning_index); | |
< help3("You meant to type ## instead of #, right?")@/ | |
< ("Or maybe a } was forgotten somewhere earlier, and things")@/ | |
< ("are all screwed up? I'm going to assume you meant ##."); | |
< back_error; cur_tok←s; | |
< end | |
< else cur_tok←out_param_token-"0"+cur_chr; | |
< end | |
< @* \[28] 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. The following programs show what is required for one particular | |
< operating system; similar routines for other systems are not difficult | |
< to devise. | |
< @^fingers@> | |
< @^system dependencies@> | |
--- | |
> sprint_cs(warning_index); | |
> help3("You meant to type ## instead of #, right?")@/ | |
> ("Or maybe a } was forgotten somewhere earlier, and things")@/ | |
> ("are all screwed up? I'm going to assume that you meant ##."); | |
> back_error; cur_tok:=s; | |
> end | |
> else cur_tok:=out_param_token-"0"+cur_chr; | |
> end | |
> | |
> @ Another way to create a token list is via the \.{\\read} command. The | |
> sixteen files potentially usable for reading appear in the following | |
> global variables. The value of |read_open[n]| will be |closed| if | |
> stream number |n| has not been opened or if it has been fully read; | |
> |just_open| if an \.{\\openin} but not a \.{\\read} has been done; | |
> and |normal| if it is open and ready to read the next line. | |
7711,7723c9329,9330 | |
< \TeX\ assumes that a file name has three parts: the name proper, its | |
< ``exten\-sion'', and a ``file area'' where it is found in an external file | |
< system. The extension of an input file or a send file is assumed to be | |
< `\.{.tex}' unless otherwise specified; it is `\.{.err}' on the error | |
< transcript file that records each run of \TeX; it is `\.{.tfm}' on the font | |
< metric files that describe characters in the fonts \TeX\ uses; it is | |
< `\.{.dvi}' on the output files that specify typesetting information; and it | |
< is `\.{.fmt}' on the format files written by \.{INITEX} to initialize \TeX. | |
< The file area can be arbitrary on input files, but it is usually the | |
< user's current area when a file is output. If an input file cannot be | |
< found on the specified area, \TeX\ will look for it on a special system | |
< area; this special area is intended for commonly used input files like | |
< \.{webhdr.tex}. | |
--- | |
> @d closed=2 {not open, or at end of file} | |
> @d just_open=1 {newly opened, first line not yet read} | |
7725,7734c9332,9334 | |
< Simple uses of \TeX\ refer only to file names that have no explicit extension | |
< or area. For example, one usually says `\.{\\input paper}' or | |
< `\.{\\font100=helvetica}' instead of `\.{\\input paper.new}' or | |
< `\.{\\font100=<csd.knuth>test}'. Simple file names are best, because they | |
< make the \TeX\ source files portable; whenever a file name consists entirely | |
< of letters and digits, it should be treated in the same way by all | |
< implementations of \TeX. However, users need the ability to refer to other | |
< files in their environment, especially when responding to error messages | |
< concerning unopenable files; therefore we want to let them use the syntax | |
< that appears in their favorite operating system. | |
--- | |
> @<Glob...@>= | |
> @!read_file:array[0..15] of alpha_file; {used for \.{\\read}} | |
> @!read_open:array[0..16] of normal..closed; {state of |read_file[n]|} | |
7736,7748c9336,9337 | |
< @ In order to isolate the system-dependent aspects of file names, the | |
< @^system dependencies@> | |
< system-independent parts of \TeX\ make use of three system-dependent | |
< procedures that are called |begin_name|, |more_name|, and |end_name|. In | |
< essence, if the user-specified characters of the file name are $c↓1\ldotsm c↓n$, | |
< the system-independent driver program does the operations | |
< $$|begin_name|;\,|more_name|(c↓1);\ldotss;|more_name|(c↓n); | |
< \,|end_name|.$$ | |
< These three procedures communicate with each other via global variables. | |
< After\-wards 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. | |
--- | |
> @ @<Set init...@>= | |
> for k:=0 to 16 do read_open[k]:=closed; | |
7750,7759c9339,9341 | |
< Actually the situation is slightly more complicated, because \TeX\ needs | |
< to know when the file name ends. The |more_name| routine is a function | |
< (with side effects) that returns |true| on the calls |more_name|$(c↓1)$, | |
< $\ldotss$, |more_name|$(c↓{n-1})$. The final call |more_name|$(c↓n)$ | |
< returns |false|; or, it returns |true| and the token following $c↓n$ is | |
< something like `\.{\\hbox}' (i.e., not a character). In other words, | |
< |more_name| is supposed to return |true| unless it is sure that the | |
< file name has been completely scanned; and |end_name| is supposed to be able | |
< to finish the assembly of |cur_name|, |cur_area|, and |cur_ext| regardless of | |
< whether $|more_name|(c↓n)$ returned |true| or |false|. | |
--- | |
> @ The |read_toks| procedure constructs a token list like that for any | |
> macro definition, and makes |cur_val| point to it. Parameter |r| points | |
> to the control sequence that will receive this token list. | |
7761,7764c9343,9391 | |
< @<Glob...@>= | |
< @!cur_name:str_number; {name of file just scanned} | |
< @!cur_area:str_number; {file area just scanned, or \.{""}} | |
< @!cur_ext:str_number; {file extension just scanned, or \.{""}} | |
--- | |
> @p procedure read_toks(@!n:integer;@!r:pointer); | |
> label done; | |
> var p:pointer; {tail of the token list} | |
> @!q:pointer; {new node being added to the token list via |store_new_token|} | |
> @!s:integer; {saved value of |align_state|} | |
> @!m:small_number; {stream number} | |
> begin scanner_status:=defining; warning_index:=r; | |
> def_ref:=get_avail; token_ref_count(def_ref):=null; | |
> p:=def_ref; {the reference count} | |
> store_new_token(end_match_token); | |
> if (n<0)or(n>15) then m:=16@+else m:=n; | |
> s:=align_state; align_state:=1000000; {disable tab marks, etc.} | |
> repeat @<Input and store tokens from the next line of the file@>; | |
> until align_state=1000000; | |
> cur_val:=def_ref; scanner_status:=normal; align_state:=s; | |
> end; | |
> | |
> @ @<Input and store tokens from the next line of the file@>= | |
> begin_file_reading; name:=m+1; | |
> if read_open[m]=closed then @<Input for \.{\\read} from the terminal@> | |
> else if read_open[m]=just_open then @<Input the first line of |read_file[m]|@> | |
> else @<Input the next line of |read_file[m]|@>; | |
> limit:=last; | |
> if end_line_char_inactive then decr(limit) | |
> else buffer[limit]:=end_line_char; | |
> first:=limit+1; loc:=start; state:=new_line;@/ | |
> loop@+ begin get_token; | |
> if cur_tok=0 then goto done; | |
> {|cur_cmd=cur_chr=0| will occur at the end of the line} | |
> if align_state<1000000 then {unmatched `\.\}' aborts the line} | |
> begin repeat get_token; until cur_tok=0; | |
> align_state:=1000000; goto done; | |
> end; | |
> store_new_token(cur_tok); | |
> end; | |
> done: end_file_reading | |
> | |
> @ Here we input on-line into the |buffer| array, prompting the user explicitly | |
> if |n>=0|. The value of |n| is set negative so that additional prompts | |
> will not be given in the case of multi-line input. | |
> | |
> @<Input for \.{\\read} from the terminal@>= | |
> if interaction>nonstop_mode then | |
> if n<0 then prompt_input("") | |
> else begin wake_up_terminal; | |
> print_ln; sprint_cs(r); prompt_input("="); n:=-1; | |
> end | |
> else fatal_error("*** (cannot \read from terminal in nonstop modes)") | |
> @.cannot \\read@> | |
7766,7771c9393,9394 | |
< @ The file names we shall deal with 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 `\..' to the end, otherwise the file extension | |
< is null. | |
--- | |
> @ The first line of a file must be treated specially, since |input_ln| | |
> must be told not to start with |get|. | |
7774,7775c9397,9416 | |
< We can scan such file names easily by using two global variables that keep track | |
< of the occurrences of area and extension delimiters: | |
--- | |
> @<Input the first line of |read_file[m]|@>= | |
> if input_ln(read_file[m],false) then read_open[m]:=normal | |
> else begin a_close(read_file[m]); read_open[m]:=closed; | |
> end | |
> | |
> @ An empty line is appended at the end of a |read_file|. | |
> @^empty line at end of file@> | |
> | |
> @<Input the next line of |read_file[m]|@>= | |
> begin if not input_ln(read_file[m],true) then | |
> begin a_close(read_file[m]); read_open[m]:=closed; | |
> if align_state<>1000000 then | |
> begin runaway; | |
> print_err("File ended within "); print_esc("read"); | |
> @.File ended within \\read@> | |
> help1("This \read has unbalanced braces."); | |
> align_state:=1000000; error; | |
> end; | |
> end; | |
> end | |
7777,7778c9418,9890 | |
< @<Glob...@>= | |
< @!area_delimiter:pool_pointer; {the most recent `\.>' or `\.:', if any} | |
--- | |
> @* \[28] Conditional processing. | |
> We consider now the way \TeX\ handles various kinds of \.{\\if} commands. | |
> | |
> @d if_char_code=0 { `\.{\\if}' } | |
> @d if_cat_code=1 { `\.{\\ifcat}' } | |
> @d if_int_code=2 { `\.{\\ifnum}' } | |
> @d if_dim_code=3 { `\.{\\ifdim}' } | |
> @d if_odd_code=4 { `\.{\\ifodd}' } | |
> @d if_vmode_code=5 { `\.{\\ifvmode}' } | |
> @d if_hmode_code=6 { `\.{\\ifhmode}' } | |
> @d if_mmode_code=7 { `\.{\\ifmmode}' } | |
> @d if_inner_code=8 { `\.{\\ifinner}' } | |
> @d if_void_code=9 { `\.{\\ifvoid}' } | |
> @d if_hbox_code=10 { `\.{\\ifhbox}' } | |
> @d if_vbox_code=11 { `\.{\\ifvbox}' } | |
> @d ifx_code=12 { `\.{\\ifx}' } | |
> @d if_eof_code=13 { `\.{\\ifeof}' } | |
> @d if_true_code=14 { `\.{\\iftrue}' } | |
> @d if_false_code=15 { `\.{\\iffalse}' } | |
> @d if_case_code=16 { `\.{\\ifcase}' } | |
> | |
> @<Put each...@>= | |
> primitive("if",if_test,if_char_code); | |
> @!@:if_char_}{\.{\\if} primitive@> | |
> primitive("ifcat",if_test,if_cat_code); | |
> @!@:if_cat_code_}{\.{\\ifcat} primitive@> | |
> primitive("ifnum",if_test,if_int_code); | |
> @!@:if_int_}{\.{\\ifnum} primitive@> | |
> primitive("ifdim",if_test,if_dim_code); | |
> @!@:if_dim_}{\.{\\ifdim} primitive@> | |
> primitive("ifodd",if_test,if_odd_code); | |
> @!@:if_odd_}{\.{\\ifodd} primitive@> | |
> primitive("ifvmode",if_test,if_vmode_code); | |
> @!@:if_vmode_}{\.{\\ifvmode} primitive@> | |
> primitive("ifhmode",if_test,if_hmode_code); | |
> @!@:if_hmode_}{\.{\\ifhmode} primitive@> | |
> primitive("ifmmode",if_test,if_mmode_code); | |
> @!@:if_mmode_}{\.{\\ifmmode} primitive@> | |
> primitive("ifinner",if_test,if_inner_code); | |
> @!@:if_inner_}{\.{\\ifinner} primitive@> | |
> primitive("ifvoid",if_test,if_void_code); | |
> @!@:if_void_}{\.{\\ifvoid} primitive@> | |
> primitive("ifhbox",if_test,if_hbox_code); | |
> @!@:if_hbox_}{\.{\\ifhbox} primitive@> | |
> primitive("ifvbox",if_test,if_vbox_code); | |
> @!@:if_vbox_}{\.{\\ifvbox} primitive@> | |
> primitive("ifx",if_test,ifx_code); | |
> @!@:ifx_}{\.{\\ifx} primitive@> | |
> primitive("ifeof",if_test,if_eof_code); | |
> @!@:if_eof_}{\.{\\ifeof} primitive@> | |
> primitive("iftrue",if_test,if_true_code); | |
> @!@:if_true_}{\.{\\iftrue} primitive@> | |
> primitive("iffalse",if_test,if_false_code); | |
> @!@:if_false_}{\.{\\iffalse} primitive@> | |
> primitive("ifcase",if_test,if_case_code); | |
> @!@:if_case_}{\.{\\ifcase} primitive@> | |
> | |
> @ @<Cases of |print_cmd_chr|...@>= | |
> if_test: case chr_code of | |
> if_cat_code:print_esc("ifcat"); | |
> if_int_code:print_esc("ifnum"); | |
> if_dim_code:print_esc("ifdim"); | |
> if_odd_code:print_esc("ifodd"); | |
> if_vmode_code:print_esc("ifvmode"); | |
> if_hmode_code:print_esc("ifhmode"); | |
> if_mmode_code:print_esc("ifmmode"); | |
> if_inner_code:print_esc("ifinner"); | |
> if_void_code:print_esc("ifvoid"); | |
> if_hbox_code:print_esc("ifhbox"); | |
> if_vbox_code:print_esc("ifvbox"); | |
> ifx_code:print_esc("ifx"); | |
> if_eof_code:print_esc("ifeof"); | |
> if_true_code:print_esc("iftrue"); | |
> if_false_code:print_esc("iffalse"); | |
> if_case_code:print_esc("ifcase"); | |
> othercases print_esc("if") | |
> endcases; | |
> | |
> @ Conditions can be inside conditions, and this nesting has a stack | |
> that is independent of the |save_stack|. | |
> | |
> Four global variables represent the top of the condition stack: | |
> |cond_ptr| points to pushed-down entries, if any; |if_limit| specifies | |
> the largest code of a |fi_or_else| command that is syntactically legal; | |
> |cur_if| is the name of the current type of conditional; and |if_line| | |
> is the line number at which it began. | |
> | |
> If no conditions are currently in progress, the condition stack has the | |
> special state |cond_ptr=null|, |if_limit=normal|, |cur_if=0|, |if_line=0|. | |
> Otherwise |cond_ptr| points to a two-word node; the |type|, |subtype|, and | |
> |link| fields of the first word contain |if_limit|, |cur_if|, and | |
> |cond_ptr| at the next level, and the second word contains the | |
> corresponding |if_line|. | |
> | |
> @d if_node_size=2 {number of words in stack entry for conditionals} | |
> @d if_line_field(#)==mem[#+1].int | |
> @d if_code=1 {code for \.{\\if...} being evaluated} | |
> @d fi_code=2 {code for \.{\\fi}} | |
> @d else_code=3 {code for \.{\\else}} | |
> @d or_code=4 {code for \.{\\or}} | |
> | |
> @<Glob...@>= | |
> @!cond_ptr:pointer; {top of the condition stack} | |
> @!if_limit:normal..or_code; {upper bound on |fi_or_else| codes} | |
> @!cur_if:small_number; {type of conditional being worked on} | |
> @!if_line:integer; {line where that conditional began} | |
> | |
> @ @<Set init...@>= | |
> cond_ptr:=null; if_limit:=normal; cur_if:=0; if_line:=0; | |
> | |
> @ @<Put each...@>= | |
> primitive("fi",fi_or_else,fi_code); | |
> @!@:fi_}{\.{\\fi} primitive@> | |
> text(frozen_fi):="fi"; eqtb[frozen_fi]:=eqtb[cur_val]; | |
> primitive("or",fi_or_else,or_code); | |
> @!@:or_}{\.{\\or} primitive@> | |
> primitive("else",fi_or_else,else_code); | |
> @!@:else_}{\.{\\else} primitive@> | |
> | |
> @ @<Cases of |print_cmd_chr|...@>= | |
> fi_or_else: if chr_code=fi_code then print_esc("fi") | |
> else if chr_code=or_code then print_esc("or") | |
> else print_esc("else"); | |
> | |
> @ When we skip conditional text, we keep track of the line number | |
> where skipping began, for use in error messages. | |
> | |
> @<Glob...@>= | |
> @!skip_line:integer; {skipping began here} | |
> | |
> @ Here is a procedure that ignores text until coming to an \.{\\or}, | |
> \.{\\else}, or \.{\\fi} at level zero of $\.{\\if}\ldots\.{\\fi}$ | |
> nesting. After it has acted, |cur_chr| will indicate the token that | |
> was found, but |cur_tok| will not be set (because this makes the | |
> procedure run faster). | |
> | |
> @p procedure pass_text; | |
> label done; | |
> var l:integer; {level of $\.{\\if}\ldots\.{\\fi}$ nesting} | |
> @!save_scanner_status:small_number; {|scanner_status| upon entry} | |
> begin save_scanner_status:=scanner_status; scanner_status:=skipping; l:=0; | |
> skip_line:=line; | |
> loop@+ begin get_next; | |
> if cur_cmd=fi_or_else then | |
> begin if l=0 then goto done; | |
> if cur_chr=fi_code then decr(l); | |
> end | |
> else if cur_cmd=if_test then incr(l); | |
> end; | |
> done: scanner_status:=save_scanner_status; | |
> end; | |
> | |
> @ When we begin to process a new \.{\\if}, we set |if_limit:=if_code|; then | |
> if\/ \.{\\or} or \.{\\else} or \.{\\fi} occurs before the current \.{\\if} | |
> condition has been evaluated, \.{\\relax} will be inserted. | |
> For example, a sequence of commands like `\.{\\ifvoid1\\else...\\fi}' | |
> would otherwise require something after the `\.1'. | |
> | |
> @<Push the condition stack@>= | |
> begin p:=get_node(if_node_size); link(p):=cond_ptr; type(p):=if_limit; | |
> subtype(p):=cur_if; if_line_field(p):=if_line; | |
> cond_ptr:=p; cur_if:=cur_chr; if_limit:=if_code; if_line:=line; | |
> end | |
> | |
> @ @<Pop the condition stack@>= | |
> begin p:=cond_ptr; if_line:=if_line_field(p); | |
> cur_if:=subtype(p); if_limit:=type(p); cond_ptr:=link(p); | |
> free_node(p,if_node_size); | |
> end | |
> | |
> @ Here's a procedure that changes the |if_limit| code corresponding to | |
> a given value of |cond_ptr|. | |
> | |
> @p procedure change_if_limit(@!l:small_number;@!p:pointer); | |
> label exit; | |
> var q:pointer; | |
> begin if p=cond_ptr then if_limit:=l {that's the easy case} | |
> else begin q:=cond_ptr; | |
> loop@+ begin if q=null then confusion("if"); | |
> @:this can't happen if}{\quad if@> | |
> if link(q)=p then | |
> begin type(q):=l; return; | |
> end; | |
> q:=link(q); | |
> end; | |
> end; | |
> exit:end; | |
> | |
> @ A condition is started when the |expand| procedure encounters | |
> an |if_test| command; in that case |expand| reduces to |conditional|, | |
> which is a recursive procedure. | |
> @^recursion@> | |
> | |
> @p procedure conditional; | |
> label exit,common_ending; | |
> var b:boolean; {is the condition true?} | |
> @!r:"<"..">"; {relation to be evaluated} | |
> @!m,@!n:integer; {to be tested against the second operand} | |
> @!p,@!q:pointer; {for traversing token lists in \.{\\ifx} tests} | |
> @!save_scanner_status:small_number; {|scanner_status| upon entry} | |
> @!save_cond_ptr:pointer; {|cond_ptr| corresponding to this conditional} | |
> @!this_if:small_number; {type of this conditional} | |
> begin @<Push the condition stack@>;@+save_cond_ptr:=cond_ptr;this_if:=cur_chr;@/ | |
> @<Either process \.{\\ifcase} or set |b| to the value of a boolean condition@>; | |
> if tracing_commands>1 then @<Display the value of |b|@>; | |
> if b then | |
> begin change_if_limit(else_code,save_cond_ptr); | |
> return; {wait for \.{\\else} or \.{\\fi}} | |
> end; | |
> @<Skip to \.{\\else} or \.{\\fi}, then |goto common_ending|@>; | |
> common_ending: if cur_chr=fi_code then @<Pop the condition stack@> | |
> else if_limit:=fi_code; {wait for \.{\\fi}} | |
> exit:end; | |
> | |
> @ In a construction like `\.{\\if\\iftrue abc\\else d\\fi}', the first | |
> \.{\\else} that we come to after learning that the \.{\\if} is false is | |
> not the \.{\\else} we're looking for. Hence the following curious | |
> logic is needed. | |
> | |
> @ @<Skip to \.{\\else} or \.{\\fi}...@>= | |
> loop@+ begin pass_text; | |
> if cond_ptr=save_cond_ptr then | |
> begin if cur_chr<>or_code then goto common_ending; | |
> print_err("Extra "); print_esc("or"); | |
> @.Extra \\or@> | |
> help1("I'm ignoring this; it doesn't match any \if."); | |
> error; | |
> end | |
> else if cur_chr=fi_code then @<Pop the condition stack@>; | |
> end | |
> | |
> @ @<Either process \.{\\ifcase} or set |b|...@>= | |
> case this_if of | |
> if_char_code, if_cat_code: @<Test if two characters match@>; | |
> if_int_code, if_dim_code: @<Test relation between integers or dimensions@>; | |
> if_odd_code: @<Test if an integer is odd@>; | |
> if_vmode_code: b:=(abs(mode)=vmode); | |
> if_hmode_code: b:=(abs(mode)=hmode); | |
> if_mmode_code: b:=(abs(mode)=mmode); | |
> if_inner_code: b:=(mode<0); | |
> if_void_code, if_hbox_code, if_vbox_code: @<Test box register status@>; | |
> ifx_code: @<Test if two tokens match@>; | |
> if_eof_code: begin scan_four_bit_int; b:=(read_open[cur_val]=closed); | |
> end; | |
> if_true_code: b:=true; | |
> if_false_code: b:=false; | |
> if_case_code: @<Select the appropriate case | |
> and |return| or |goto common_ending|@>; | |
> end {there are no other cases} | |
> | |
> @ @<Display the value of |b|@>= | |
> begin begin_diagnostic; | |
> if b then print("{true}")@+else print("{false}"); | |
> end_diagnostic(false); | |
> end | |
> | |
> @ Here we use the fact that |"<"|, |"="|, and |">"| are consecutive ASCII | |
> codes. | |
> @^ASCII code@> | |
> | |
> @<Test relation between integers or dimensions@>= | |
> begin if this_if=if_int_code then scan_int@+else scan_normal_dimen; | |
> n:=cur_val; @<Get the next non-blank non-call...@>; | |
> if (cur_tok>=other_token+"<")and(cur_tok<=other_token+">") then | |
> r:=cur_tok-other_token | |
> else begin print_err("Missing = inserted for "); | |
> @.Missing = inserted@> | |
> print_cmd_chr(if_test,this_if); | |
> help1("I was expecting to see `<', `=', or `>'. Didn't."); | |
> back_error; r:="="; | |
> end; | |
> if this_if=if_int_code then scan_int@+else scan_normal_dimen; | |
> case r of | |
> "<": b:=(n<cur_val); | |
> "=": b:=(n=cur_val); | |
> ">": b:=(n>cur_val); | |
> end; | |
> end | |
> | |
> @ @<Test if an integer is odd@>= | |
> begin scan_int; b:=odd(cur_val); | |
> end | |
> | |
> @ @<Test box register status@>= | |
> begin scan_eight_bit_int; p:=box(cur_val); | |
> if this_if=if_void_code then b:=(p=null) | |
> else if p=null then b:=false | |
> else if this_if=if_hbox_code then b:=(type(p)=hlist_node) | |
> else b:=(type(p)=vlist_node); | |
> end | |
> | |
> @ An active character will be treated as category 13 following | |
> \.{\\if\\noexpand} or following \.{\\ifcat\\noexpand}. We use the fact that | |
> active characters have the smallest tokens, among all control sequences. | |
> | |
> @d get_x_token_or_active_char==@t@>@; | |
> begin get_x_token; | |
> if cur_cmd=relax then if cur_chr=no_expand_flag then | |
> begin cur_cmd:=active_char; | |
> cur_chr:=cur_tok-cs_token_flag-active_base; | |
> end; | |
> end | |
> | |
> @<Test if two characters match@>= | |
> begin get_x_token_or_active_char; | |
> if (cur_cmd>active_char)or(cur_chr>255) then {not a character} | |
> begin m:=relax; n:=256; | |
> end | |
> else begin m:=cur_cmd; n:=cur_chr; | |
> end; | |
> get_x_token_or_active_char; | |
> if (cur_cmd>active_char)or(cur_chr>255) then | |
> begin cur_cmd:=relax; cur_chr:=256; | |
> end; | |
> if this_if=if_char_code then b:=(n=cur_chr)@+else b:=(m=cur_cmd); | |
> end | |
> | |
> @ Note that `\.{\\ifx}' will declare two macros different if one is \\{long} | |
> or \\{outer} and the other isn't, even though the texts of the macros are | |
> the same. | |
> | |
> We need to reset |scanner_status|, since \.{\\outer} control sequences | |
> are allowed, but we might be scanning a macro definition or preamble. | |
> | |
> @<Test if two tokens match@>= | |
> begin save_scanner_status:=scanner_status; scanner_status:=normal; | |
> get_next; n:=cur_cs; p:=cur_cmd; q:=cur_chr; | |
> get_next; if cur_cmd<>p then b:=false | |
> else if cur_cmd<call then b:=(cur_chr=q) | |
> else @<Test if two macro texts match@>; | |
> scanner_status:=save_scanner_status; | |
> end | |
> | |
> @ Note also that `\.{\\ifx}' decides that macros \.{\\a} and \.{\\b} are | |
> different in examples like this: | |
> $$\vbox{\halign{\.{#}\hfil&\qquad\.{#}\hfil\cr | |
> {}\\def\\a\{\\c\}& | |
> {}\\def\\c\{\}\cr | |
> {}\\def\\b\{\\d\}& | |
> {}\\def\\d\{\}\cr}}$$ | |
> | |
> @<Test if two macro texts match@>= | |
> begin p:=link(cur_chr); q:=link(equiv(n)); {omit reference counts} | |
> if p=q then b:=true | |
> else begin while (p<>null)and(q<>null) do | |
> if info(p)<>info(q) then p:=null | |
> else begin p:=link(p); q:=link(q); | |
> end; | |
> b:=((p=null)and(q=null)); | |
> end; | |
> end | |
> | |
> @ @<Select the appropriate case and |return| or |goto common_ending|@>= | |
> begin scan_int; n:=cur_val; {|n| is the number of cases to pass} | |
> if tracing_commands>1 then | |
> begin begin_diagnostic; print("{case "); print_int(n); print_char("}"); | |
> end_diagnostic(false); | |
> end; | |
> while n<>0 do | |
> begin pass_text; | |
> if cond_ptr=save_cond_ptr then | |
> if cur_chr=or_code then decr(n) | |
> else goto common_ending | |
> else if cur_chr=fi_code then @<Pop the condition stack@>; | |
> end; | |
> change_if_limit(or_code,save_cond_ptr); | |
> return; {wait for \.{\\or}, \.{\\else}, or \.{\\fi}} | |
> end | |
> | |
> @ The processing of conditionals is complete except for the following | |
> code, which is actually part of |expand|. It comes into play when | |
> \.{\\or}, \.{\\else}, or \.{\\fi} is scanned. | |
> | |
> @<Terminate the current conditional and skip to \.{\\fi}@>= | |
> if cur_chr>if_limit then | |
> if if_limit=if_code then insert_relax {condition not yet evaluated} | |
> else begin print_err("Extra "); print_cmd_chr(fi_or_else,cur_chr); | |
> @.Extra \\or@> | |
> @.Extra \\else@> | |
> @.Extra \\fi@> | |
> help1("I'm ignoring this; it doesn't match any \if."); | |
> error; | |
> end | |
> else begin while cur_chr<>fi_code do pass_text; {skip to \.{\\fi}} | |
> @<Pop the condition stack@>; | |
> end | |
> | |
> @* \[29] File names. | |
> It's time now to fret about file names. Besides the fact that different | |
> operating systems treat files in different ways, we must cope with the | |
> fact that completely different naming conventions are used by different | |
> groups of people. The following programs show what is required for one | |
> particular operating system; similar routines for other systems are not | |
> difficult to devise. | |
> @^fingers@> | |
> @^system dependencies@> | |
> | |
> \TeX\ assumes that a file name has three parts: the name proper; its | |
> ``extension''; and a ``file area'' where it is found in an external file | |
> system. The extension of an input file or a write file is assumed to be | |
> `\.{.tex}' unless otherwise specified; it is `\.{.log}' on the | |
> transcript file that records each run of \TeX; it is `\.{.tfm}' on the font | |
> metric files that describe characters in the fonts \TeX\ uses; it is | |
> `\.{.dvi}' on the output files that specify typesetting information; and it | |
> is `\.{.fmt}' on the format files written by \.{INITEX} to initialize \TeX. | |
> The file area can be arbitrary on input files, but files are usually | |
> output to the user's current area. If an input file cannot be | |
> found on the specified area, \TeX\ will look for it on a special system | |
> area; this special area is intended for commonly used input files like | |
> \.{webmac.tex}. | |
> | |
> Simple uses of \TeX\ refer only to file names that have no explicit | |
> extension or area. For example, a person usually says `\.{\\input} \.{paper}' | |
> or `\.{\\font\\tenrm} \.= \.{helvetica}' instead of `\.{\\input} | |
> \.{paper.new}' or `\.{\\font\\tenrm} \.= \.{<csd.knuth>test}'. Simple file | |
> names are best, because they make the \TeX\ source files portable; | |
> whenever a file name consists entirely of letters and digits, it should be | |
> treated in the same way by all implementations of \TeX. However, users | |
> need the ability to refer to other files in their environment, especially | |
> when responding to error messages concerning unopenable files; therefore | |
> we want to let them use the syntax that appears in their favorite | |
> operating system. | |
> | |
> The following procedures don't allow spaces to be part of | |
> file names; but some users seem to like names that are spaced-out. | |
> System-dependent changes to allow such things should probably | |
> be made with reluctance, and only when an entire file name that | |
> includes spaces is ``quoted'' somehow. | |
> | |
> @ In order to isolate the system-dependent aspects of file names, the | |
> @^system dependencies@> | |
> system-independent parts of \TeX\ are expressed in terms | |
> of three system-dependent | |
> procedures called |begin_name|, |more_name|, and |end_name|. In | |
> essence, if the user-specified characters of the file name are $c_1\ldots c_n$, | |
> the system-independent driver program does the operations | |
> $$|begin_name|;\,|more_name|(c_1);\,\ldots\,;\,|more_name|(c_n); | |
> \,|end_name|.$$ | |
> These three procedures communicate with each other via global variables. | |
> Afterwards the file name will appear in the string pool as three strings | |
> called |cur_name|\penalty10000\hskip-.05em, | |
> |cur_area|, and |cur_ext|; the latter two are null (i.e., | |
> |""|), unless they were explicitly specified by the user. | |
> | |
> Actually the situation is slightly more complicated, because \TeX\ needs | |
> to know when the file name ends. The |more_name| routine is a function | |
> (with side effects) that returns |true| on the calls |more_name|$(c_1)$, | |
> \dots, |more_name|$(c_{n-1})$. The final call |more_name|$(c_n)$ | |
> returns |false|; or, it returns |true| and the token following $c_n$ is | |
> something like `\.{\\hbox}' (i.e., not a character). In other words, | |
> |more_name| is supposed to return |true| unless it is sure that the | |
> file name has been completely scanned; and |end_name| is supposed to be able | |
> to finish the assembly of |cur_name|, |cur_area|, and |cur_ext| regardless of | |
> whether $|more_name|(c_n)$ returned |true| or |false|. | |
> | |
> @<Glob...@>= | |
> @!cur_name:str_number; {name of file just scanned} | |
> @!cur_area:str_number; {file area just scanned, or \.{""}} | |
> @!cur_ext:str_number; {file extension just scanned, or \.{""}} | |
> | |
> @ The file names we shall deal with for illustrative purposes have the | |
> following structure: If the name contains `\.>' or `\.:', the file area | |
> consists of all characters up to and including the final such character; | |
> otherwise the file area is null. If the remaining file name contains | |
> `\..', the file extension consists of all such characters from the first | |
> remaining `\..' to the end, otherwise the file extension is null. | |
> @^system dependencies@> | |
> | |
> We can scan such file names easily by using two global variables that keep track | |
> of the occurrences of area and extension delimiters: | |
> | |
> @<Glob...@>= | |
> @!area_delimiter:pool_pointer; {the most recent `\.>' or `\.:', if any} | |
7782,7784c9894,9897 | |
< system area called |TEX_area|. Font files whose areas are not given explicitly | |
< are assumed to appear in a standard system area called |TEX_font_area|. | |
< These system area names will, of course, vary from place to place. | |
--- | |
> system area called |TEX_area|. Font metric files whose areas are not given | |
> explicitly are assumed to appear in a standard system area called | |
> |TEX_font_area|. These system area names will, of course, vary from place | |
> to place. | |
7787,7788c9900,9903 | |
< @d TEX_area=="<TeX>" | |
< @d TEX_font_area=="<TeX.fonts>" | |
--- | |
> @d TEX_area=="TeXinputs:" | |
> @.TeXinputs@> | |
> @d TEX_font_area=="TeXfonts:" | |
> @.TeXfonts@> | |
7794c9909 | |
< begin area_delimiter←0; ext_delimiter←0; | |
--- | |
> begin area_delimiter:=0; ext_delimiter:=0; | |
7797c9912,9915 | |
< @ And here's the second. | |
--- | |
> @ And here's the second. The string pool might change as the file name is | |
> being scanned, since a new \.{\\csname} might be entered; therefore we keep | |
> |area_delimiter| and |ext_delimiter| relative to the beginning of the current | |
> string, instead of assigning an absolute address like |pool_ptr| to them. | |
7800,7808c9918,9926 | |
< @p function more_name(@!c:ascii_code):boolean; | |
< begin if c=" " then more_name←false | |
< else begin if (c=">")∨(c=":") then | |
< begin area_delimiter←pool_ptr; ext_delimiter←0; | |
< end | |
< else if (c=".")∧(ext_delimiter=0) then ext_delimiter←pool_ptr; | |
< str_room(1); append_char(c); {contribute |c| to the current string} | |
< more_name←true; | |
< end; | |
--- | |
> @p function more_name(@!c:ASCII_code):boolean; | |
> begin if c=" " then more_name:=false | |
> else begin str_room(1); append_char(c); {contribute |c| to the current string} | |
> if (c=">")or(c=":") then | |
> begin area_delimiter:=cur_length; ext_delimiter:=0; | |
> end | |
> else if (c=".")and(ext_delimiter=0) then ext_delimiter:=cur_length; | |
> more_name:=true; | |
> end; | |
7815,7819c9933,9939 | |
< begin if str_ptr+3>max_strings then overflow("number of strings",max_strings); | |
< if area_delimiter=0 then cur_area←"" | |
< else begin cur_area←str_ptr; incr(str_ptr); | |
< str_start[str_ptr]←area_delimiter+1; | |
< end; | |
--- | |
> begin if str_ptr+3>max_strings then | |
> overflow("number of strings",max_strings-init_str_ptr); | |
> @:TeX capacity exceeded number of strings}{\quad number of strings@> | |
> if area_delimiter=0 then cur_area:="" | |
> else begin cur_area:=str_ptr; | |
> str_start[str_ptr+1]:=str_start[str_ptr]+area_delimiter; incr(str_ptr); | |
> end; | |
7821,7825c9941,9946 | |
< begin cur_ext←""; cur_name←make_string; | |
< end | |
< else begin cur_name←str_ptr; incr(str_ptr); | |
< str_start[str_ptr]←ext_delimiter; cur_ext←make_string; | |
< end; | |
--- | |
> begin cur_ext:=""; cur_name:=make_string; | |
> end | |
> else begin cur_name:=str_ptr; | |
> str_start[str_ptr+1]:=str_start[str_ptr]+ext_delimiter-area_delimiter-1; | |
> incr(str_ptr); cur_ext:=make_string; | |
> end; | |
7835c9956 | |
< begin print(a); print(n); print(e); | |
--- | |
> begin slow_print(a); slow_print(n); slow_print(e); | |
7838,7839c9959,9962 | |
< @ Another system-dependent routine is needed to convert three \TeX\ strings | |
< into the |name_of_file| value that is used to open files. | |
--- | |
> @ Another system-dependent routine is needed to convert three internal | |
> \TeX\ strings | |
> into the |name_of_file| value that is used to open files. The present code | |
> allows both lowercase and uppercase letters in the file name. | |
7842,7845c9965,9967 | |
< @d append_to_name(#)==begin c←#; incr(k); | |
< if (c≥"a")∧(c≤"z") then c←c-@'40; {convert to upper case} | |
< name_of_file[k]←xchr[c]; | |
< end | |
--- | |
> @d append_to_name(#)==begin c:=#; incr(k); | |
> if k<=file_name_size then name_of_file[k]:=xchr[c]; | |
> end | |
7849,7858c9971,9978 | |
< @!c: ascii_code; {character being packed} | |
< @!j:pool_pointer; {index into |string_pool|} | |
< begin if length(a)+length(n)+length(e)>file_name_size then | |
< overflow("file name size",file_name_size); | |
< k←0; | |
< for j←str_start[a] to str_start[a+1]-1 do append_to_name(str_pool[j]); | |
< for j←str_start[n] to str_start[n+1]-1 do append_to_name(str_pool[j]); | |
< for j←str_start[e] to str_start[e+1]-1 do append_to_name(str_pool[j]); | |
< name_length←k; | |
< for k←name_length+1 to file_name_size do name_of_file[k]←' '; | |
--- | |
> @!c: ASCII_code; {character being packed} | |
> @!j:pool_pointer; {index into |str_pool|} | |
> begin k:=0; | |
> for j:=str_start[a] to str_start[a+1]-1 do append_to_name(so(str_pool[j])); | |
> for j:=str_start[n] to str_start[n+1]-1 do append_to_name(so(str_pool[j])); | |
> for j:=str_start[e] to str_start[e+1]-1 do append_to_name(so(str_pool[j])); | |
> if k<=file_name_size then name_length:=k@+else name_length:=file_name_size; | |
> for k:=name_length+1 to file_name_size do name_of_file[k]:=' '; | |
7867,7868c9987,9990 | |
< @d format_default_length=22 {length of the |TEX_format_default| string} | |
< @d format_area_length=13 {length of its area part} | |
--- | |
> @d format_default_length=20 {length of the |TEX_format_default| string} | |
> @d format_area_length=11 {length of its area part} | |
> @d format_ext_length=4 {length of its `\.{.fmt}' part} | |
> @d format_extension=".fmt" {the extension, as a \.{WEB} constant} | |
7874c9996,9999 | |
< TEX_format_default←'<TeX.formats>BASIC.fmt'; | |
--- | |
> TEX_format_default:='TeXformats:plain.fmt'; | |
> @.TeXformats@> | |
> @.plain@> | |
> @^system dependencies@> | |
7877c10002 | |
< if format_default_length>file_name_size then bad←31; | |
--- | |
> if format_default_length>file_name_size then bad:=31; | |
7881c10006,10007 | |
< |buffer[a..b]|, followed by the last four characters of |format_default|. | |
--- | |
> |buffer[a..b]|, followed by the last |format_ext_length| characters of | |
> |TEX_format_default|. | |
7891c10017 | |
< @!c: ascii_code; {character being packed} | |
--- | |
> @!c: ASCII_code; {character being packed} | |
7893,7900c10019,10027 | |
< begin if n+b-a+5>file_name_size then b←a+file_name_size-n-5; | |
< k←0; | |
< for j←1 to n do append_to_name(xord[TEX_format_default[j]]); | |
< for j←a to b do append_to_name(buffer[j]); | |
< for j←format_default_length-3 to format_default_length do | |
< append_to_name(xord[TEX_format_default[j]]); | |
< name_length←k; | |
< for k←name_length+1 to file_name_size do name_of_file[k]←' '; | |
--- | |
> begin if n+b-a+1+format_ext_length>file_name_size then | |
> b:=a+file_name_size-n-1-format_ext_length; | |
> k:=0; | |
> for j:=1 to n do append_to_name(xord[TEX_format_default[j]]); | |
> for j:=a to b do append_to_name(buffer[j]); | |
> for j:=format_default_length-format_ext_length+1 to format_default_length do | |
> append_to_name(xord[TEX_format_default[j]]); | |
> if k<=file_name_size then name_length:=k@+else name_length:=file_name_size; | |
> for k:=name_length+1 to file_name_size do name_of_file[k]:=' '; | |
7905,7906c10032,10035 | |
< the preliminary initialization. The buffer contains the first line of input | |
< in |buffer[loc..(last-1)]|, where |loc<last| and |buffer[loc]≠" "|. | |
--- | |
> the preliminary initialization, or when the user is substituting another | |
> format file by typing `\.\&' after the initial `\.{**}' prompt. The buffer | |
> contains the first line of input in |buffer[loc..(last-1)]|, where | |
> |loc<last| and |buffer[loc]<>" "|. | |
7911,7931c10040,10064 | |
< var j:0..buf_size; {the first space after the file name} | |
< begin if buffer[loc]≠"\" then | |
< begin j←loc+1; buffer[last]←" "; | |
< while buffer[j]≠" " do incr(j); | |
< pack_buffered_name(0,loc,j-1); {try first without the system file area} | |
< if w_open_in(fmt_file) then | |
< begin loc←j; goto found; | |
< end;@/ | |
< {now try the system format file area} | |
< pack_buffered_name(format_area_length,loc,j-1); | |
< if w_open_in(fmt_file) then | |
< begin loc←j; goto found; | |
< end; | |
< end; | |
< {now pull out all the stops: try for the system \.{BASIC} file} | |
< pack_buffered_name(format_default_length-4,1,0); | |
< if ¬ w_open_in(fmt_file) then | |
< begin write_ln(term_out,'I can''t find the BASIC format file!'); | |
< open_fmt_file←false; return; | |
< end; | |
< found:open_fmt_file←true; | |
--- | |
> var j:0..buf_size; {the first space after the format file name} | |
> begin j:=loc; | |
> if buffer[loc]="&" then | |
> begin incr(loc); j:=loc; buffer[last]:=" "; | |
> while buffer[j]<>" " do incr(j); | |
> pack_buffered_name(0,loc,j-1); {try first without the system file area} | |
> if w_open_in(fmt_file) then goto found; | |
> pack_buffered_name(format_area_length,loc,j-1); | |
> {now try the system format file area} | |
> if w_open_in(fmt_file) then goto found; | |
> wake_up_terminal; | |
> wterm_ln('Sorry, I can''t find that format;',' will try PLAIN.'); | |
> @.Sorry, I can't find...@> | |
> update_terminal; | |
> end; | |
> {now pull out all the stops: try for the system \.{plain} file} | |
> pack_buffered_name(format_default_length-format_ext_length,1,0); | |
> if not w_open_in(fmt_file) then | |
> begin wake_up_terminal; | |
> wterm_ln('I can''t find the PLAIN format file!'); | |
> @.I can't find PLAIN...@> | |
> @.plain@> | |
> open_fmt_file:=false; return; | |
> end; | |
> found:loc:=j; open_fmt_file:=true; | |
7937,7938c10070,10071 | |
< ideally be changed to deduce the full name of file@@|f|, if it is | |
< possible to do this in a \PASCAL\ program. | |
--- | |
> 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. | |
7940a10074,10076 | |
> This routine might be called after string memory has overflowed, hence | |
> we dare not use `|str_room|'. | |
> | |
7943,7945c10079,10084 | |
< begin str_room(name_length); | |
< for k←1 to name_length do append_char(xord[name_of_file[k]]); | |
< make_name_string←make_string; | |
--- | |
> begin if (pool_ptr+name_length>pool_size)or(str_ptr=max_strings)or | |
> (cur_length>0) then | |
> make_name_string:="?" | |
> else begin for k:=1 to name_length do append_char(xord[name_of_file[k]]); | |
> make_name_string:=make_string; | |
> end; | |
7948c10087 | |
< begin a_make_name_string←make_name_string; | |
--- | |
> begin a_make_name_string:=make_name_string; | |
7951c10090 | |
< begin b_make_name_string←make_name_string; | |
--- | |
> begin b_make_name_string:=make_name_string; | |
7954,7964c10093 | |
< begin w_make_name_string←make_name_string; | |
< end; | |
< | |
< @ Similarly, the ideal |write_name_string| would write the full | |
< external name of |fmt_file|, assuming that |fmt_file| has been opened. | |
< The procedure shown here merely copies |name_of_file|. Output in this | |
< case goes to the user's terminal. | |
< | |
< @p procedure write_name_string; | |
< var k:1..file_name_size; {index into |name_of_file|} | |
< begin for k←1 to name_length do write(term_out,name_of_file[k]); | |
--- | |
> begin w_make_name_string:=make_name_string; | |
7967,7970c10096,10099 | |
< @ Now let's consider the routines by which \TeX\ deals with file names | |
< in a (hopefully) system-independent manner. | |
< First comes a procedure that looks for a file name in the input by | |
< calling |get_nc_token| for the information. | |
--- | |
> @ Now let's consider the ``driver'' | |
> routines by which \TeX\ deals with file names | |
> in a system-independent manner. First comes a procedure that looks for a | |
> file name in the input by calling |get_x_token| for the information. | |
7974c10103 | |
< begin begin_name; | |
--- | |
> begin name_in_progress:=true; begin_name; | |
7976,7982c10105,10111 | |
< loop@+begin if (cur_cmd>other_char)∨(cur_chr>127) then {not a character} | |
< begin back_input; goto done; | |
< end; | |
< if ¬ more_name(cur_chr) then goto done; | |
< get_nc_token; | |
< end; | |
< done: end_name; | |
--- | |
> loop@+begin if (cur_cmd>other_char)or(cur_chr>255) then {not a character} | |
> begin back_input; goto done; | |
> end; | |
> if not more_name(cur_chr) then goto done; | |
> get_x_token; | |
> end; | |
> done: end_name; name_in_progress:=false; | |
7985,7987c10114,10124 | |
< @ The global variable |job_name| contains the file name that was first | |
< \.{\\input} by the user. This name is extended by `\.{err}' and `\.{dvi}' | |
< and `\.{fmt}' in order to make the names of \TeX's output files. | |
--- | |
> @ The global variable |name_in_progress| is used to prevent recursive | |
> use of |scan_file_name|, since the |begin_name| and other procedures | |
> communicate via global variables. Recursion would arise only by | |
> devious tricks like `\.{\\input\\input f}'; such attempts at sabotage | |
> must be thwarted. Furthermore, |name_in_progress| prevents \.{\\input} | |
> @^recursion@> | |
> from being initiated when a font size specification is being scanned. | |
> | |
> Another global variable, |job_name|, contains the file name that was first | |
> \.{\\input} by the user. This name is extended by `\.{.log}' and `\.{.dvi}' | |
> and `\.{.fmt}' in the names of \TeX's output files. | |
7989a10127 | |
> @!name_in_progress:boolean; {is a file name being scanned?} | |
7990a10129 | |
> @!log_opened:boolean; {has the transcript file been opened?} | |
7993c10132,10133 | |
< We have |job_name=0| if and only the `\.{err}' file has not been opened. | |
--- | |
> 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. | |
7995c10135,10136 | |
< @<Initialize the output...@>=job_name←0; | |
--- | |
> @<Initialize the output...@>= | |
> job_name:=0; name_in_progress:=false; log_opened:=false; | |
7998c10139 | |
< |job_name≠0|. It ignores and changes the current settings of |cur_area| | |
--- | |
> |job_name<>0|. It ignores and changes the current settings of |cur_area| | |
8003,8006c10144,10147 | |
< @p procedure pack_job_name(@!s:str_number); {|s = ".err"|, |".dvi"|, or | |
< |".fmt"|} | |
< begin cur_area←""; cur_ext←s; | |
< cur_name←job_name; pack_cur_name; | |
--- | |
> @p procedure pack_job_name(@!s:str_number); {|s = ".log"|, |".dvi"|, or | |
> |format_extension|} | |
> begin cur_area:=""; cur_ext:=s; | |
> cur_name:=job_name; pack_cur_name; | |
8010,8011c10151,10152 | |
< 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| | |
--- | |
> 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| | |
8019c10160,10161 | |
< begin if s="input file name" then print_nl("! I can't find file `") | |
--- | |
> begin if interaction=scroll_mode then wake_up_terminal; | |
> if s="input file name" then print_err("I can't find file `") | |
8021c10163 | |
< else print_nl("! I can't write on file `"); | |
--- | |
> else print_err("I can't write on file `"); | |
8025a10168 | |
> @.Please type...@> | |
8027c10170,10171 | |
< fatal_error("*** (job aborted, file error in nonstop mode)"); | |
--- | |
> fatal_error("*** (job aborted, file error in nonstop mode)"); | |
> @.job aborted, file error...@> | |
8029c10173 | |
< if cur_ext="" then cur_ext←e; | |
--- | |
> if cur_ext="" then cur_ext:=e; | |
8034,8039c10178,10183 | |
< begin begin_name; k←first; | |
< while (buffer[k]=" ")∧(k<last) do incr(k); | |
< loop@+ begin if k=last then goto done; | |
< if ¬ more_name(buffer[k]) then goto done; | |
< incr(k); | |
< end; | |
--- | |
> begin begin_name; k:=first; | |
> while (buffer[k]=" ")and(k<last) do incr(k); | |
> loop@+ begin if k=last then goto done; | |
> if not more_name(buffer[k]) then goto done; | |
> incr(k); | |
> end; | |
8043,8044c10187,10188 | |
< @ Here's an example of how these conventions are used. We shall use the | |
< macro |ensure_dvi_open| when it is time to ship out a box of stuff. | |
--- | |
> @ Here's an example of how these conventions are used. Whenever it is time to | |
> ship out a box of stuff, we shall use the macro |ensure_dvi_open|. | |
8047,8052c10191,10196 | |
< begin if job_name=0 then open_err_file; | |
< pack_job_name(".dvi"); | |
< while ¬ b_open_out(dvi_file) do | |
< prompt_file_name("file name for output",".dvi"); | |
< output_file_name←b_make_name_string(dvi_file); | |
< end | |
--- | |
> begin if job_name=0 then open_log_file; | |
> pack_job_name(".dvi"); | |
> while not b_open_out(dvi_file) do | |
> prompt_file_name("file name for output",".dvi"); | |
> output_file_name:=b_make_name_string(dvi_file); | |
> end | |
8056a10201 | |
> @!log_name:str_number; {full name of the log file} | |
8058c10203 | |
< @ @<Initialize the output...@>=output_file_name←0; | |
--- | |
> @ @<Initialize the output...@>=output_file_name:=0; | |
8060c10205 | |
< @ The |open_err_file| routine is used to open the transcript file and to help | |
--- | |
> @ The |open_log_file| routine is used to open the transcript file and to help | |
8063c10208 | |
< @p procedure open_err_file; | |
--- | |
> @p procedure open_log_file; | |
8065a10211 | |
> @!l:0..buf_size; {end of first input line} | |
8067,8072c10213,10219 | |
< begin old_setting←selector; print_nl(""); | |
< if job_name=0 then job_name←"texput"; | |
< pack_job_name(".err"); | |
< while ¬ a_open_out(err_file) do | |
< prompt_file_name("`err' file name for the transcript",".err"); | |
< selector←err_only; | |
--- | |
> begin old_setting:=selector; | |
> if job_name=0 then job_name:="texput"; | |
> @.texput@> | |
> pack_job_name(".log"); | |
> while not a_open_out(log_file) do @<Try to get a different log file name@>; | |
> log_name:=a_make_name_string(log_file); | |
> selector:=log_only; log_opened:=true; | |
8074,8075c10221,10226 | |
< input_stack[input_ptr]←cur_input; {make sure bottom level is in memory} | |
< for k←1 to input_stack[0].limit_field do print(buffer[k-1]); | |
--- | |
> input_stack[input_ptr]:=cur_input; {make sure bottom level is in memory} | |
> print_nl("**"); | |
> @.**@> | |
> l:=input_stack[0].limit_field; {last position of first line} | |
> if buffer[l]=end_line_char then decr(l); | |
> for k:=1 to l do print(buffer[k]); | |
8077c10228 | |
< selector←old_setting+2; | |
--- | |
> selector:=old_setting+2; {|log_only| or |term_and_log|} | |
8079a10231,10249 | |
> @ Sometimes |open_log_file| is called at awkward moments when \TeX\ is | |
> unable to print error messages or even to |show_context|. | |
> The |prompt_file_name| routine can result in a |fatal_error|, but the |error| | |
> routine will not be invoked because |log_opened| will be false. | |
> | |
> The normal idea of |batch_mode| is that nothing at all should be written | |
> on the terminal. However, in the unusual case that | |
> no log file could be opened, we make an exception and allow | |
> an explanatory message to be seen. | |
> | |
> Incidentally, the program always refers to the log file as a `\.{transcript | |
> file}', because some systems cannot use the extension `\.{.log}' for | |
> this file. | |
> | |
> @<Try to get a different log file name@>= | |
> begin selector:=term_only; | |
> prompt_file_name("transcript file name",".log"); | |
> end | |
> | |
8081,8082c10251,10252 | |
< begin write(err_file,banner); | |
< print(format_ident); print(" "); | |
--- | |
> begin wlog(banner); | |
> slow_print(format_ident); print(" "); | |
8084,8085c10254,10255 | |
< months←'JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'; | |
< for k←3*month-2 to 3*month do write(err_file,months[k]); | |
--- | |
> months:='JANFEBMARAPRMAYJUNJULAUGSEPOCTNOVDEC'; | |
> for k:=3*month-2 to 3*month do wlog(months[k]); | |
8087,8089c10257 | |
< print_int(time div 60); print_char(":"); | |
< print_char("0"+((time mod 60) div 10)); | |
< print_char("0"+(time mod 10)); print_ln; | |
--- | |
> print_two(time div 60); print_char(":"); print_two(time mod 60); | |
8098c10266 | |
< if cur_ext="" then cur_ext←".tex"; | |
--- | |
> if cur_ext="" then cur_ext:=".tex"; | |
8100,8107c10268,10277 | |
< loop@+ begin begin_file_reading; {set up |cur_file| and new level of input} | |
< if a_open_in(cur_file) then goto done; | |
< pack_file_name(cur_name,TEX_area,cur_ext); | |
< if a_open_in(cur_file) then goto done; | |
< end_file_reading; {remove the level that didn't work} | |
< prompt_file_name("input file name",".tex"); | |
< end; | |
< done: name←a_make_name_string(cur_file); state←new_line; | |
--- | |
> loop@+ begin begin_file_reading; {set up |cur_file| and new level of input} | |
> if a_open_in(cur_file) then goto done; | |
> if cur_area="" then | |
> begin pack_file_name(cur_name,TEX_area,cur_ext); | |
> if a_open_in(cur_file) then goto done; | |
> end; | |
> end_file_reading; {remove the level that didn't work} | |
> prompt_file_name("input file name",".tex"); | |
> end; | |
> done: name:=a_make_name_string(cur_file); | |
8109,8112c10279,10288 | |
< begin job_name←cur_name; open_err_file; | |
< end; {|open_err_file| doesn't |show_context|, so |limit| | |
< and |loc| needn't be set to meaningful values yet} | |
< print(" ("); print(name); update_terminal; | |
--- | |
> begin job_name:=cur_name; open_log_file; | |
> end; {|open_log_file| doesn't |show_context|, so |limit| | |
> and |loc| needn't be set to meaningful values yet} | |
> if term_offset+length(name)>max_print_line-2 then print_ln | |
> else if (term_offset>0)or(file_offset>0) then print_char(" "); | |
> print_char("("); incr(open_parens); slow_print(name); update_terminal; | |
> state:=new_line; | |
> if name=str_ptr-1 then {we can conserve string pool space now} | |
> begin flush_string; name:=cur_name; | |
> end; | |
8116,8118c10292,10296 | |
< @ Here we have to remember that the |input_ln| routine | |
< starts with a |get|, so we have to read the first character of the file | |
< before it is lost. | |
--- | |
> @ Here we have to remember to tell the |input_ln| routine not to | |
> start with a |get|. If the file is empty, it is considered to | |
> contain a single blank line. | |
> @^system dependencies@> | |
> @^empty line at end of file@> | |
8121,8125c10299,10300 | |
< begin if eoln(cur_file) then last←start | |
< else begin buffer[start]←xord[cur_file^]; first←start+1; | |
< if ¬ input_ln(cur_file) then confusion("input"); | |
< @:confusion input}{\quad input@> | |
< end; | |
--- | |
> begin line:=1; | |
> if input_ln(cur_file,false) then do_nothing; | |
8127c10302,10304 | |
< buffer[limit]←carriage_return; first←limit+1; loc←start; line←1; | |
--- | |
> if end_line_char_inactive then decr(limit) | |
> else buffer[limit]:=end_line_char; | |
> first:=limit+1; loc:=start; | |
8129c10306,10307 | |
< @* \[29] Font metric data. | |
--- | |
> | |
> @* \[30] Font metric data. | |
8131c10309 | |
< \.{TFM} files; the `\.T' in `\.{TFM} stands for \TeX, | |
--- | |
> \.{TFM} files; the `\.T' in `\.{TFM}' stands for \TeX, | |
8163c10341 | |
< They are all nonnegative and less than $2^{15}$. We must have |bc-1≤ec≤255|, | |
--- | |
> They are all nonnegative and less than $2^{15}$. We must have |bc-1<=ec<=255|, | |
8167,8170c10345 | |
< and as few as 0 characters (if |bc=ec+1|). An exception to these rules is | |
< planned for oriental fonts, which will be identified by the condition |ec=256|; | |
< such fonts are not allowed except in extensions to \TeX82. | |
< @^oriental characters@>@^Chinese characters@>@^Japanese characters@> | |
--- | |
> and as few as 0 characters (if |bc=ec+1|). | |
8206,8207c10381,10382 | |
< scheme used (e.g., `\.{XEROX TEXT}' or `\.{TeX MATHSY}'), the next five | |
< give the font family name (e.g., `\.{HELVETICA}' or `\.{CMSY}'), and the | |
--- | |
> scheme used (e.g., `\.{XEROX text}' or `\.{TeX math symbols}'), the next five | |
> give the font identifier (e.g., `\.{HELVETICA}' or `\.{CMSY}'), and the | |
8211c10386 | |
< is not explicitly repeated in \.{DVI} format. | |
--- | |
> is not explicitly repeated in \.{DVI}~format. | |
8226c10401 | |
< the font, in units of points. This number must be at least 1.0; it is | |
--- | |
> the font, in units of \TeX\ points. This number must be at least 1.0; it is | |
8231c10406 | |
< and replace it by $\delta$, and to multiply the $x$ and@@$y$ coordinates | |
--- | |
> and replace it by $\delta$, and to multiply the $x$ and~$y$ coordinates | |
8233,8235c10408,10411 | |
< design size. {\sl All other dimensions in the\/\ \.{TFM} file are | |
< |fix_word| numbers in design-size units.} Thus, for example, the value | |
< of |param[6]|, one \.{em} or \.{\\quad}, is often the |fix_word| value | |
--- | |
> design size. {\sl All other dimensions in the\/ \.{TFM} file are | |
> |fix_word|\kern-1pt\ numbers in design-size units}, with the exception of | |
> |param[1]| (which denotes the slant ratio). Thus, for example, the value | |
> of |param[6]|, which defines the \.{em} unit, is often the |fix_word| value | |
8242,8244c10418,10420 | |
< @ Next comes the |char_info| array, which contains one |char_info_word| | |
< per character. Each |@!char_info_word| contains six fields packed into | |
< four bytes as follows. | |
--- | |
> @ 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. | |
8248c10424 | |
< (4@@bits)\par | |
--- | |
> (4~bits)\par | |
8250c10426 | |
< (2@@bits)\par | |
--- | |
> (2~bits)\par | |
8261,8262c10437,10438 | |
< The italic correction of a character has three different uses. | |
< (a)@@In ordinary text, the italic correction is added to the width only if | |
--- | |
> The italic correction of a character has two different uses. | |
> (a)~In ordinary text, the italic correction is added to the width only if | |
8264,8269c10440,10441 | |
< (b)@@In math formulas, the italic correction is always added to the width, | |
< unless the character has a subscript but no superscript. | |
< (c)@@In math formulas for which the character is a mathop in display style, | |
< a nonzero italic correction also affects the ``limit switch.'' For example, | |
< an integral sign $\int$ has a nonzero italic correction, but a summation | |
< sign $\sum$ does not. | |
--- | |
> (b)~In math formulas, the italic correction is always added to the width, | |
> except with respect to the positioning of subscripts. | |
8280,8283c10452,10455 | |
< \yskip\hang|tag=0| (|no_tag|) means that |remainder| is unused.\par | |
< \hang|tag=1| (|lig_tag|) means that this character has a ligature/kerning | |
< program starting at |lig_kern[remainder]|.\par | |
< \hang|tag=2| (|list_tag|) means that this character is part of a chain of | |
--- | |
> \yskip\hangg|tag=0| (|no_tag|) means that |remainder| is unused.\par | |
> \hangg|tag=1| (|lig_tag|) means that this character has a ligature/kerning | |
> program starting at position |remainder| in the |lig_kern| array.\par | |
> \hangg|tag=2| (|list_tag|) means that this character is part of a chain of | |
8286c10458 | |
< \hang|tag=3| (|ext_tag|) means that this character code represents an | |
--- | |
> \hangg|tag=3| (|ext_tag|) means that this character code represents an | |
8305,8306c10477,10479 | |
< \yskip\hang first byte: |stop_bit|, indicates the final program step | |
< if the byte is 128 or more.\par | |
--- | |
> \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 | |
8308,8310c10481,10483 | |
< then perform the operation and stop, otherwise continue.''\par | |
< \hang third byte: |op_bit|, indicates a ligature step if less than@@128, | |
< a kern step otherwise.\par | |
--- | |
> 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 | |
8313,8316c10486,10488 | |
< In a ligature step the current character and |next_char| are replaced by | |
< the single character whose code is |remainder|. In a kern step, an | |
< additional space equal to |@!kern[remainder]| is inserted between the | |
< current character and |next_char|. (The value of |kern[remainder]| is | |
--- | |
> In a kern step, an | |
> additional space equal to |kern[256*(op_byte-128)+remainder]| is inserted | |
> between the current character and |next_char|. This amount is | |
8318c10490 | |
< by kerning, but it might be positive.) | |
--- | |
> by kerning; but it might be positive. | |
8320,8323c10492,10525 | |
< @d stop_flag=128+min_quarterword | |
< {value indicating `\.{STOP}' in a lig/kern program} | |
< @d kern_flag=128+min_quarterword {op code for a kern step} | |
< @d stop_bit(#)==#.b0 | |
--- | |
> There are eight kinds of ligature steps, having |op_byte| codes $4a+2b+c$ where | |
> $0\le a\le b+c$ and $0\le b,c\le1$. The character whose code is | |
> |remainder| is inserted between the current character and |next_char|; | |
> then the current character is deleted if $b=0$, and |next_char| is | |
> deleted if $c=0$; then we pass over $a$~characters to reach the next | |
> current character (which may have a ligature/kerning program of its own). | |
> | |
> If the very first instruction of the |lig_kern| array has |skip_byte=255|, | |
> the |next_char| byte is the so-called right boundary character of this font; | |
> the value of |next_char| need not lie between |bc| and~|ec|. | |
> If the very last instruction of the |lig_kern| array has |skip_byte=255|, | |
> there is a special ligature/kerning program for a left boundary character, | |
> beginning at location |256*op_byte+remainder|. | |
> The interpretation is that \TeX\ puts implicit boundary characters | |
> before and after each consecutive string of characters from the same font. | |
> These implicit characters do not appear in the output, but they can affect | |
> ligatures and kerning. | |
> | |
> If the very first instruction of a character's |lig_kern| program has | |
> |skip_byte>128|, the program actually begins in location | |
> |256*op_byte+remainder|. This feature allows access to large |lig_kern| | |
> arrays, because the first instruction must otherwise | |
> appear in a location |<=255|. | |
> | |
> Any instruction with |skip_byte>128| in the |lig_kern| array must satisfy | |
> the condition | |
> $$\hbox{|256*op_byte+remainder<nl|.}$$ | |
> If such an instruction is encountered during | |
> normal program execution, it denotes an unconditional halt; no ligature | |
> or kerning command is performed. | |
> | |
> @d stop_flag==qi(128) {value indicating `\.{STOP}' in a lig/kern program} | |
> @d kern_flag==qi(128) {op code for a kern step} | |
> @d skip_byte(#)==#.b0 | |
8325c10527 | |
< @d op_bit(#)==#.b2 | |
--- | |
> @d op_byte(#)==#.b2 | |
8337,8338c10539,10540 | |
< $TR^kMR^kB$ from top to bottom, for some |k≥0|, unless $M$ is absent; | |
< in the latter case we can have $TR^kB$ for both even and odd values of@@|k|. | |
--- | |
> $TR^kMR^kB$ from top to bottom, for some |k>=0|, unless $M$ is absent; | |
> in the latter case we can have $TR^kB$ for both even and odd values of~|k|. | |
8354c10556 | |
< number; it is the only |fix_word| other than the design size itself that is | |
--- | |
> number; it's the only |fix_word| other than the design size itself that is | |
8358c10560 | |
< Note that character @'40 in the font need not have anything to do with | |
--- | |
> Note that character |" "| in the font need not have anything to do with | |
8392,8394c10594,10597 | |
< When the user defines \.{\\font 100}, say, \TeX\ assigns an | |
< internal number to the user's font 100. For example, if this internal number | |
< is 13, we will have |font_code[13]=100| and |font_number[100]=13|. | |
--- | |
> When the user defines \.{\\font\\f}, say, \TeX\ assigns an internal number | |
> to the user's font~\.{\\f}. Adding this number to |font_id_base| gives the | |
> |eqtb| location of a ``frozen'' control sequence that will always select | |
> the font. | |
8397d10599 | |
< @!user_font_code=0..bad_font_code; {font identification in \TeX\ input} | |
8398a10601 | |
> @!font_index=0..font_mem_size; {index into |font_info|} | |
8401a10605,10607 | |
> @d non_char==qi(256) {a |halfword| code that can't match a real character} | |
> @d non_address=0 {a spurious |bchar_label|} | |
> | |
8403,8405c10609,10611 | |
< @!font_info:array[0..font_mem_size] of memory_word; | |
< {the big collection of font data} | |
< @!fmem_ptr:0..font_mem_size; {first unused word of |font_info|} | |
--- | |
> @!font_info:array[font_index] of memory_word; | |
> {the big collection of font data} | |
> @!fmem_ptr:font_index; {first unused word of |font_info|} | |
8407,8410d10612 | |
< @!font_code:array[internal_font_number] of user_font_code; {the first user | |
< font code corresponding to an internal font number} | |
< @!font_number:array[user_font_code] of internal_font_number; {the internal | |
< font number corresponding to a user's font code} | |
8413,8416c10615,10617 | |
< @!font_scaled:array[internal_font_number] of boolean; {is the ``at'' size | |
< different from the design size?} | |
< @!font_params:array[internal_font_number] of halfword; {how many font | |
< parameters are present} | |
--- | |
> @!font_dsize:array[internal_font_number] of scaled; {``design'' size} | |
> @!font_params:array[internal_font_number] of font_index; {how many font | |
> parameters are present} | |
8419,8426c10620,10638 | |
< @!font_bc:array[internal_font_number] of eight_bits; {beginning (smallest) | |
< character code} | |
< @!font_ec:array[internal_font_number] of eight_bits; {ending (largest) | |
< character code} | |
< @!font_glue:array[internal_font_number] of pointer; {glue specification | |
< for interword space, |null| if not allocated} | |
< @!font_used:array[internal_font_number] of boolean; {has a character from | |
< this font actually appeared in the output?} | |
--- | |
> @!font_bc:array[internal_font_number] of eight_bits; | |
> {beginning (smallest) character code} | |
> @!font_ec:array[internal_font_number] of eight_bits; | |
> {ending (largest) character code} | |
> @!font_glue:array[internal_font_number] of pointer; | |
> {glue specification for interword space, |null| if not allocated} | |
> @!font_used:array[internal_font_number] of boolean; | |
> {has a character from this font actually appeared in the output?} | |
> @!hyphen_char:array[internal_font_number] of integer; | |
> {current \.{\\hyphenchar} values} | |
> @!skew_char:array[internal_font_number] of integer; | |
> {current \.{\\skewchar} values} | |
> @!bchar_label:array[internal_font_number] of font_index; | |
> {start of |lig_kern| program for left boundary character, | |
> |non_address| if there is none} | |
> @!font_bchar:array[internal_font_number] of min_quarterword..non_char; | |
> {right boundary character, |non_char| if there is none} | |
> @!font_false_bchar:array[internal_font_number] of min_quarterword..non_char; | |
> {|font_bchar| if it doesn't exist in the font, otherwise |non_char|} | |
8432,8435c10644,10647 | |
< part of this word (the |b0| field), |font_info[width_base[f]+w].sc| | |
< is the width of the character. (These formulas assume that |min_quarterword| | |
< has already been added to |c| and to |w|, since \TeX\ stores its | |
< quarterwords that way.) | |
--- | |
> part of this word (the |b0| field), the width of the character is | |
> |font_info[width_base[f]+w].sc|. (These formulas assume that | |
> |min_quarterword| has already been added to |c| and to |w|, since \TeX\ | |
> stores its quarterwords that way.) | |
8437c10649 | |
< @<Globals...@>= | |
--- | |
> @<Glob...@>= | |
8439c10651 | |
< {base addresses for |char_info|} | |
--- | |
> {base addresses for |char_info|} | |
8441c10653 | |
< {base addresses for widths} | |
--- | |
> {base addresses for widths} | |
8443c10655 | |
< {base addresses for heights} | |
--- | |
> {base addresses for heights} | |
8445c10657 | |
< {base addresses for depths} | |
--- | |
> {base addresses for depths} | |
8447c10659 | |
< {base addresses for italic corrections} | |
--- | |
> {base addresses for italic corrections} | |
8449c10661 | |
< {base addresses for ligature/kerning programs} | |
--- | |
> {base addresses for ligature/kerning programs} | |
8451c10663 | |
< {base addresses for kerns} | |
--- | |
> {base addresses for kerns} | |
8453c10665 | |
< {base addresses for extensible recipes} | |
--- | |
> {base addresses for extensible recipes} | |
8455c10667 | |
< {base addresses for font parameters} | |
--- | |
> {base addresses for font parameters} | |
8457,8458c10669,10670 | |
< @ In order to cope more easily with erroneous situations, the undefined font | |
< is assumed to have seven valid parameters, all equal to zero. | |
--- | |
> @ @<Set init...@>= | |
> for k:=font_base to font_max do font_used[k]:=false; | |
8460,8467c10672,10694 | |
< @<Set init...@>= | |
< for k←0 to bad_font_code do font_number[k]←undefined_font; | |
< font_ptr←font_base; fmem_ptr←7; font_code[undefined_font]←bad_font_code; | |
< font_bc[undefined_font]←1; font_ec[undefined_font]←0; | |
< font_glue[undefined_font]←zero_glue; font_params[undefined_font]←7; | |
< param_base[undefined_font]←-1; | |
< for k←0 to 6 do font_info[k].sc←0; | |
< for k←font_base to font_max do font_used[k]←false; | |
--- | |
> @ \TeX\ always knows at least one font, namely the null font. It has no | |
> characters, and its seven parameters are all equal to zero. | |
> | |
> @<Initialize table...@>= | |
> font_ptr:=null_font; fmem_ptr:=7; | |
> font_name[null_font]:="nullfont"; font_area[null_font]:=""; | |
> hyphen_char[null_font]:="-"; skew_char[null_font]:=-1; | |
> bchar_label[null_font]:=non_address; | |
> font_bchar[null_font]:=non_char; font_false_bchar[null_font]:=non_char; | |
> font_bc[null_font]:=1; font_ec[null_font]:=0; | |
> font_size[null_font]:=0; font_dsize[null_font]:=0; | |
> char_base[null_font]:=0; width_base[null_font]:=0; | |
> height_base[null_font]:=0; depth_base[null_font]:=0; | |
> italic_base[null_font]:=0; lig_kern_base[null_font]:=0; | |
> kern_base[null_font]:=0; exten_base[null_font]:=0; | |
> font_glue[null_font]:=null; font_params[null_font]:=7; | |
> param_base[null_font]:=-1; | |
> for k:=0 to 6 do font_info[k].sc:=0; | |
> | |
> @ @<Put each...@>= | |
> primitive("nullfont",set_font,null_font); | |
> @!@:null_font_}{\.{\\nullfont} primitive@> | |
> text(frozen_null_font):="nullfont"; eqtb[frozen_null_font]:=eqtb[cur_val]; | |
8475c10702 | |
< the character's width, so that the long formula above is at least | |
--- | |
> the character's width; hence the long formula above is at least | |
8493,8495c10720,10722 | |
< Access to a character's |height|, |depth|, and |tag| fields is part of | |
< \TeX's inner loop, so we want these macros to produce code that is as fast | |
< as possible under the circumstances. | |
--- | |
> Access to a character's |width|, |height|, |depth|, and |tag| fields is | |
> part of \TeX's inner loop, so we want these macros to produce code that is | |
> as fast as possible under the circumstances. | |
8503c10730 | |
< @d char_italic_end(#)==qo(#.b2) div 4].sc | |
--- | |
> @d char_italic_end(#)==(qo(#.b2)) div 4].sc | |
8506c10733 | |
< @d char_height_end(#)==# div 16].sc | |
--- | |
> @d char_height_end(#)==(#) div 16].sc | |
8508c10735 | |
< @d char_depth_end(#)==# mod 16].sc | |
--- | |
> @d char_depth_end(#)==(#) mod 16].sc | |
8510c10737 | |
< @d char_tag(#)==(qo(#.b2) mod 4) | |
--- | |
> @d char_tag(#)==((qo(#.b2)) mod 4) | |
8520,8521c10747,10748 | |
< null_character.b0←min_quarterword; null_character.b1←min_quarterword; | |
< null_character.b2←min_quarterword; null_character.b3←min_quarterword; | |
--- | |
> null_character.b0:=min_quarterword; null_character.b1:=min_quarterword; | |
> null_character.b2:=min_quarterword; null_character.b3:=min_quarterword; | |
8525c10752,10755 | |
< kerning command |j|. | |
--- | |
> kerning command~|j| in font~|f|. If |j| is the |char_info| for a character | |
> with a ligature/kern program, the first instruction of that program is either | |
> |i=font_info[lig_kern_start(f)(j)]| or |font_info[lig_kern_restart(f)(i)]|, | |
> depending on whether or not |skip_byte(i)<=stop_flag|. | |
8527,8528c10757,10761 | |
< @d lig_kern_start(#)==lig_kern_base[#]+rem_byte {beginning of lig/kern program} | |
< @d char_kern_end(#)==rem_byte(#)].sc | |
--- | |
> The constant |kern_base_offset| should be simplified, for \PASCAL\ compilers | |
> that do not do local optimization. | |
> @^system dependencies@> | |
> | |
> @d char_kern_end(#)==256*op_byte(#)+rem_byte(#)].sc | |
8529a10763,10766 | |
> @d kern_base_offset==256*(128+min_quarterword) | |
> @d lig_kern_start(#)==lig_kern_base[#]+rem_byte {beginning of lig/kern program} | |
> @d lig_kern_restart_end(#)==256*op_byte(#)+rem_byte(#)+32768-kern_base_offset | |
> @d lig_kern_restart(#)==lig_kern_base[#]+lig_kern_restart_end | |
8550,8554c10787,10793 | |
< is called |read_font_info|. It has four parameters: the user font code@@|u|, | |
< the file name and area strings |nom| and |aire|, and the ``at'' size@@|s|; | |
< if |s|@@is nonzero, |read_font_info| substitutes |s| for the design size. | |
< In the latter case, |s| must be positive and less than 2048 (i.e., | |
< it is less than $2^{27}$ when considered as an integer). | |
--- | |
> is called |read_font_info|. It has four parameters: the user font | |
> identifier~|u|, the file name and area strings |nom| and |aire|, and the | |
> ``at'' size~|s|. If |s|~is negative, it's the negative of a scale factor | |
> to be applied to the design size; |s=-1000| is the normal case. | |
> Otherwise |s| will be substituted for the design size; in this | |
> case, |s| must be positive and less than $2048\rm\,pt$ | |
> (i.e., it must be less than $2^{27}$ when considered as an integer). | |
8556a10796 | |
> It returns the value of the internal font number that was just loaded. | |
8558c10798 | |
< information is stored. | |
--- | |
> information is stored; |null_font| is returned in this case. | |
8563,8564c10803,10804 | |
< @p procedure read_font_info(@!u:user_font_code; | |
< @!nom,@!aire:str_number; @!s:scaled); {input a \.{TFM} file} | |
--- | |
> @p function read_font_info(@!u:pointer;@!nom,@!aire:str_number; | |
> @!s:scaled):internal_font_number; {input a \.{TFM} file} | |
8566c10806 | |
< var k:0..font_mem_size; {index into |font_info|} | |
--- | |
> var k:font_index; {index into |font_info|} | |
8569c10809 | |
< {sizes of subfiles} | |
--- | |
> {sizes of subfiles} | |
8570a10811 | |
> @!g:internal_font_number; {the number to return} | |
8572a10814,10815 | |
> @!bch_label:integer; {left boundary start location, or infinity} | |
> @!bchar:0..256; {right boundary character, or 256} | |
8575,8578c10818,10822 | |
< {auxiliary quantities used in fixed-point multiplication} | |
< begin @<Read and check the font data; |abort| if the \.{TFM} file is | |
< malformed; if there's no room for this font, say so and |goto | |
< done|; otherwise |incr(font_ptr)| and |goto done|@>; | |
--- | |
> {auxiliary quantities used in fixed-point multiplication} | |
> begin g:=null_font;@/ | |
> @<Read and check the font data; |abort| if the \.{TFM} file is | |
> malformed; if there's no room for this font, say so and |goto | |
> done|; otherwise |incr(font_ptr)| and |goto done|@>; | |
8580c10824,10825 | |
< done: b_close(tfm_file); | |
--- | |
> done: if file_opened then b_close(tfm_file); | |
> read_font_info:=g; | |
8590,8594c10835,10842 | |
< @d start_font_error_message==print_nl("! Font "); print_int(u); | |
< print_char("="); print_file_name(nom,aire,""); | |
< if s≠0 then | |
< begin print(" at "); print_scaled(s); print("pt"); | |
< end | |
--- | |
> @d start_font_error_message==print_err("Font "); sprint_cs(u); | |
> print_char("="); print_file_name(nom,aire,""); | |
> if s>=0 then | |
> begin print(" at "); print_scaled(s); print("pt"); | |
> end | |
> else if s<>-1000 then | |
> begin print(" scaled "); print_int(-s); | |
> end | |
8605c10853 | |
< ("e.g., type `I\font<same number>=<new name>'."); | |
--- | |
> ("e.g., type `I\font<same font id>=<substitute font name>'."); | |
8621c10869 | |
< file_opened←false; | |
--- | |
> file_opened:=false; | |
8624,8625c10872,10873 | |
< if not b_open_in(tfm_file) then goto bad_tfm; | |
< file_opened←true | |
--- | |
> if not b_open_in(tfm_file) then abort; | |
> file_opened:=true | |
8631c10879 | |
< for example by defining |fget| to be `\!|begin get(tfm_file);| | |
--- | |
> for example by defining |fget| to be `\ignorespaces|begin get(tfm_file);| | |
8637,8646c10885,10894 | |
< @d read_sixteen(#)==begin #←fbyte; | |
< if #>127 then abort; | |
< fget; #←#*@'400+fbyte; | |
< end | |
< @d store_four_quarters(#)==begin fget; a←fbyte; qw.b0←qi(a); | |
< fget; b←fbyte; qw.b1←qi(b); | |
< fget; c←fbyte; qw.b2←qi(c); | |
< fget; d←fbyte; qw.b3←qi(d); | |
< #←qw; | |
< end | |
--- | |
> @d read_sixteen(#)==begin #:=fbyte; | |
> if #>127 then abort; | |
> fget; #:=#*@'400+fbyte; | |
> end | |
> @d store_four_quarters(#)==begin fget; a:=fbyte; qw.b0:=qi(a); | |
> fget; b:=fbyte; qw.b1:=qi(b); | |
> fget; c:=fbyte; qw.b2:=qi(c); | |
> fget; d:=fbyte; qw.b3:=qi(d); | |
> #:=qw; | |
> end | |
8653c10901,10904 | |
< if (bc>ec+1)∨(ec>255) then abort; | |
--- | |
> if (bc>ec+1)or(ec>255) then abort; | |
> if bc>255 then {|bc=256| and |ec=255|} | |
> begin bc:=1; ec:=0; | |
> end; | |
8662c10913,10914 | |
< if lf≠6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np then abort; | |
--- | |
> if lf<>6+lh+(ec-bc+1)+nw+nh+nd+ni+nl+nk+ne+np then abort; | |
> if (nw=0)or(nh=0)or(nd=0)or(ni=0) then abort; | |
8665c10917 | |
< @ The preliminary settings of the index variables |char_base|, | |
--- | |
> @ The preliminary settings of the index-offset variables |char_base|, | |
8672,8685c10924,10937 | |
< lf←lf-6-lh; {|lf| words should be loaded into |font_info|} | |
< if np<7 then lf←lf+7-np; {at least seven parameters will appear} | |
< if (font_ptr=font_max)∨(fmem_ptr+lf>font_mem_size) then | |
< @<Apologize for not loading the font, |goto done|@>; | |
< f←font_ptr+1; | |
< char_base[f]←fmem_ptr-bc; | |
< width_base[f]←char_base[f]+ec+1; | |
< height_base[f]←width_base[f]+nw; | |
< depth_base[f]←height_base[f]+nh; | |
< italic_base[f]←depth_base[f]+nd; | |
< lig_kern_base[f]←italic_base[f]+ni; | |
< kern_base[f]←lig_kern_base[f]+nl; | |
< exten_base[f]←kern_base[f]+nk; | |
< param_base[f]←exten_base[f]+ne | |
--- | |
> lf:=lf-6-lh; {|lf| words should be loaded into |font_info|} | |
> if np<7 then lf:=lf+7-np; {at least seven parameters will appear} | |
> if (font_ptr=font_max)or(fmem_ptr+lf>font_mem_size) then | |
> @<Apologize for not loading the font, |goto done|@>; | |
> f:=font_ptr+1; | |
> char_base[f]:=fmem_ptr-bc; | |
> width_base[f]:=char_base[f]+ec+1; | |
> height_base[f]:=width_base[f]+nw; | |
> depth_base[f]:=height_base[f]+nh; | |
> italic_base[f]:=depth_base[f]+nd; | |
> lig_kern_base[f]:=italic_base[f]+ni; | |
> kern_base[f]:=lig_kern_base[f]+nl-kern_base_offset; | |
> exten_base[f]:=kern_base[f]+kern_base_offset+nk; | |
> param_base[f]:=exten_base[f]+ne | |
8689c10941 | |
< print(" not loaded: No more room."); | |
--- | |
> print(" not loaded: Not enough room left"); | |
8694c10946 | |
< ("Or maybe try `I\font<same number>=<name of loaded font>'."); | |
--- | |
> ("Or maybe try `I\font<same font id>=<name of loaded font>'."); | |
8704c10956 | |
< fget; z←z*@'400+fbyte; fget; z←(z*@'20)+(fbyte div@'20); | |
--- | |
> fget; z:=z*@'400+fbyte; fget; z:=(z*@'20)+(fbyte div@'20); | |
8707,8713c10959,10965 | |
< begin fget;fget;fget;fget;decr(lh); {ignore the rest of the header} | |
< end; | |
< if s=0 then font_scaled[f]←false | |
< else if z=s then font_scaled[f]←false | |
< else begin font_scaled[f]←true; z←s; | |
< end; | |
< font_size[f]←z; | |
--- | |
> begin fget;fget;fget;fget;decr(lh); {ignore the rest of the header} | |
> end; | |
> font_dsize[f]:=z; | |
> if s<>-1000 then | |
> if s>=0 then z:=s | |
> else z:=xn_over_d(z,-s,1000); | |
> font_size[f]:=z; | |
8717,8727c10969,10979 | |
< for k←fmem_ptr to width_base[f]-1 do | |
< begin store_four_quarters(font_info[k].qqqq); | |
< if (a≥nw)∨(b div @'20≥nh)∨(b mod @'20≥nd)∨ | |
< (c div 4≥ni) then abort; | |
< case c mod 4 of | |
< lig_tag: if d≥nl then abort; | |
< ext_tag: if d≥ne then abort; | |
< list_tag: @<Check for charlist cycle@>; | |
< othercases do_nothing {|no_tag|} | |
< endcases; | |
< end | |
--- | |
> for k:=fmem_ptr to width_base[f]-1 do | |
> begin store_four_quarters(font_info[k].qqqq); | |
> if (a>=nw)or(b div @'20>=nh)or(b mod @'20>=nd)or | |
> (c div 4>=ni) then abort; | |
> case c mod 4 of | |
> lig_tag: if d>=nl then abort; | |
> ext_tag: if d>=ne then abort; | |
> list_tag: @<Check for charlist cycle@>; | |
> othercases do_nothing {|no_tag|} | |
> endcases; | |
> end | |
8734c10986 | |
< @d check_byte_range(#)==begin if (#<bc)∨(#>ec) then abort@+end | |
--- | |
> @d check_byte_range(#)==begin if (#<bc)or(#>ec) then abort@+end | |
8740,8744c10992,10996 | |
< begin qw←char_info(f)(d); | |
< {N.B.: not |qi(d)|, since |char_base[f]| hasn't been adjusted yet} | |
< if char_tag(qw)≠list_tag then goto not_found; | |
< d←qo(rem_byte(qw)); {next character on the list} | |
< end; | |
--- | |
> begin qw:=char_info(f)(d); | |
> {N.B.: not |qi(d)|, since |char_base[f]| hasn't been adjusted yet} | |
> if char_tag(qw)<>list_tag then goto not_found; | |
> d:=qo(rem_byte(qw)); {next character on the list} | |
> end; | |
8750c11002 | |
< $$x=\left\{\vcenter{\halign{\lft{$#$,}\qquad&if \lft{$#$}\cr | |
--- | |
> $$x=\left\{\vcenter{\halign{$#$,\hfil\qquad&if $#$\hfil\cr | |
8753c11005 | |
< (No other choices of $a$ are allowed, since the magnitude of a number in | |
--- | |
> (No other choices of |a| are allowed, since the magnitude of a number in | |
8755,8756c11007,11008 | |
< quantity by the integer@@|z|, which is known to be less than $2^{27}$. Let | |
< $\alpha=16z$. If $|z|<2^{23}$, the individual multiplications $b\cdot z$, | |
--- | |
> quantity by the integer~|z|, which is known to be less than $2^{27}$. | |
> If $|z|<2^{23}$, the individual multiplications $b\cdot z$, | |
8762c11014 | |
< if $a=0$, or the same quantity minus $\alpha$ if $a=255$. | |
--- | |
> if $a=0$, or the same quantity minus $\alpha=2^{4+e}z^\prime$ if $a=255$. | |
8766,8770c11018,11022 | |
< @d store_scaled(#)==begin fget; a←fbyte; fget; b←fbyte; | |
< fget; c←fbyte; fget; d←fbyte;@/ | |
< sw←(((((d*z)div@'400)+(c*z))div@'400)+(b*z))div beta; | |
< if a=0 then #←sw@+else if a=255 then #←sw-alpha@+else abort; | |
< end | |
--- | |
> @d store_scaled(#)==begin fget; a:=fbyte; fget; b:=fbyte; | |
> fget; c:=fbyte; fget; d:=fbyte;@/ | |
> sw:=(((((d*z)div@'400)+(c*z))div@'400)+(b*z))div beta; | |
> if a=0 then #:=sw@+else if a=255 then #:=sw-alpha@+else abort; | |
> end | |
8774,8779c11026,11031 | |
< for k←width_base[f] to lig_kern_base[f]-1 do | |
< store_scaled(font_info[k].sc); | |
< if font_info[width_base[f]].sc≠0 then abort; {\\{width}[0] must be zero} | |
< if font_info[height_base[f]].sc≠0 then abort; {\\{height}[0] must be zero} | |
< if font_info[depth_base[f]].sc≠0 then abort; {\\{depth}[0] must be zero} | |
< if font_info[italic_base[f]].sc≠0 then abort; {\\{italic}[0] must be zero} | |
--- | |
> for k:=width_base[f] to lig_kern_base[f]-1 do | |
> store_scaled(font_info[k].sc); | |
> if font_info[width_base[f]].sc<>0 then abort; {\\{width}[0] must be zero} | |
> if font_info[height_base[f]].sc<>0 then abort; {\\{height}[0] must be zero} | |
> if font_info[depth_base[f]].sc<>0 then abort; {\\{depth}[0] must be zero} | |
> if font_info[italic_base[f]].sc<>0 then abort; {\\{italic}[0] must be zero} | |
8783,8799c11035,11066 | |
< begin alpha←16*z; beta←16; | |
< while z≥@'40000000 do | |
< begin z←z div 2; beta←beta div 2; | |
< end; | |
< end | |
< | |
< @ @<Read ligature/kern program@>= | |
< begin for k←lig_kern_base[f] to kern_base[f]-1 do | |
< begin store_four_quarters(font_info[k].qqqq); | |
< check_byte_range(b); | |
< if c<kern_flag then check_byte_range(d) | |
< else if d≥nk then abort; | |
< end; | |
< if (nl>0)∧(a<stop_flag) then abort; {check for stop bit on last command} | |
< for k←kern_base[f] to exten_base[f]-1 do | |
< store_scaled(font_info[k].sc); | |
< end | |
--- | |
> begin alpha:=16; | |
> while z>=@'40000000 do | |
> begin z:=z div 2; alpha:=alpha+alpha; | |
> end; | |
> beta:=256 div alpha; alpha:=alpha*z; | |
> end | |
> | |
> @ @d check_existence(#)==@t@>@;@/ | |
> begin check_byte_range(#); | |
> qw:=char_info(f)(#); {N.B.: not |qi(#)|} | |
> if not char_exists(qw) then abort; | |
> end | |
> | |
> @<Read ligature/kern program@>= | |
> bch_label:=@'77777; bchar:=256; | |
> if nl>0 then | |
> begin for k:=lig_kern_base[f] to kern_base[f]+kern_base_offset-1 do | |
> begin store_four_quarters(font_info[k].qqqq); | |
> if a>128 then | |
> begin if 256*c+d>=nl then abort; | |
> if a=255 then if k=lig_kern_base[f] then bchar:=b; | |
> end | |
> else begin if b<>bchar then check_existence(b); | |
> if c<128 then check_existence(d) {check ligature} | |
> else if 256*(c-128)+d>=nk then abort; {check kern} | |
> if a<128 then if k-lig_kern_base[f]+a+1>=nl then abort; | |
> end; | |
> end; | |
> if a=255 then bch_label:=256*c+d; | |
> end; | |
> for k:=kern_base[f]+kern_base_offset to exten_base[f]-1 do | |
> store_scaled(font_info[k].sc); | |
8802,8808c11069,11075 | |
< for k←exten_base[f] to param_base[f]-1 do | |
< begin store_four_quarters(font_info[k].qqqq); | |
< if a≠0 then check_byte_range(a); | |
< if b≠0 then check_byte_range(b); | |
< if c≠0 then check_byte_range(c); | |
< check_byte_range(d); | |
< end | |
--- | |
> for k:=exten_base[f] to param_base[f]-1 do | |
> begin store_four_quarters(font_info[k].qqqq); | |
> if a<>0 then check_existence(a); | |
> if b<>0 then check_existence(b); | |
> if c<>0 then check_existence(c); | |
> check_existence(d); | |
> end | |
8814,8821c11081,11088 | |
< begin for k←1 to np do | |
< if k=1 then {the |slant| parameter is a pure number} | |
< begin fget; sw←fbyte; if sw>127 then sw←sw-256; | |
< fget; sw←sw*@'400+fbyte; fget; sw←sw*@'400+fbyte; | |
< fget; font_info[param_base[f]].sc← | |
< (sw*@'20)+(fbyte div@'20); | |
< end | |
< else store_scaled(font_info[param_base[f]+k-1].sc); | |
--- | |
> begin for k:=1 to np do | |
> if k=1 then {the |slant| parameter is a pure number} | |
> begin fget; sw:=fbyte; if sw>127 then sw:=sw-256; | |
> fget; sw:=sw*@'400+fbyte; fget; sw:=sw*@'400+fbyte; | |
> fget; font_info[param_base[f]].sc:= | |
> (sw*@'20)+(fbyte div@'20); | |
> end | |
> else store_scaled(font_info[param_base[f]+k-1].sc); | |
8823c11090 | |
< for k←np+1 to 7 do font_info[param_base[f]+k-1].sc←0; | |
--- | |
> for k:=np+1 to 7 do font_info[param_base[f]+k-1].sc:=0; | |
8830,8831c11097,11098 | |
< @d adjust(#)==#[f]←qo(#[f]) | |
< {correct for the excess |min_quarterword| that was added} | |
--- | |
> @d adjust(#)==#[f]:=qo(#[f]) | |
> {correct for the excess |min_quarterword| that was added} | |
8834,8838c11101,11113 | |
< font_code[f]←u; font_number[u]←f; | |
< if np≥7 then font_params[f]←np@+else font_params[f]←7; | |
< font_name[f]←nom; | |
< font_area[f]←aire; | |
< font_bc[f]←bc; font_ec[f]←ec; font_glue[f]←null; | |
--- | |
> if np>=7 then font_params[f]:=np@+else font_params[f]:=7; | |
> hyphen_char[f]:=default_hyphen_char; skew_char[f]:=default_skew_char; | |
> if bch_label<nl then bchar_label[f]:=bch_label+lig_kern_base[f] | |
> else bchar_label[f]:=non_address; | |
> font_bchar[f]:=qi(bchar); | |
> font_false_bchar[f]:=qi(bchar); | |
> if bchar<=ec then if bchar>=bc then | |
> begin qw:=char_info(f)(bchar); {N.B.: not |qi(bchar)|} | |
> if char_exists(qw) then font_false_bchar[f]:=non_char; | |
> end; | |
> font_name[f]:=nom; | |
> font_area[f]:=aire; | |
> font_bc[f]:=bc; font_ec[f]:=ec; font_glue[f]:=null; | |
8842c11117 | |
< fmem_ptr←fmem_ptr+lf; font_ptr←f; goto done | |
--- | |
> fmem_ptr:=fmem_ptr+lf; font_ptr:=f; g:=f; goto done | |
8847,8848c11122,11123 | |
< @<Declare procedures that scan restricted classes of integers@>= | |
< procedure scan_font_number; | |
--- | |
> @<Declare procedures that scan font-related stuff@>= | |
> procedure scan_font_ident; | |
8850,8866c11125,11139 | |
< begin scan_int; | |
< if (cur_val<0)∨(cur_val≥bad_font_code) then f←undefined_font | |
< else f←font_number[cur_val]; | |
< if f=undefined_font then | |
< begin print_nl("! Undefined font code"); | |
< @.Undefined font code@> | |
< help3("Watch out---you must define a font code before you")@/ | |
< ("try to use the font, so you may have to start over.")@/ | |
< ("(Chapter 27 of the manual explains how to survive this.)"); | |
< int_error(cur_val); | |
< end; | |
< cur_val←f; | |
< end; | |
< | |
< @ The following routine is used to implement `\.{\\texinfo} |m| |n|'. If | |
< font |m| is undefined, no error message is needed since |scan_font_number| | |
< will have already issued one. | |
--- | |
> @!m:halfword; | |
> begin @<Get the next non-blank non-call...@>; | |
> if cur_cmd=def_font then f:=cur_font | |
> else if cur_cmd=set_font then f:=cur_chr | |
> else if cur_cmd=def_family then | |
> begin m:=cur_chr; scan_four_bit_int; f:=equiv(m+cur_val); | |
> end | |
> else begin print_err("Missing font identifier"); | |
> @.Missing font identifier@> | |
> help2("I was looking for a control sequence whose")@/ | |
> ("current meaning has been defined by \font."); | |
> back_error; f:=null_font; | |
> end; | |
> cur_val:=f; | |
> end; | |
8867a11141 | |
> @ The following routine is used to implement `\.{\\fontdimen} |n| |f|'. | |
8871,8873c11145,11147 | |
< @<Declare procedures that scan restricted classes of integers@>= | |
< procedure scan_tex_info(@!writing:boolean); | |
< {sets |cur_val| to |font_info| location} | |
--- | |
> @<Declare procedures that scan font-related stuff@>= | |
> procedure find_font_dimen(@!writing:boolean); | |
> {sets |cur_val| to |font_info| location} | |
8875,8889c11149,11162 | |
< begin scan_font_number; f←cur_val; scan_int; | |
< if f=undefined_font then cur_val←fmem_ptr {a harmless location} | |
< else begin if cur_val≤0 then cur_val←fmem_ptr | |
< else begin if writing ∧(cur_val≤space_shrink_code)∧@| | |
< (cur_val≥space_code)∧(font_glue[f]≠null) then | |
< begin delete_glue_ref(font_glue[f]); | |
< font_glue[f]←null; | |
< end; | |
< if cur_val>font_params[f] then | |
< if f<font_ptr then cur_val←fmem_ptr | |
< else @<Increase the number of parameters in the last font@> | |
< else cur_val←cur_val+param_base[f]; | |
< end; | |
< @<Issue an error message if |cur_val=fmem_ptr|@>; | |
< end; | |
--- | |
> @!n:integer; {the parameter number} | |
> begin scan_int; n:=cur_val; scan_font_ident; f:=cur_val; | |
> if n<=0 then cur_val:=fmem_ptr | |
> else begin if writing and(n<=space_shrink_code)and@| | |
> (n>=space_code)and(font_glue[f]<>null) then | |
> begin delete_glue_ref(font_glue[f]); | |
> font_glue[f]:=null; | |
> end; | |
> if n>font_params[f] then | |
> if f<font_ptr then cur_val:=fmem_ptr | |
> else @<Increase the number of parameters in the last font@> | |
> else cur_val:=n+param_base[f]; | |
> end; | |
> @<Issue an error message if |cur_val=fmem_ptr|@>; | |
8894,8900c11167,11174 | |
< begin help2("To increase the number of font parameters, you must")@/ | |
< ("use \texinfo immediately after the font code is defined."); | |
< print_nl("! Font "); print_int(font_code[f]); | |
< @.Font x has n texinfo...@> | |
< print(" has "); print_int(font_params[f]); | |
< print(" texinfo parameters"); error; | |
< end | |
--- | |
> begin print_err("Font "); print_esc(font_id_text(f)); | |
> print(" has only "); print_int(font_params[f]); | |
> print(" fontdimen parameters"); | |
> @.Font x has only...@> | |
> help2("To increase the number of font parameters, you must")@/ | |
> ("use \fontdimen immediately after the \font is loaded."); | |
> error; | |
> end | |
8903,8905c11177,11183 | |
< repeat if fmem_ptr=font_mem_size then overflow("font memory",font_mem_size); | |
< font_info[fmem_ptr].sc←0; incr(fmem_ptr); incr(font_params[f]); | |
< until cur_val=font_params[f] | |
--- | |
> begin repeat if fmem_ptr=font_mem_size then | |
> overflow("font memory",font_mem_size); | |
> @:TeX capacity exceeded font memory}{\quad font memory@> | |
> font_info[fmem_ptr].sc:=0; incr(fmem_ptr); incr(font_params[f]); | |
> until n=font_params[f]; | |
> cur_val:=fmem_ptr-1; {this equals |param_base[f]+font_params[f]|} | |
> end | |
8909c11187 | |
< that characters exist when it sees them. The following procedure | |
--- | |
> that characters exist when it sees them. The following procedure | |
8913,8915c11191,11193 | |
< begin if tracing_lost_chars≠0 then | |
< begin begin_diagnostic; | |
< print_nl("Missing character: There is no "); | |
--- | |
> begin if tracing_lost_chars>0 then | |
> begin begin_diagnostic; | |
> print_nl("Missing character: There is no "); | |
8917,8919c11195,11197 | |
< print_ascii(c); print(" in font "); | |
< print(font_name[f]); print_char("!"); end_diagnostic; | |
< end; | |
--- | |
> print_ASCII(c); print(" in font "); | |
> slow_print(font_name[f]); print_char("!"); end_diagnostic(false); | |
> end; | |
8929,8933c11207,11211 | |
< begin if (font_bc[f]≤c)∧(font_ec[f]≥c) then | |
< if char_exists(char_info(f)(qi(c))) then | |
< begin p←get_avail; font(p)←f; character(p)←qi(c); | |
< new_character←p; return; | |
< end; | |
--- | |
> begin if font_bc[f]<=c then if font_ec[f]>=c then | |
> if char_exists(char_info(f)(qi(c))) then | |
> begin p:=get_avail; font(p):=f; character(p):=qi(c); | |
> new_character:=p; return; | |
> end; | |
8935c11213 | |
< new_character←null; | |
--- | |
> new_character:=null; | |
8937,8938c11215,11217 | |
< @* \[30] Device-independent file format. | |
< The most important output pro\-duced by a run of \TeX\ is the ``device | |
--- | |
> | |
> @* \[31] Device-independent file format. | |
> The most important output produced by a run of \TeX\ is the ``device | |
8941c11220 | |
< David R. Fuchs in 1979. Almost any reasonable device can be driven by | |
--- | |
> David R. Fuchs in 1979. Almost any reasonable typesetting device can be | |
8944c11223 | |
< a program that takes \.{DVI} files as input, and dozens of such | |
--- | |
> driven by a program that takes \.{DVI} files as input, and dozens of such | |
8959c11238,11239 | |
< $-2^{15}$ and $2^{15}-1$. | |
--- | |
> $-2^{15}$ and $2^{15}-1$. As in \.{TFM} files, numbers that occupy | |
> more than one byte position appear in BigEndian order. | |
8961,8969c11241,11252 | |
< A \.{DVI} file consists of a sequence of one or more ``pages,'' followed by | |
< a ``postamble.'' A ``page'' consists of a |bop| command, followed by any number | |
< of other commands that tell where characters are to be placed on a physical | |
< page, followed by an |eop| command. The pages appear in the order that \TeX\ | |
< generated them. If we ignore |nop| commands (which are allowed between | |
< any two commands in the file), each |eop| command is immediately followed by | |
< a |bop| command, or by a |pst| command; in the latter case, there are no | |
< more pages in the file, and the remaining bytes form the postamble. | |
< Further details about the postamble will be explained later. | |
--- | |
> A \.{DVI} file consists of a ``preamble,'' followed by a sequence of one | |
> or more ``pages,'' followed by a ``postamble.'' The preamble is simply a | |
> |pre| command, with its parameters that define the dimensions used in the | |
> file; this must come first. Each ``page'' consists of a |bop| command, | |
> followed by any number of other commands that tell where characters are to | |
> be placed on a physical page, followed by an |eop| command. The pages | |
> appear in the order that \TeX\ generated them. If we ignore |nop| commands | |
> and \\{fnt\_def} commands (which are allowed between any two commands in | |
> the file), each |eop| command is immediately followed by a |bop| command, | |
> or by a |post| command; in the latter case, there are no more pages in the | |
> file, and the remaining bytes form the postamble. Further details about | |
> the postamble will be explained later. | |
8973c11256 | |
< the first byte is number@@0, then comes number@@1, and so on. For example, | |
--- | |
> the first byte is number~0, then comes number~1, and so on. For example, | |
8975,8980c11258,11264 | |
< this makes it feasible to read the pages in backwards order, in case you | |
< are producing output on devices that stack their output face up. If the | |
< first page on a \.{DVI} file occupies bytes 0 to 99, and if the second | |
< page occupies bytes 100 to 299, then the |bop| that starts in byte 100 | |
< points to 0 and the |bop| thats starts in byte 300 points to 100. (The | |
< first |bop|, i.e., the one that starts in byte 0, has a pointer of $-1$.) | |
--- | |
> this makes it feasible to read the pages in backwards order, in case the | |
> results are being directed to a device that stacks its output face up. | |
> Suppose the preamble of a \.{DVI} file occupies bytes 0 to 99. Now if the | |
> first page occupies bytes 100 to 999, say, and if the second | |
> page occupies bytes 1000 to 1999, then the |bop| that starts in byte 1000 | |
> points to 100 and the |bop| that starts in byte 2000 points to 1000. (The | |
> very first |bop|, i.e., the one starting in byte 100, has a pointer of~$-1$.) | |
8984,8985c11268,11269 | |
< implicit instead of explicit; when a \.{DVI}-reading program reads the | |
< commands for a page, it keeps track of several quantities: (a)@@The current | |
--- | |
> implicit instead of explicit. When a \.{DVI}-reading program reads the | |
> commands for a page, it keeps track of several quantities: (a)~The current | |
8987c11271 | |
< by \\{fnt} and \\{fnt\_num} commands. (b)@@The current position on the page | |
--- | |
> by \\{fnt} and \\{fnt\_num} commands. (b)~The current position on the page | |
8993c11277 | |
< flipped; the Cartesian version of |(h,v)| would be |(h,-v)|. (c)@@The | |
--- | |
> flipped; the Cartesian version of |(h,v)| would be |(h,-v)|. (c)~The | |
8995,8996c11279,11280 | |
< where |w| and@@|x| are used for horizontal spacing and where |y| and@@|z| | |
< are used for vertical spacing. (d)@@There is a stack containing | |
--- | |
> where |w| and~|x| are used for horizontal spacing and where |y| and~|z| | |
> are used for vertical spacing. (d)~There is a stack containing | |
8998c11282 | |
< change the current level of operation. Note that the current font@@|f| is | |
--- | |
> change the current level of operation. Note that the current font~|f| is | |
9004c11288 | |
< there is a small unit of measurement such that increasing |h| by@@1 means | |
--- | |
> there is a small unit of measurement such that increasing |h| by~1 means | |
9010,9012c11294,11296 | |
< @ Here is list of all the commands that may appear in a \.{DVI} file. With | |
< each command we give its symbolic name (e.g., |bop|), its opcode byte | |
< (e.g., 129), and its parameters (if any). The parameters are followed | |
--- | |
> @ Here is a list of all the commands that may appear in a \.{DVI} file. Each | |
> command is specified by its symbolic name (e.g., |bop|), its opcode byte | |
> (e.g., 139), and its parameters (if any). The parameters are followed | |
9016c11300 | |
< \yskip\hang|set_char_0| 0. Typeset character number@@0 from font@@|f| | |
--- | |
> \yskip\hang|set_char_0| 0. Typeset character number~0 from font~|f| | |
9022,9024c11306,11308 | |
< \yskip\hang|set_char_1| through |set_char_127| (opcodes 1 to 127). | |
< Do the operations of |set_char_0|, but use the appropriate character number | |
< instead of char\-acter@@0. | |
--- | |
> \yskip\hang\\{set\_char\_1} through \\{set\_char\_127} (opcodes 1 to 127). | |
> Do the operations of |set_char_0|; but use the character whose number | |
> matches the opcode, instead of character~0. | |
9027,9028c11311,11312 | |
< number@@|c| is typeset. \TeX82 uses this command for characters in the | |
< range |128≤c<256|. | |
--- | |
> number~|c| is typeset. \TeX82 uses this command for characters in the | |
> range |128<=c<256|. | |
9030,9031c11314,11315 | |
< \yskip\hang|set2| 129 |c[2]|. Same as |set1|, except that@@|c| is two | |
< bytes long, so it is in the range |0≤c<65536|. \TeX82 never uses this | |
--- | |
> \yskip\hang|@!set2| 129 |c[2]|. Same as |set1|, except that |c|~is two | |
> bytes long, so it is in the range |0<=c<65536|. \TeX82 never uses this | |
9036c11320 | |
< \yskip\hang|set3| 130 |c[3]|. Same as |set1|, except that@@|c| is three | |
--- | |
> \yskip\hang|@!set3| 130 |c[3]|. Same as |set1|, except that |c|~is three | |
9041c11325 | |
< \yskip\hang|set4| 131 |c[4]|. Same as |set1|, except that@@|c| is four | |
--- | |
> \yskip\hang|@!set4| 131 |c[4]|. Same as |set1|, except that |c|~is four | |
9045,9046c11329,11330 | |
< of height@@|a| and width@@|b|, with its bottom left corner at |(h,v)|. Then | |
< set |h←h+b|. If either |a≤0| or |b≤0|, nothing should be typeset. Note | |
--- | |
> of height~|a| and width~|b|, with its bottom left corner at |(h,v)|. Then | |
> set |h:=h+b|. If either |a<=0| or |b<=0|, nothing should be typeset. Note | |
9051c11335 | |
< \yskip\hang|put1| 133 |c[1]|. Typeset character number@@|c| from font@@|f| | |
--- | |
> \yskip\hang|@!put1| 133 |c[1]|. Typeset character number~|c| from font~|f| | |
9056c11340 | |
< \yskip\hang|put2| 134 |c[2]|. Same as |set2|, except that |h| is not changed. | |
--- | |
> \yskip\hang|@!put2| 134 |c[2]|. Same as |set2|, except that |h| is not changed. | |
9058c11342 | |
< \yskip\hang|put3| 135 |c[3]|. Same as |set3|, except that |h| is not changed. | |
--- | |
> \yskip\hang|@!put3| 135 |c[3]|. Same as |set3|, except that |h| is not changed. | |
9060c11344 | |
< \yskip\hang|put4| 136 |c[4]|. Same as |set4|, except that |h| is not changed. | |
--- | |
> \yskip\hang|@!put4| 136 |c[4]|. Same as |set4|, except that |h| is not changed. | |
9069,9071c11353,11355 | |
< \yskip\hang|bop| 139 $c↓0[4]$ $c↓1[4]$ $\ldots$ $c↓9[4]$ $p[4]$. Beginning | |
< of a page: Set |(h,v,w,x,y,z)←(0,0,0,0,0,0)| and set the stack empty. Set | |
< the current font |f| to an undefined value. The ten $c↓i$ parameters hold | |
--- | |
> \yskip\hang|bop| 139 $c_0[4]$ $c_1[4]$ $\ldots$ $c_9[4]$ $p[4]$. Beginning | |
> of a page: Set |(h,v,w,x,y,z):=(0,0,0,0,0,0)| and set the stack empty. Set | |
> the current font |f| to an undefined value. The ten $c_i$ parameters hold | |
9075c11359 | |
< |p| points to the previous |bop| command in the file, where the first | |
--- | |
> |p| points to the previous |bop| in the file; the first | |
9083c11367 | |
< |h|@@coordinate; so it usually needs to be sorted into some order that is | |
--- | |
> |h|~coordinate; so it usually needs to be sorted into some order that is | |
9095,9097c11379,11381 | |
< \yskip\hang|right1| 143 |b[1]|. Set |h←h+b|, i.e., move right |b| units. | |
< The parameter is a signed number in two's complement notation, |-128≤b<128|; | |
< if |b<0|, the reference point actually moves left. | |
--- | |
> \yskip\hang|right1| 143 |b[1]|. Set |h:=h+b|, i.e., move right |b| units. | |
> The parameter is a signed number in two's complement notation, |-128<=b<128|; | |
> if |b<0|, the reference point moves left. | |
9100c11384 | |
< two-byte quantity in the range |-32768≤b<32768|. | |
--- | |
> two-byte quantity in the range |-32768<=b<32768|. | |
9103c11387 | |
< three-byte quantity in the range |@t$-2^{23}$@>≤b<@t$2^{23}$@>|. | |
--- | |
> three-byte quantity in the range |@t$-2^{23}$@><=b<@t$2^{23}$@>|. | |
9106c11390 | |
< four-byte quantity in the range |@t$-2^{31}$@>≤b<@t$2^{31}$@>|. | |
--- | |
> four-byte quantity in the range |@t$-2^{31}$@><=b<@t$2^{31}$@>|. | |
9108c11392 | |
< \yskip\hang|w0| 147. Set |h←h+w|; i.e., move right |w| units. With luck, | |
--- | |
> \yskip\hang|w0| 147. Set |h:=h+w|; i.e., move right |w| units. With luck, | |
9113,9115c11397,11399 | |
< \yskip\hang|w1| 148 |b[1]|. Set |w←b| and |h←h+b|. The value of |b| is a | |
< signed quantity in two's complement notation, |-128≤b<128|. This command | |
< changes the current |w|@@spacing and moves right by |b|. | |
--- | |
> \yskip\hang|w1| 148 |b[1]|. Set |w:=b| and |h:=h+b|. The value of |b| is a | |
> signed quantity in two's complement notation, |-128<=b<128|. This command | |
> changes the current |w|~spacing and moves right by |b|. | |
9117,9118c11401,11402 | |
< \yskip\hang|w2| 149 |b[2]|. Same as |w1|, but |b| is two bytes long, | |
< |-32768≤b<32768|. | |
--- | |
> \yskip\hang|@!w2| 149 |b[2]|. Same as |w1|, but |b| is two bytes long, | |
> |-32768<=b<32768|. | |
9120,9121c11404,11405 | |
< \yskip\hang|w3| 150 |b[3]|. Same as |w1|, but |b| is three bytes long, | |
< |@t$-2^{23}$@>≤b<@t$2^{23}$@>|. | |
--- | |
> \yskip\hang|@!w3| 150 |b[3]|. Same as |w1|, but |b| is three bytes long, | |
> |@t$-2^{23}$@><=b<@t$2^{23}$@>|. | |
9123,9124c11407,11408 | |
< \yskip\hang|w4| 151 |b[4]|. Same as |w1|, but |b| is four bytes long, | |
< |@t$-2^{31}$@>≤b<@t$2^{31}$@>|. | |
--- | |
> \yskip\hang|@!w4| 151 |b[4]|. Same as |w1|, but |b| is four bytes long, | |
> |@t$-2^{31}$@><=b<@t$2^{31}$@>|. | |
9126c11410 | |
< \yskip\hang|x0| 152. Set |h←h+x|; i.e., move right |x| units. The `|x|' | |
--- | |
> \yskip\hang|x0| 152. Set |h:=h+x|; i.e., move right |x| units. The `|x|' | |
9130,9132c11414,11416 | |
< \yskip\hang|x1| 153 |b[1]|. Set |x←b| and |h←h+b|. The value of |b| is a | |
< signed quantity in two's complement notation, |-128≤b<128|. This command | |
< changes the current |x|@@spacing and moves right by |b|. | |
--- | |
> \yskip\hang|x1| 153 |b[1]|. Set |x:=b| and |h:=h+b|. The value of |b| is a | |
> signed quantity in two's complement notation, |-128<=b<128|. This command | |
> changes the current |x|~spacing and moves right by |b|. | |
9134,9135c11418,11419 | |
< \yskip\hang|x2| 154 |b[2]|. Same as |x1|, but |b| is two bytes long, | |
< |-32768≤b<32768|. | |
--- | |
> \yskip\hang|@!x2| 154 |b[2]|. Same as |x1|, but |b| is two bytes long, | |
> |-32768<=b<32768|. | |
9137,9138c11421,11422 | |
< \yskip\hang|x3| 155 |b[3]|. Same as |x1|, but |b| is three bytes long, | |
< |@t$-2^{23}$@>≤b<@t$2^{23}$@>|. | |
--- | |
> \yskip\hang|@!x3| 155 |b[3]|. Same as |x1|, but |b| is three bytes long, | |
> |@t$-2^{23}$@><=b<@t$2^{23}$@>|. | |
9140,9141c11424,11425 | |
< \yskip\hang|x4| 156 |b[4]|. Same as |x1|, but |b| is four bytes long, | |
< |@t$-2^{31}$@>≤b<@t$2^{31}$@>|. | |
--- | |
> \yskip\hang|@!x4| 156 |b[4]|. Same as |x1|, but |b| is four bytes long, | |
> |@t$-2^{31}$@><=b<@t$2^{31}$@>|. | |
9143,9145c11427,11429 | |
< \yskip\hang|down1| 157 |a[1]|. Set |v←v+a|, i.e., move down |a| units. | |
< The parameter is a signed number in two's complement notation, |-128≤a<128|; | |
< if |a<0|, the reference point actually moves up. | |
--- | |
> \yskip\hang|down1| 157 |a[1]|. Set |v:=v+a|, i.e., move down |a| units. | |
> The parameter is a signed number in two's complement notation, |-128<=a<128|; | |
> if |a<0|, the reference point moves up. | |
9147,9148c11431,11432 | |
< \yskip\hang|down2| 158 |a[2]|. Same as |down1|, except that |a| is a | |
< two-byte quantity in the range |-32768≤a<32768|. | |
--- | |
> \yskip\hang|@!down2| 158 |a[2]|. Same as |down1|, except that |a| is a | |
> two-byte quantity in the range |-32768<=a<32768|. | |
9150,9151c11434,11435 | |
< \yskip\hang|down3| 159 |a[3]|. Same as |down1|, except that |a| is a | |
< three-byte quantity in the range |@t$-2^{23}$@>≤a<@t$2^{23}$@>|. | |
--- | |
> \yskip\hang|@!down3| 159 |a[3]|. Same as |down1|, except that |a| is a | |
> three-byte quantity in the range |@t$-2^{23}$@><=a<@t$2^{23}$@>|. | |
9153,9154c11437,11438 | |
< \yskip\hang|down4| 160 |a[4]|. Same as |down1|, except that |a| is a | |
< four-byte quantity in the range |@t$-2^{31}$@>≤a<@t$2^{31}$@>|. | |
--- | |
> \yskip\hang|@!down4| 160 |a[4]|. Same as |down1|, except that |a| is a | |
> four-byte quantity in the range |@t$-2^{31}$@><=a<@t$2^{31}$@>|. | |
9156c11440 | |
< \yskip\hang|y0| 161. Set |v←v+y|; i.e., move down |y| units. With luck, | |
--- | |
> \yskip\hang|y0| 161. Set |v:=v+y|; i.e., move down |y| units. With luck, | |
9161,9163c11445,11447 | |
< \yskip\hang|y1| 162 |a[1]|. Set |y←a| and |v←v+a|. The value of |a| is a | |
< signed quantity in two's complement notation, |-128≤a<128|. This command | |
< changes the current |y|@@spacing and moves down by |a|. | |
--- | |
> \yskip\hang|y1| 162 |a[1]|. Set |y:=a| and |v:=v+a|. The value of |a| is a | |
> signed quantity in two's complement notation, |-128<=a<128|. This command | |
> changes the current |y|~spacing and moves down by |a|. | |
9165,9166c11449,11450 | |
< \yskip\hang|y2| 163 |a[2]|. Same as |y1|, but |a| is two bytes long, | |
< |-32768≤a<32768|. | |
--- | |
> \yskip\hang|@!y2| 163 |a[2]|. Same as |y1|, but |a| is two bytes long, | |
> |-32768<=a<32768|. | |
9168,9169c11452,11453 | |
< \yskip\hang|y3| 164 |a[3]|. Same as |y1|, but |a| is three bytes long, | |
< |@t$-2^{23}$@>≤a<@t$2^{23}$@>|. | |
--- | |
> \yskip\hang|@!y3| 164 |a[3]|. Same as |y1|, but |a| is three bytes long, | |
> |@t$-2^{23}$@><=a<@t$2^{23}$@>|. | |
9171,9172c11455,11456 | |
< \yskip\hang|y4| 165 |a[4]|. Same as |y1|, but |a| is four bytes long, | |
< |@t$-2^{31}$@>≤a<@t$2^{31}$@>|. | |
--- | |
> \yskip\hang|@!y4| 165 |a[4]|. Same as |y1|, but |a| is four bytes long, | |
> |@t$-2^{31}$@><=a<@t$2^{31}$@>|. | |
9174c11458 | |
< \yskip\hang|z0| 166. Set |v←v+z|; i.e., move down |z| units. The `|z|' commands | |
--- | |
> \yskip\hang|z0| 166. Set |v:=v+z|; i.e., move down |z| units. The `|z|' commands | |
9177,9179c11461,11463 | |
< \yskip\hang|z1| 167 |a[1]|. Set |z←a| and |v←v+a|. The value of |a| is a | |
< signed quantity in two's complement notation, |-128≤a<128|. This command | |
< changes the current |z|@@spacing and moves down by |a|. | |
--- | |
> \yskip\hang|z1| 167 |a[1]|. Set |z:=a| and |v:=v+a|. The value of |a| is a | |
> signed quantity in two's complement notation, |-128<=a<128|. This command | |
> changes the current |z|~spacing and moves down by |a|. | |
9181,9182c11465,11466 | |
< \yskip\hang|z2| 168 |a[2]|. Same as |z1|, but |a| is two bytes long, | |
< |-32768≤a<32768|. | |
--- | |
> \yskip\hang|@!z2| 168 |a[2]|. Same as |z1|, but |a| is two bytes long, | |
> |-32768<=a<32768|. | |
9184,9185c11468,11469 | |
< \yskip\hang|z3| 169 |a[3]|. Same as |z1|, but |a| is three bytes long, | |
< |@t$-2^{23}$@>≤a<@t$2^{23}$@>|. | |
--- | |
> \yskip\hang|@!z3| 169 |a[3]|. Same as |z1|, but |a| is three bytes long, | |
> |@t$-2^{23}$@><=a<@t$2^{23}$@>|. | |
9187,9188c11471,11472 | |
< \yskip\hang|z4| 170 |a[4]|. Same as |z1|, but |a| is four bytes long, | |
< |@t$-2^{31}$@>≤a<@t$2^{31}$@>|. | |
--- | |
> \yskip\hang|@!z4| 170 |a[4]|. Same as |z1|, but |a| is four bytes long, | |
> |@t$-2^{31}$@><=a<@t$2^{31}$@>|. | |
9190c11474,11475 | |
< \yskip\hang|fnt_num_0| 171. Set |f←0|. | |
--- | |
> \yskip\hang|fnt_num_0| 171. Set |f:=0|. Font 0 must previously have been | |
> defined by a \\{fnt\_def} instruction, as explained below. | |
9192,9193c11477,11478 | |
< \yskip\hang|fnt_num_1| through |fnt_num_63| (opcodes 172 to 234). Set | |
< |f←1|, $\ldotss$, \hbox{|f←63|}, respectively. | |
--- | |
> \yskip\hang\\{fnt\_num\_1} through \\{fnt\_num\_63} (opcodes 172 to 234). Set | |
> |f:=1|, \dots, \hbox{|f:=63|}, respectively. | |
9195,9196c11480,11481 | |
< \yskip\hang|fnt1| 235 |n[1]|. Set |f←n|. \TeX82 uses this command for font | |
< numbers in the range |64≤n<256|. | |
--- | |
> \yskip\hang|fnt1| 235 |k[1]|. Set |f:=k|. \TeX82 uses this command for font | |
> numbers in the range |64<=k<256|. | |
9198,9199c11483,11484 | |
< \yskip\hang|fnt2| 236 |n[2]|. Same as |fnt1|, except that@@|n| is two | |
< bytes long, so it is in the range |0≤n<65536|. \TeX82 never generates this | |
--- | |
> \yskip\hang|@!fnt2| 236 |k[2]|. Same as |fnt1|, except that |k|~is two | |
> bytes long, so it is in the range |0<=k<65536|. \TeX82 never generates this | |
9204c11489 | |
< \yskip\hang|fnt3| 237 |n[3]|. Same as |fnt1|, except that@@|n| is three | |
--- | |
> \yskip\hang|@!fnt3| 237 |k[3]|. Same as |fnt1|, except that |k|~is three | |
9207,9217c11492,11513 | |
< \yskip\hang|fnt4| 238 |n[4]|. Same as |fnt1|, except that@@|n| is four | |
< bytes long; this is for the really big font numbers. The value $-1$ | |
< is forbidden, so the legal values of@@|f| are $-2^{31}\L f<-1$ and | |
< $0\L f<2^{31}-1$. | |
< | |
< \yskip\hang|xxx| 239 |m[1]| |x[m]|. This command is undefined in | |
< general; it functions as an $(m+2)$-byte |nop| unless special \.{DVI}-reading | |
< programs are being used. \TeX82 generates this command when an \.{\\xsend} | |
< appears, setting |m| to the number of bytes being sent. It is recommended that | |
< |x| be a string having the form of a keyword followed by possible parameters | |
< relevant to that keyword. | |
--- | |
> \yskip\hang|@!fnt4| 238 |k[4]|. Same as |fnt1|, except that |k|~is four | |
> bytes long; this is for the really big font numbers (and for the negative ones). | |
> | |
> \yskip\hang|xxx1| 239 |k[1]| |x[k]|. This command is undefined in | |
> general; it functions as a $(k+2)$-byte |nop| unless special \.{DVI}-reading | |
> programs are being used. \TeX82 generates |xxx1| when a short enough | |
> \.{\\special} appears, setting |k| to the number of bytes being sent. It | |
> is recommended that |x| be a string having the form of a keyword followed | |
> by possible parameters relevant to that keyword. | |
> | |
> \yskip\hang|@!xxx2| 240 |k[2]| |x[k]|. Like |xxx1|, but |0<=k<65536|. | |
> | |
> \yskip\hang|@!xxx3| 241 |k[3]| |x[k]|. Like |xxx1|, but |0<=k<@t$2^{24}$@>|. | |
> | |
> \yskip\hang|xxx4| 242 |k[4]| |x[k]|. Like |xxx1|, but |k| can be ridiculously | |
> large. \TeX82 uses |xxx4| when sending a string of length 256 or more. | |
> | |
> \yskip\hang|fnt_def1| 243 |k[1]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|. | |
> Define font |k|, where |0<=k<256|; font definitions will be explained shortly. | |
> | |
> \yskip\hang|@!fnt_def2| 244 |k[2]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|. | |
> Define font |k|, where |0<=k<65536|. | |
9219c11515,11516 | |
< \yskip\hang|pst| 240. Beginning of the postamble, see below. | |
--- | |
> \yskip\hang|@!fnt_def3| 245 |k[3]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|. | |
> Define font |k|, where |0<=k<@t$2^{24}$@>|. | |
9221c11518,11529 | |
< \yskip\noindent Commands 241--255 are undefined at the present time. | |
--- | |
> \yskip\hang|@!fnt_def4| 246 |k[4]| |c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|. | |
> Define font |k|, where |@t$-2^{31}$@><=k<@t$2^{31}$@>|. | |
> | |
> \yskip\hang|pre| 247 |i[1]| |num[4]| |den[4]| |mag[4]| |k[1]| |x[k]|. | |
> Beginning of the preamble; this must come at the very beginning of the | |
> file. Parameters |i|, |num|, |den|, |mag|, |k|, and |x| are explained below. | |
> | |
> \yskip\hang|post| 248. Beginning of the postamble, see below. | |
> | |
> \yskip\hang|post_post| 249. Ending of the postamble, see below. | |
> | |
> \yskip\noindent Commands 250--255 are undefined at the present time. | |
9226d11533 | |
< @d put1=133 {typeset a character} | |
9245,9246c11552,11619 | |
< @d xxx=239 {extension to \.{DVI} primitives} | |
< @d pst=240 {postamble} | |
--- | |
> @d xxx1=239 {extension to \.{DVI} primitives} | |
> @d xxx4=242 {potentially long extension to \.{DVI} primitives} | |
> @d fnt_def1=243 {define the meaning of a font number} | |
> @d pre=247 {preamble} | |
> @d post=248 {postamble beginning} | |
> @d post_post=249 {postamble ending} | |
> | |
> @ The preamble contains basic information about the file as a whole. As | |
> stated above, there are six parameters: | |
> $$\hbox{|@!i[1]| |@!num[4]| |@!den[4]| |@!mag[4]| |@!k[1]| |@!x[k]|.}$$ | |
> The |i| byte identifies \.{DVI} format; currently this byte is always set | |
> to~2. (The value |i=3| is currently used for an extended format that | |
> allows a mixture of right-to-left and left-to-right typesetting. | |
> Some day we will set |i=4|, when \.{DVI} format makes another | |
> incompatible change---perhaps in the year 2048.) | |
> | |
> The next two parameters, |num| and |den|, are positive integers that define | |
> the units of measurement; they are the numerator and denominator of a | |
> fraction by which all dimensions in the \.{DVI} file could be multiplied | |
> in order to get lengths in units of $10^{-7}$ meters. Since $\rm 7227{pt} = | |
> 254{cm}$, and since \TeX\ works with scaled points where there are $2^{16}$ | |
> sp in a point, \TeX\ sets | |
> $|num|/|den|=(254\cdot10^5)/(7227\cdot2^{16})=25400000/473628672$. | |
> @^sp@> | |
> | |
> The |mag| parameter is what \TeX\ calls \.{\\mag}, i.e., 1000 times the | |
> desired magnification. The actual fraction by which dimensions are | |
> multiplied is therefore $|mag|\cdot|num|/1000|den|$. Note that if a \TeX\ | |
> source document does not call for any `\.{true}' dimensions, and if you | |
> change it only by specifying a different \.{\\mag} setting, the \.{DVI} | |
> file that \TeX\ creates will be completely unchanged except for the value | |
> of |mag| in the preamble and postamble. (Fancy \.{DVI}-reading programs allow | |
> users to override the |mag|~setting when a \.{DVI} file is being printed.) | |
> | |
> Finally, |k| and |x| allow the \.{DVI} writer to include a comment, which is not | |
> interpreted further. The length of comment |x| is |k|, where |0<=k<256|. | |
> | |
> @d id_byte=2 {identifies the kind of \.{DVI} files described here} | |
> | |
> @ Font definitions for a given font number |k| contain further parameters | |
> $$\hbox{|c[4]| |s[4]| |d[4]| |a[1]| |l[1]| |n[a+l]|.}$$ | |
> The four-byte value |c| is the check sum that \TeX\ found in the \.{TFM} | |
> file for this font; |c| should match the check sum of the font found by | |
> programs that read this \.{DVI} file. | |
> @^check sum@> | |
> | |
> Parameter |s| contains a fixed-point scale factor that is applied to | |
> the character widths in font |k|; font dimensions in \.{TFM} files and | |
> other font files are relative to this quantity, which is called the | |
> ``at size'' elsewhere in this documentation. The value of |s| is | |
> always positive and less than $2^{27}$. It is given in the same units | |
> as the other \.{DVI} dimensions, i.e., in sp when \TeX82 has made the | |
> file. Parameter |d| is similar to |s|; it is the ``design size,'' and | |
> (like~|s|) it is given in \.{DVI} units. Thus, font |k| is to be used | |
> at $|mag|\cdot s/1000d$ times its normal size. | |
> | |
> The remaining part of a font definition gives the external name of the font, | |
> which is an ASCII string of length |a+l|. The number |a| is the length | |
> of the ``area'' or directory, and |l| is the length of the font name itself; | |
> the standard local system font area is supposed to be used when |a=0|. | |
> The |n| field contains the area in its first |a| bytes. | |
> | |
> Font definitions must appear before the first use of a particular font number. | |
> Once font |k| is defined, it must not be defined again; however, we | |
> shall see below that font definitions appear in the postamble as well as | |
> in the pages, so in this sense each font number is defined exactly twice, | |
> if at all. Like |nop| commands, font definitions can | |
> appear before the first |bop|, or between an |eop| and a |bop|. | |
9251c11624 | |
< generated by \MF\ by adhering to the following principles: (1)@@The \MF\ | |
--- | |
> generated by \MF\ by adhering to the following principles: (1)~The \MF\ | |
9254c11627 | |
< reference point, i.e., in row@@0 and column@@0 of the \MF\ raster. This | |
--- | |
> reference point, i.e., in row~0 and column~0 of the \MF\ raster. This | |
9257c11630 | |
< the \.{DVI} file. (2)@@A typeset rule of height $a>0$ and width $b>0$ | |
--- | |
> the \.{DVI} file. (2)~A typeset rule of height $a>0$ and width $b>0$ | |
9260c11633 | |
< |0≤x<@t$\alpha$@>b| and |0≤y<@t$\alpha$@>a|, where $\alpha$ is the number | |
--- | |
> |0<=x<@t$\alpha$@>b| and |0<=y<@t$\alpha$@>a|, where $\alpha$ is the number | |
9266c11639 | |
< @ The last page in a \.{DVI} file is followed by `|pst|'; this command | |
--- | |
> @ The last page in a \.{DVI} file is followed by `|post|'; this command | |
9268,9288c11641,11649 | |
< accumulated about the file. The postamble has the form | |
< $$\hbox{|p[4]| |n[4]| |d[4]| |m[4]| |l[4]| |u[4]| |s[2]| |t[2]| | |
< $\langle\,$font definitions$\,\rangle$ | |
< $(-1)[4]$ |q[4]| |i[1]| 223's|[≥4]|}$$ | |
< Here |p| is a pointer to the final |bop| in the file. The next two parameters, | |
< |n| and |d|, are positive integers that define the units of measurement; | |
< they are the numerator and denominator of a fraction by which all dimensions | |
< in the \.{DVI} file could be multiplied in order to get lengths in units | |
< of $10^{-7}$ meters. (Since there are 72.27 points per inch and 2.54 centimeters | |
< per inch, and since \TeX82 works with scaled points where there are $2^{16}$ | |
< sp in a point, \TeX82 sets |n=25400000| and $d=7227\cdot2^{16}=473628672$.) | |
< @^sp@> | |
< | |
< The next parameter, |m|, is \TeX's \.{\\mag} parameter, i.e., 1000 times the | |
< desired magnification. The actual fraction by which dimensions are multiplied | |
< is therefore $mn/1000d$. Note that if a \TeX\ source document does not call | |
< for any `\.{true}' dimensions, and if you change it only by specifying a | |
< different \.{\\mag} setting, the \.{DVI} file that \TeX\ creates will be | |
< completely unchanged except for the value of |m| in the postamble. (Fancy | |
< \.{DVI}-reading programs allow users to override the |m|@@setting when a | |
< \.{DVI} file is being printed.) | |
--- | |
> accumulated about the file, making it possible to print subsets of the data | |
> with reasonable efficiency. The postamble has the form | |
> $$\vbox{\halign{\hbox{#\hfil}\cr | |
> |post| |p[4]| |num[4]| |den[4]| |mag[4]| |l[4]| |u[4]| |s[2]| |t[2]|\cr | |
> $\langle\,$font definitions$\,\rangle$\cr | |
> |post_post| |q[4]| |i[1]| 223's$[{\G}4]$\cr}}$$ | |
> Here |p| is a pointer to the final |bop| in the file. The next three | |
> parameters, |num|, |den|, and |mag|, are duplicates of the quantities that | |
> appeared in the preamble. | |
9293,9296c11654,11664 | |
< position individual ``pages'' on large sheets of film or paper. | |
< Parameter |s| is the maximum stack depth (i.e., the excess of |push| commands | |
< over |pop| commands) needed to process this file. Then comes |t|, the total | |
< number of pages (|bop| commands) present. | |
--- | |
> position individual ``pages'' on large sheets of film or paper; however, | |
> the standard convention for output on normal size paper is to position each | |
> page so that the upper left-hand corner is exactly one inch from the left | |
> and the top. Experience has shown that it is unwise to design \.{DVI}-to-printer | |
> software that attempts cleverly to center the output; a fixed position of | |
> the upper left corner is easiest for users to understand and to work with. | |
> Therefore |l| and~|u| are often ignored. | |
> | |
> Parameter |s| is the maximum stack depth (i.e., the largest excess of | |
> |push| commands over |pop| commands) needed to process this file. Then | |
> comes |t|, the total number of pages (|bop| commands) present. | |
9299,9327c11667,11675 | |
< speci\-fi\-ca\-tions having the form | |
< \def\f{↓{\!f}} | |
< $$\hbox{|f[4]| $c\f[4]$ $s\f[4]$ $a\f[1]$ $l\f[1]$ $n\f[a\f+l\f]$.}$$ | |
< The first parameter in a font definition is the font number, $f$; this | |
< must be different from $-1$ and distinct from the font numbers in other | |
< definitions. (Note that the font definitions are followed by the four-byte | |
< value $-1$, so it will be clear when the definitions have ended.) The | |
< next parameter, $c\f$, is the check sum that \TeX\ found in the \.{TFM} | |
< file for this font; it should match the check sum of the font found by | |
< @^check sum@> | |
< programs that read this \.{DVI} file. | |
< Parameter $s\f$ contains a fixed-point scale factor that is applied to the | |
< character widths in font |f|; font dimensions in \.{TFM} files and other font | |
< files are relative to this quantity, which is called the ``at size'' elsewhere | |
< in this documentation. The value of $s\f$ is always positive and less than | |
< $2^{27}$. It is given in the same units as the other dimensions of the | |
< file, i.e., in sp. | |
< | |
< The remaining part of a font definition gives the external name of the font, | |
< which is an ascii string of length $a\f+l\f$. The number $a\f$ is the length | |
< of the ``area'' or directory, and $l\f$ is the length of the font name itself; | |
< the standard local system font area is supposed to be used when $a\f=0$. | |
< The $n\f$ field contains the area in its first $a\f$ bytes. | |
< | |
< @ The last part of the postamble, following the phony font number | |
< $-1$, contains |q|, a pointer to the |pst| command that started the | |
< postamble. An identification byte, |i|, comes next; currently this byte | |
< is always set to@@2. (Some day we will set |i=3|, when \.{DVI} format | |
< makes another incompatible change---perhaps in 1992.) | |
--- | |
> \\{fnt\_def} commands as described above, possibly interspersed with |nop| | |
> commands. Each font number that is used in the \.{DVI} file must be defined | |
> exactly twice: Once before it is first selected by a \\{fnt} command, and once | |
> in the postamble. | |
> | |
> @ The last part of the postamble, following the |post_post| byte that | |
> signifies the end of the font definitions, contains |q|, a pointer to the | |
> |post| command that started the postamble. An identification byte, |i|, | |
> comes next; this currently equals~2, as in the preamble. | |
9329c11677 | |
< Following the |i| byte there are four or more bytes that are all equal to | |
--- | |
> The |i| byte is followed by four or more bytes that are all equal to | |
9341,9345c11689,11693 | |
< the \.{DVI} reader starts at the end and skips backwards over the 223's | |
< until finding the identification byte. Then it backs up four bytes, reads | |
< |q|, and goes to byte |q| of the file. This byte should, of course, | |
< contain the value 240 (|pst|); now the postamble can be read, so the | |
< \.{DVI} reader discovers all the information needed for typesetting the | |
--- | |
> the \.{DVI} reader can start at the end and skip backwards over the 223's | |
> until finding the identification byte. Then it can back up four bytes, read | |
> |q|, and move to byte |q| of the file. This byte should, of course, | |
> contain the value 248 (|post|); now the postamble can be read, so the | |
> \.{DVI} reader can discover all the information needed for typesetting the | |
9348,9362c11696,11697 | |
< desirable. | |
< | |
< The reason for reading the postamble first is that the \.{DVI} reader must | |
< know the widths of characters, in order to find out where things go on a page; | |
< and it needs to know the names of the fonts, so that it can get their widths | |
< from a \.{TFM} file or from some other kind of font-information file. | |
< The reason for writing the postamble last is that \TeX\ can't put out all | |
< the font names until it has finished generating the pages of the \.{DVI} | |
< file, since new fonts can occur anywhere in a \TeX\ job; and the alternative | |
< of sprinkling font definitions throughout a \.{DVI} file is unattractive, | |
< since that would make it necessary to read the whole file even when | |
< printing only one page. Furthermore, we wouldn't want to copy the | |
< information in the first part of a \.{DVI} file to the end of another file | |
< that begins with the postamble information, since the first part | |
< is typically quite long. | |
--- | |
> desirable. This saves a lot of time, since \.{DVI} files used in production | |
> jobs tend to be large. | |
9370,9371c11705,11708 | |
< \PASCAL, one can simply read them twice, first skipping to the postamble | |
< and then doing the pages. | |
--- | |
> \PASCAL, one can simply read them from front to back, since the necessary | |
> header information is present in the preamble and in the font definitions. | |
> (The |l| and |u| and |s| and |t| parameters, which appear only in the | |
> postamble, are ``frills'' that are handy but not absolutely necessary.) | |
9373,9374c11710 | |
< @d id_byte=2 {identifies the kind of \.{DVI} files described here} | |
< @* \[31] Shipping pages out. | |
--- | |
> @* \[32] Shipping pages out. | |
9393a11730,11731 | |
> The variable |dead_cycles| contains the number of times an output routine | |
> has been initiated since the last |ship_out|. | |
9406a11745 | |
> @!dead_cycles:integer; {recent outputs that didn't ship anything out} | |
9410d11748 | |
< @!hd:quarterword; {height and depth indices for a character} | |
9413c11751 | |
< @!lq,@!lr,@!lx:integer; {quantities used in calculations for leaders} | |
--- | |
> @!lq,@!lr:integer; {quantities used in calculations for leaders} | |
9416,9417c11754,11755 | |
< total_pages←0; max_v←0; max_h←0; max_push←0; last_bop←-1; | |
< doing_leaders←false; | |
--- | |
> total_pages:=0; max_v:=0; max_h:=0; max_push:=0; last_bop:=-1; | |
> doing_leaders:=false; dead_cycles:=0; cur_s:=-1; | |
9440c11778 | |
< A byte is present in the buffer only if its number is |≥dvi_gone|. | |
--- | |
> A byte is present in the buffer only if its number is |>=dvi_gone|. | |
9446a11785 | |
> @^system dependencies@> | |
9454c11793 | |
< output buffer has been fully emptied} | |
--- | |
> output buffer has been fully emptied} | |
9461,9462c11800,11801 | |
< half_buf←dvi_buf_size div 2; dvi_limit←dvi_buf_size; dvi_ptr←0; | |
< dvi_offset←0; dvi_gone←0; | |
--- | |
> half_buf:=dvi_buf_size div 2; dvi_limit:=dvi_buf_size; dvi_ptr:=0; | |
> dvi_offset:=0; dvi_gone:=0; | |
9477c11816 | |
< begin for k←a to b do write(dvi_file,dvi_buf[k]); | |
--- | |
> begin for k:=a to b do write(dvi_file,dvi_buf[k]); | |
9483,9485c11822,11824 | |
< @d dvi_out(#)==@+begin dvi_buf[dvi_ptr]←#; incr(dvi_ptr); | |
< if dvi_ptr=dvi_limit then dvi_swap; | |
< end | |
--- | |
> @d dvi_out(#)==@+begin dvi_buf[dvi_ptr]:=#; incr(dvi_ptr); | |
> if dvi_ptr=dvi_limit then dvi_swap; | |
> end | |
9489,9494c11828,11833 | |
< begin write_dvi(0,half_buf-1); dvi_limit←half_buf; | |
< dvi_offset←dvi_offset+dvi_buf_size; dvi_ptr←0; | |
< end | |
< else begin write_dvi(half_buf,dvi_buf_size-1); dvi_limit←dvi_buf_size; | |
< end; | |
< dvi_gone←dvi_gone+half_buf; | |
--- | |
> begin write_dvi(0,half_buf-1); dvi_limit:=half_buf; | |
> dvi_offset:=dvi_offset+dvi_buf_size; dvi_ptr:=0; | |
> end | |
> else begin write_dvi(half_buf,dvi_buf_size-1); dvi_limit:=dvi_buf_size; | |
> end; | |
> dvi_gone:=dvi_gone+half_buf; | |
9498c11837 | |
< will be a multiple of@@4. | |
--- | |
> will be a multiple of~4. | |
9508,9514c11847,11853 | |
< begin if x≥0 then dvi_out(x div @'100000000) | |
< else begin x:=x+@'10000000000; | |
< x:=x+@'10000000000; | |
< dvi_out((x div @'100000000) + 128); | |
< end; | |
< x←x mod @'100000000; dvi_out(x div @'200000); | |
< x←x mod @'200000; dvi_out(x div @'400); | |
--- | |
> begin if x>=0 then dvi_out(x div @'100000000) | |
> else begin x:=x+@'10000000000; | |
> x:=x+@'10000000000; | |
> dvi_out((x div @'100000000) + 128); | |
> end; | |
> x:=x mod @'100000000; dvi_out(x div @'200000); | |
> x:=x mod @'200000; dvi_out(x div @'400); | |
9517a11857,11889 | |
> @ A mild optimization of the output is performed by the |dvi_pop| | |
> routine, which issues a |pop| unless it is possible to cancel a | |
> `|push| |pop|' pair. The parameter to |dvi_pop| is the byte address | |
> following the old |push| that matches the new |pop|. | |
> | |
> @p procedure dvi_pop(@!l:integer); | |
> begin if (l=dvi_offset+dvi_ptr)and(dvi_ptr>0) then decr(dvi_ptr) | |
> else dvi_out(pop); | |
> end; | |
> | |
> @ Here's a procedure that outputs a font definition. Since \TeX82 uses at | |
> most 256 different fonts per job, |fnt_def1| is always used as the command code. | |
> | |
> @p procedure dvi_font_def(@!f:internal_font_number); | |
> var k:pool_pointer; {index into |str_pool|} | |
> begin dvi_out(fnt_def1); | |
> dvi_out(f-font_base-1);@/ | |
> dvi_out(qo(font_check[f].b0)); | |
> dvi_out(qo(font_check[f].b1)); | |
> dvi_out(qo(font_check[f].b2)); | |
> dvi_out(qo(font_check[f].b3));@/ | |
> dvi_four(font_size[f]); | |
> dvi_four(font_dsize[f]);@/ | |
> dvi_out(length(font_area[f])); | |
> dvi_out(length(font_name[f])); | |
> @<Output the font name whose internal number is |f|@>; | |
> end; | |
> | |
> @ @<Output the font name whose internal number is |f|@>= | |
> for k:=str_start[font_area[f]] to str_start[font_area[f]+1]-1 do | |
> dvi_out(so(str_pool[k])); | |
> for k:=str_start[font_name[f]] to str_start[font_name[f]+1]-1 do | |
> dvi_out(so(str_pool[k])) | |
9536,9539c11908,11911 | |
< $$3↓z\,1↓y\,4↓d\,1↓y\,5↓y\,9↓d\,2↓d\,6↓d\,5↓y\,3↓z\,5↓y\,8↓d\,9↓d.$$ | |
< There are three $y$-hits ($1↓y\ldotsm1↓y$ and $5↓y\ldotsm5↓y\ldotsm5↓y$) and | |
< one $z$-hit ($3↓z\ldotsm3↓z$); there are no $d$-hits, since the two appearances | |
< of $9↓d$ have $d$'s between them, but we don't count $d$-hits so it doesn't | |
--- | |
> $$3_z\,1_y\,4_d\,1_y\,5_y\,9_d\,2_d\,6_d\,5_y\,3_z\,5_y\,8_d\,9_d.$$ | |
> There are three $y$-hits ($1_y\ldots1_y$ and $5_y\ldots5_y\ldots5_y$) and | |
> one $z$-hit ($3_z\ldots3_z$); there are no $d$-hits, since the two appearances | |
> of $9_d$ have $d$'s between them, but we don't count $d$-hits so it doesn't | |
9547,9548c11919,11920 | |
< sequence until one of the following things happens: (a)@@You see | |
< $\delta↓y$ or $\delta↓z$, and this was the first time you encountered a | |
--- | |
> sequence until one of the following things happens: (a)~You see | |
> $\delta_y$ or $\delta_z$, and this was the first time you encountered a | |
9550c11922 | |
< $\delta$; you have scored a hit. (b)@@You see $\delta↓d$, and no $y$ | |
--- | |
> $\delta$; you have scored a hit. (b)~You see $\delta_d$, and no $y$ | |
9552c11924 | |
< the previous $\delta↓d$ to $\delta↓y$ (this corresponds to changing a | |
--- | |
> the previous $\delta_d$ to $\delta_y$ (this corresponds to changing a | |
9554,9556c11926,11928 | |
< another hit. (c)@@You see $\delta↓d$, and a $y$ subscript has been seen | |
< but not a $z$. Change the previous $\delta↓d$ to $\delta↓z$ and assign | |
< $z$ to the new $\delta$. (d)@@You encounter both $y$ and $z$ subscripts | |
--- | |
> another hit. (c)~You see $\delta_d$, and a $y$ subscript has been seen | |
> but not a $z$. Change the previous $\delta_d$ to $\delta_z$ and assign | |
> $z$ to the new $\delta$. (d)~You encounter both $y$ and $z$ subscripts | |
9561c11933 | |
< The subscripts $3↓z\,1↓y\,4↓d\ldotsm$ in the example above were, in fact, | |
--- | |
> The subscripts $3_z\,1_y\,4_d\ldots\,$ in the example above were, in fact, | |
9584c11956 | |
< down_ptr←null; right_ptr←null; | |
--- | |
> down_ptr:=null; right_ptr:=null; | |
9597,9598c11969,11970 | |
< begin q←get_node(movement_node_size); {new node for the top of the stack} | |
< width(q)←w; location(q)←dvi_offset+dvi_ptr; | |
--- | |
> begin q:=get_node(movement_node_size); {new node for the top of the stack} | |
> width(q):=w; location(q):=dvi_offset+dvi_ptr; | |
9600,9603c11972,11975 | |
< begin link(q)←down_ptr; down_ptr←q; | |
< end | |
< else begin link(q)←right_ptr; right_ptr←q; | |
< end; | |
--- | |
> begin link(q):=down_ptr; down_ptr:=q; | |
> end | |
> else begin link(q):=right_ptr; right_ptr:=q; | |
> end; | |
9605c11977 | |
< to generate; |goto found| if node |p| is a ``hit''@>; | |
--- | |
> to generate; |goto found| if node |p| is a ``hit''@>; | |
9608c11980 | |
< appearance of@@|w|@>; | |
--- | |
> appearance of~|w|@>; | |
9625c11997 | |
< redefining hits so that $\delta↓y\ldotsm \delta↓y$ is a hit if all $y$'s between | |
--- | |
> redefining hits so that $\delta_y\ldots \delta_y$ is a hit if all $y$'s between | |
9627c11999 | |
< parenthesis level of the right-hand $\delta↓y$ is deeper than or equal to | |
--- | |
> parenthesis level of the right-hand $\delta_y$ is deeper than or equal to | |
9631,9634c12003,12009 | |
< $$2↓y\,7↓d\,1↓d\,(\,8↓z\,2↓y\,8↓z\,)\,1$$ | |
< we cannot change the previous $1↓d$ to $1↓y$, since that would invalidate | |
< the $2↓y\ldotsm2↓y$ hit. But we can change it to $1↓z$, scoring a hit | |
< since the intervening $8↓z$'s are enclosed in parentheses. | |
--- | |
> $$2_y\,7_d\,1_d\,(\,8_z\,2_y\,8_z\,)\,1$$ | |
> we cannot change the previous $1_d$ to $1_y$, since that would invalidate | |
> the $2_y\ldots2_y$ hit. But we can change it to $1_z$, scoring a hit | |
> since the intervening $8_z$'s are enclosed in parentheses. | |
> | |
> The program below removes movement nodes that are introduced after a |push|, | |
> before it outputs the corresponding |pop|. | |
9649c12024 | |
< info(q)←info(p); | |
--- | |
> info(q):=info(p); | |
9651,9670c12026,12045 | |
< begin dvi_out(o+y0-down1); {|y0| or |w0|} | |
< while link(q)≠p do | |
< begin q←link(q); | |
< case info(q) of | |
< yz_OK: info(q)←z_OK; | |
< y_OK: info(q)←d_fixed; | |
< othercases do_nothing | |
< endcases; | |
< end; | |
< end | |
< else begin dvi_out(o+z0-down1); {|z0| or |x0|} | |
< while link(q)≠p do | |
< begin q←link(q); | |
< case info(q) of | |
< yz_OK: info(q)←y_OK; | |
< z_OK: info(q)←d_fixed; | |
< othercases do_nothing | |
< endcases; | |
< end; | |
< end | |
--- | |
> begin dvi_out(o+y0-down1); {|y0| or |w0|} | |
> while link(q)<>p do | |
> begin q:=link(q); | |
> case info(q) of | |
> yz_OK: info(q):=z_OK; | |
> y_OK: info(q):=d_fixed; | |
> othercases do_nothing | |
> endcases; | |
> end; | |
> end | |
> else begin dvi_out(o+z0-down1); {|z0| or |x0|} | |
> while link(q)<>p do | |
> begin q:=link(q); | |
> case info(q) of | |
> yz_OK: info(q):=y_OK; | |
> z_OK: info(q):=d_fixed; | |
> othercases do_nothing | |
> endcases; | |
> end; | |
> end | |
9673,9687c12048,12062 | |
< info(q)←yz_OK; | |
< if abs(w)≥@'40000000 then | |
< begin dvi_out(o+3); {|down4| or |right4|} | |
< dvi_four(w); return; | |
< end; | |
< if abs(w)≥@'100000 then | |
< begin dvi_out(o+2); {|down3| or |right3|} | |
< if w<0 then w←w+@'100000000; | |
< dvi_out(w div @'200000); w←w mod @'200000; goto 2; | |
< end; | |
< if abs(w)≥@'200 then | |
< begin dvi_out(o+1); {|down2| or |right2|} | |
< if w<0 then w←w+@'200000; | |
< goto 2; | |
< end; | |
--- | |
> info(q):=yz_OK; | |
> if abs(w)>=@'40000000 then | |
> begin dvi_out(o+3); {|down4| or |right4|} | |
> dvi_four(w); return; | |
> end; | |
> if abs(w)>=@'100000 then | |
> begin dvi_out(o+2); {|down3| or |right3|} | |
> if w<0 then w:=w+@'100000000; | |
> dvi_out(w div @'200000); w:=w mod @'200000; goto 2; | |
> end; | |
> if abs(w)>=@'200 then | |
> begin dvi_out(o+1); {|down2| or |right2|} | |
> if w<0 then w:=w+@'200000; | |
> goto 2; | |
> end; | |
9689c12064 | |
< if w<0 then w←w+@'400; | |
--- | |
> if w<0 then w:=w+@'400; | |
9698a12074 | |
> @^inner loop@> | |
9705,9716c12081,12092 | |
< p←link(q); mstate←none_seen; | |
< while p≠null do | |
< begin if width(p)=w then @<Consider a node with matching width; | |
< |goto found| if it's a hit@> | |
< else case mstate+info(p) of | |
< none_seen+y_here: mstate←y_seen; | |
< none_seen+z_here: mstate←z_seen; | |
< y_seen+z_here,z_seen+y_here: goto not_found; | |
< othercases do_nothing | |
< endcases; | |
< p←link(p); | |
< end; | |
--- | |
> p:=link(q); mstate:=none_seen; | |
> while p<>null do | |
> begin if width(p)=w then @<Consider a node with matching width; | |
> |goto found| if it's a hit@> | |
> else case mstate+info(p) of | |
> none_seen+y_here: mstate:=y_seen; | |
> none_seen+z_here: mstate:=z_seen; | |
> y_seen+z_here,z_seen+y_here: goto not_found; | |
> othercases do_nothing | |
> endcases; | |
> p:=link(p); | |
> end; | |
9721c12097 | |
< moving finger writes, $\ldotss\,$.'' | |
--- | |
> moving finger writes, $\ldots\,\,$.'' | |
9725,9730c12101,12106 | |
< none_seen+yz_OK,none_seen+y_OK,z_seen+yz_OK,z_seen+y_OK:@;@/ | |
< if location(p)<dvi_gone then goto not_found | |
< else @<Change buffered instruction to |y| or |w| and |goto found|@>; | |
< none_seen+z_OK,y_seen+yz_OK,y_seen+z_OK:@;@/ | |
< if location(p)<dvi_gone then goto not_found | |
< else @<Change buffered instruction to |z| or |x| and |goto found|@>; | |
--- | |
> none_seen+yz_OK,none_seen+y_OK,z_seen+yz_OK,z_seen+y_OK:@t@>@;@/ | |
> if location(p)<dvi_gone then goto not_found | |
> else @<Change buffered instruction to |y| or |w| and |goto found|@>; | |
> none_seen+z_OK,y_seen+yz_OK,y_seen+z_OK:@t@>@;@/ | |
> if location(p)<dvi_gone then goto not_found | |
> else @<Change buffered instruction to |z| or |x| and |goto found|@>; | |
9736,9739c12112,12115 | |
< begin k←location(p)-dvi_offset; | |
< if k<0 then k←k+dvi_buf_size; | |
< dvi_buf[k]←dvi_buf[k]+y1-down1; | |
< info(p)←y_here; goto found; | |
--- | |
> begin k:=location(p)-dvi_offset; | |
> if k<0 then k:=k+dvi_buf_size; | |
> dvi_buf[k]:=dvi_buf[k]+y1-down1; | |
> info(p):=y_here; goto found; | |
9743,9746c12119,12122 | |
< begin k←location(p)-dvi_offset; | |
< if k<0 then k←k+dvi_buf_size; | |
< dvi_buf[k]←dvi_buf[k]+z1-down1; | |
< info(p)←z_here; goto found; | |
--- | |
> begin k:=location(p)-dvi_offset; | |
> if k<0 then k:=k+dvi_buf_size; | |
> dvi_buf[k]:=dvi_buf[k]+z1-down1; | |
> info(p):=z_here; goto found; | |
9756c12132 | |
< {delete movement nodes with |location≥l|} | |
--- | |
> {delete movement nodes with |location>=l|} | |
9759,9766c12135,12142 | |
< begin while down_ptr≠null do | |
< begin if location(down_ptr)<l then goto done; | |
< p←down_ptr; down_ptr←link(p); free_node(p,movement_node_size); | |
< end; | |
< done: while right_ptr≠null do | |
< begin if location(right_ptr)<l then return; | |
< p←right_ptr; right_ptr←link(p); free_node(p,movement_node_size); | |
< end; | |
--- | |
> begin while down_ptr<>null do | |
> begin if location(down_ptr)<l then goto done; | |
> p:=down_ptr; down_ptr:=link(p); free_node(p,movement_node_size); | |
> end; | |
> done: while right_ptr<>null do | |
> begin if location(right_ptr)<l then return; | |
> p:=right_ptr; right_ptr:=link(p); free_node(p,movement_node_size); | |
> end; | |
9777c12153 | |
< Therefore \TeX\ maintains two pairs of global variables: |dvi_h| and |dvi_v| | |
--- | |
> Therefore, \TeX\ maintains two pairs of global variables: |dvi_h| and |dvi_v| | |
9792,9797c12168,12173 | |
< @d synch_h==if cur_h≠dvi_h then | |
< begin movement(cur_h-dvi_h,right1); dvi_h←cur_h; | |
< end | |
< @d synch_v==if cur_v≠dvi_v then | |
< begin movement(cur_v-dvi_v,down1); dvi_v←cur_v; | |
< end | |
--- | |
> @d synch_h==if cur_h<>dvi_h then | |
> begin movement(cur_h-dvi_h,right1); dvi_h:=cur_h; | |
> end | |
> @d synch_v==if cur_v<>dvi_v then | |
> begin movement(cur_v-dvi_v,down1); dvi_v:=cur_v; | |
> end | |
9803c12179 | |
< @!cur_s:integer; {current depth of output box nesting} | |
--- | |
> @!cur_s:integer; {current depth of output box nesting, initially $-1$} | |
9806,9807c12182,12197 | |
< dvi_h←0; dvi_v←0; cur_h←0; dvi_f←undefined_font; | |
< cur_s←-1; ensure_dvi_open; | |
--- | |
> dvi_h:=0; dvi_v:=0; cur_h:=h_offset; dvi_f:=null_font; | |
> ensure_dvi_open; | |
> if total_pages=0 then | |
> begin dvi_out(pre); dvi_out(id_byte); {output the preamble} | |
> @^preamble of \.{DVI} file@> | |
> dvi_four(25400000); dvi_four(473628672); {conversion ratio for sp} | |
> prepare_mag; dvi_four(mag); {magnification factor is frozen} | |
> old_setting:=selector; selector:=new_string; | |
> print(" TeX output "); print_int(year); print_char("."); | |
> print_two(month); print_char("."); print_two(day); | |
> print_char(":"); print_two(time div 60); | |
> print_two(time mod 60); | |
> selector:=old_setting; dvi_out(cur_length); | |
> for s:=str_start[str_ptr] to pool_ptr-1 do dvi_out(so(str_pool[s])); | |
> pool_ptr:=str_start[str_ptr]; {flush the current string} | |
> end | |
9819c12209 | |
< recursive} | |
--- | |
> recursive} | |
9827c12217 | |
< @d advance=13 {go to this label when advancing past glue or a rule} | |
--- | |
> @d move_past=13 {go to this label when advancing past glue or a rule} | |
9833c12223 | |
< label reswitch, advance, fin_rule, next_p; | |
--- | |
> label reswitch, move_past, fin_rule, next_p; | |
9834a12225 | |
> @!left_edge: scaled; {the left coordinate for this box} | |
9842a12234 | |
> @!lx:scaled; {extra space between leader boxes} | |
9845,9846c12237,12242 | |
< begin this_box←temp_ptr; g_order←glue_order(this_box); | |
< g_sign←glue_sign(this_box); p←list_ptr(this_box); | |
--- | |
> @!glue_temp:real; {glue value before rounding} | |
> @!cur_glue:real; {glue seen so far} | |
> @!cur_g:scaled; {rounded equivalent of |cur_glue| times the glue ratio} | |
> begin cur_g:=0; cur_glue:=float_constant(0); | |
> this_box:=temp_ptr; g_order:=glue_order(this_box); | |
> g_sign:=glue_sign(this_box); p:=list_ptr(this_box); | |
9848,9852c12244,12251 | |
< if cur_s>max_push then max_push←cur_s; | |
< save_loc←dvi_offset+dvi_ptr; base_line←cur_v; | |
< while p≠null do @<Output node |p| for |hlist_out| and move to the next node, | |
< maintaining the condition |cur_v=base_line|@>; | |
< prune_movements(save_loc); decr(cur_s); | |
--- | |
> if cur_s>0 then dvi_out(push); | |
> if cur_s>max_push then max_push:=cur_s; | |
> save_loc:=dvi_offset+dvi_ptr; base_line:=cur_v; left_edge:=cur_h; | |
> while p<>null do @<Output node |p| for |hlist_out| and move to the next node, | |
> maintaining the condition |cur_v=base_line|@>; | |
> prune_movements(save_loc); | |
> if cur_s>0 then dvi_pop(save_loc); | |
> decr(cur_s); | |
9863,9875c12262,12273 | |
< begin synch_h; synch_v; | |
< repeat f←font(p); c←character(p); | |
< if f≠dvi_f then @<Change font |dvi_f| to |f|@>; | |
< if c<128+min_quarterword then dvi_out(qo(c)) | |
< else begin dvi_out(set1); dvi_out(qo(c)); | |
< end; | |
< cur_h←cur_h+char_width(f)(char_info(f)(c)); | |
< p←link(p); | |
< until not is_char_node(p); | |
< dvi_h←cur_h; | |
< end | |
< else if p≠null then @<Output the non-|char_node| |p| for |hlist_out| | |
< and move to the next node@> | |
--- | |
> begin synch_h; synch_v; | |
> repeat f:=font(p); c:=character(p); | |
> if f<>dvi_f then @<Change font |dvi_f| to |f|@>; | |
> if c>=qi(128) then dvi_out(set1); | |
> dvi_out(qo(c));@/ | |
> cur_h:=cur_h+char_width(f)(char_info(f)(c)); | |
> p:=link(p); | |
> until not is_char_node(p); | |
> dvi_h:=cur_h; | |
> end | |
> else @<Output the non-|char_node| |p| for |hlist_out| | |
> and move to the next node@> | |
9878,9882c12276,12282 | |
< begin if f≤64+font_base then dvi_out(f-font_base-1+fnt_num_0) | |
< else begin dvi_out(fnt1); dvi_out(f-font_base-1); | |
< end; | |
< dvi_f←f; | |
< font_used[f]←true; | |
--- | |
> begin if not font_used[f] then | |
> begin dvi_font_def(f); font_used[f]:=true; | |
> end; | |
> if f<=64+font_base then dvi_out(f-font_base-1+fnt_num_0) | |
> else begin dvi_out(fnt1); dvi_out(f-font_base-1); | |
> end; | |
> dvi_f:=f; | |
9888,9890c12288,12290 | |
< rule_node: begin rule_ht←height(p); rule_dp←depth(p); rule_wd←width(p); | |
< goto fin_rule; | |
< end; | |
--- | |
> rule_node: begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p); | |
> goto fin_rule; | |
> end; | |
9893c12293 | |
< kern_node,math_node:cur_h←cur_h+width(p); | |
--- | |
> kern_node,math_node:cur_h:=cur_h+width(p); | |
9899,9900c12299,12300 | |
< advance: cur_h←cur_h+rule_wd; | |
< next_p:p←link(p); | |
--- | |
> move_past: cur_h:=cur_h+rule_wd; | |
> next_p:p:=link(p); | |
9904,9911c12304,12311 | |
< if list_ptr(p)=null then cur_h←cur_h+width(p) | |
< else begin save_h←dvi_h; save_v←dvi_v; dvi_out(push); | |
< cur_v←base_line+shift_amount(p); {shift the box down} | |
< temp_ptr←p; edge←cur_h; | |
< if type(p)=vlist_node then vlist_out@+else hlist_out; | |
< dvi_out(pop); dvi_h←save_h; dvi_v←save_v; | |
< cur_h←edge+width(p); cur_v←base_line; | |
< end | |
--- | |
> if list_ptr(p)=null then cur_h:=cur_h+width(p) | |
> else begin save_h:=dvi_h; save_v:=dvi_v; | |
> cur_v:=base_line+shift_amount(p); {shift the box down} | |
> temp_ptr:=p; edge:=cur_h; | |
> if type(p)=vlist_node then vlist_out@+else hlist_out; | |
> dvi_h:=save_h; dvi_v:=save_v; | |
> cur_h:=edge+width(p); cur_v:=base_line; | |
> end | |
9914,9937c12314,12351 | |
< if is_running(rule_ht) then rule_ht←height(this_box); | |
< if is_running(rule_dp) then rule_dp←depth(this_box); | |
< rule_ht←rule_ht+rule_dp; {this is the rule thickness} | |
< if (rule_ht>0)∧(rule_wd>0) then {we don't output empty rules} | |
< begin synch_h; cur_v←base_line+rule_dp; synch_v; | |
< dvi_out(set_rule); dvi_four(rule_ht); dvi_four(rule_wd); | |
< cur_v←base_line; dvi_h←dvi_h+rule_wd; | |
< end | |
< | |
< @ @<Move right or output leaders@>= | |
< begin g←glue_ptr(p); rule_wd←width(g); | |
< if g_sign≠normal then | |
< begin if g_sign=stretching then | |
< begin if stretch_order(g)=g_order then | |
< rule_wd←rule_wd+round(glue_set(this_box)*stretch(g)); | |
< end | |
< else begin if shrink_order(g)=g_order then | |
< rule_wd←rule_wd-round(glue_set(this_box)*shrink(g)); | |
< end; | |
< end; | |
< if subtype(p)≥a_leaders then | |
< @<Output leaders in an hlist, |goto fin_rule| if a rule | |
< or to |next_p| if done@>; | |
< goto advance; | |
--- | |
> if is_running(rule_ht) then rule_ht:=height(this_box); | |
> if is_running(rule_dp) then rule_dp:=depth(this_box); | |
> rule_ht:=rule_ht+rule_dp; {this is the rule thickness} | |
> if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules} | |
> begin synch_h; cur_v:=base_line+rule_dp; synch_v; | |
> dvi_out(set_rule); dvi_four(rule_ht); dvi_four(rule_wd); | |
> cur_v:=base_line; dvi_h:=dvi_h+rule_wd; | |
> end | |
> | |
> @ @d billion==float_constant(1000000000) | |
> @d vet_glue(#)== glue_temp:=#; | |
> if glue_temp>billion then | |
> glue_temp:=billion | |
> else if glue_temp<-billion then | |
> glue_temp:=-billion | |
> | |
> @<Move right or output leaders@>= | |
> begin g:=glue_ptr(p); rule_wd:=width(g)-cur_g; | |
> if g_sign<>normal then | |
> begin if g_sign=stretching then | |
> begin if stretch_order(g)=g_order then | |
> begin cur_glue:=cur_glue+stretch(g); | |
> vet_glue(float(glue_set(this_box))*cur_glue); | |
> @^real multiplication@> | |
> cur_g:=round(glue_temp); | |
> end; | |
> end | |
> else if shrink_order(g)=g_order then | |
> begin cur_glue:=cur_glue-shrink(g); | |
> vet_glue(float(glue_set(this_box))*cur_glue); | |
> cur_g:=round(glue_temp); | |
> end; | |
> end; | |
> rule_wd:=rule_wd+cur_g; | |
> if subtype(p)>=a_leaders then | |
> @<Output leaders in an hlist, |goto fin_rule| if a rule | |
> or to |next_p| if done@>; | |
> goto move_past; | |
9941c12355 | |
< begin leader_box←leader_ptr(p); | |
--- | |
> begin leader_box:=leader_ptr(p); | |
9943,9955c12357,12370 | |
< begin rule_ht←height(leader_box); rule_dp←depth(leader_box); | |
< goto fin_rule; | |
< end; | |
< leader_wd←width(leader_box); | |
< if (leader_wd>0)∧(rule_wd>0) then | |
< begin edge←cur_h+rule_wd; | |
< @<Let |cur_h| be the position of the first box, and set |leader_wd| | |
< to the spacing between corresponding parts of boxes@>; | |
< while cur_h+leader_wd≤edge do | |
< @<Output a leader box at |cur_h|, | |
< then advance |cur_h| by |leader_wd|@>; | |
< cur_h←edge; goto next_p; | |
< end; | |
--- | |
> begin rule_ht:=height(leader_box); rule_dp:=depth(leader_box); | |
> goto fin_rule; | |
> end; | |
> leader_wd:=width(leader_box); | |
> if (leader_wd>0)and(rule_wd>0) then | |
> begin rule_wd:=rule_wd+10; {compensate for floating-point rounding} | |
> edge:=cur_h+rule_wd; lx:=0; | |
> @<Let |cur_h| be the position of the first box, and set |leader_wd+lx| | |
> to the spacing between corresponding parts of boxes@>; | |
> while cur_h+leader_wd<=edge do | |
> @<Output a leader box at |cur_h|, | |
> then advance |cur_h| by |leader_wd+lx|@>; | |
> cur_h:=edge-10; goto next_p; | |
> end; | |
9959,9963c12374,12380 | |
< case of |a_leaders| (aligned leaders), we want to move |cur_h| to the | |
< smallest multiple of |leader_wd| that is not less than the current | |
< value of |cur_h|, namely $|leader_wd|\ast\lceil |cur_h|/|leader_wd|\rceil$. | |
< The program here should work in all cases even though \PASCAL\ does not define | |
< the |div| operation precisely, and even when |cur_h| is negative. | |
--- | |
> case of |a_leaders| (aligned leaders), we want to move |cur_h| to | |
> |left_edge| plus the smallest multiple of |leader_wd| for which the result | |
> is not less than the current value of |cur_h|; i.e., |cur_h| should become | |
> $|left_edge|+|leader_wd|\times\lceil | |
> (|cur_h|-|left_edge|)/|leader_wd|\rceil$. The program here should work in | |
> all cases even though some implementations of \PASCAL\ give nonstandard | |
> results for the |div| operation when |cur_h| is less than |left_edge|. | |
9966,9967c12383,12384 | |
< by half of the excess space not occupied by the leaders; and in the case of | |
< case of |x_leaders| (expanded leaders) we increase both |cur_h| and |leader_wd| | |
--- | |
> by half of the excess space not occupied by the leaders; and in the | |
> case of |x_leaders| (expanded leaders) we increase |cur_h| | |
9974,9984c12391,12401 | |
< begin save_h←cur_h; cur_h←leader_wd*(cur_h @!div leader_wd); | |
< if cur_h<save_h then cur_h←cur_h+leader_wd; | |
< end | |
< else begin lq←rule_wd div leader_wd; {the number of box copies} | |
< lr←rule_wd mod leader_wd; {the remaining space} | |
< if subtype(p)=c_leaders then cur_h←cur_h+(lr div 2) | |
< else begin lx←(2*lr+lq+1) div (2*lq+2); {round|(lr/(q+1))|} | |
< leader_wd←leader_wd+lx; | |
< cur_h←cur_h+((lr-(lq-1)*lx) div 2); | |
< end; | |
< end | |
--- | |
> begin save_h:=cur_h; | |
> cur_h:=left_edge+leader_wd*((cur_h-left_edge)@!div leader_wd); | |
> if cur_h<save_h then cur_h:=cur_h+leader_wd; | |
> end | |
> else begin lq:=rule_wd div leader_wd; {the number of box copies} | |
> lr:=rule_wd mod leader_wd; {the remaining space} | |
> if subtype(p)=c_leaders then cur_h:=cur_h+(lr div 2) | |
> else begin lx:=lr div (lq+1); | |
> cur_h:=cur_h+((lr-(lq-1)*lx) div 2); | |
> end; | |
> end | |
9986,9987c12403,12404 | |
< @ The `\\{synch}' operations here are intended to decrease the number | |
< of bytes needed to specify horizontal and vertical motion in the \.{DVI} output. | |
--- | |
> @ The `\\{synch}' operations here are intended to decrease the number of | |
> bytes needed to specify horizontal and vertical motion in the \.{DVI} output. | |
9990,9992c12407,12409 | |
< begin cur_v←base_line+shift_amount(leader_box); synch_v; save_v←dvi_v;@/ | |
< synch_h; save_h←dvi_h; dvi_out(push); temp_ptr←leader_box; | |
< outer_doing_leaders←doing_leaders; doing_leaders←true; | |
--- | |
> begin cur_v:=base_line+shift_amount(leader_box); synch_v; save_v:=dvi_v;@/ | |
> synch_h; save_h:=dvi_h; temp_ptr:=leader_box; | |
> outer_doing_leaders:=doing_leaders; doing_leaders:=true; | |
9994,9996c12411,12413 | |
< doing_leaders←outer_doing_leaders; | |
< dvi_out(pop); dvi_v←save_v; dvi_h←save_h; cur_v←save_v; | |
< cur_h←save_h+leader_wd; | |
--- | |
> doing_leaders:=outer_doing_leaders; | |
> dvi_v:=save_v; dvi_h:=save_h; cur_v:=base_line; | |
> cur_h:=save_h+leader_wd+lx; | |
10002c12419 | |
< label advance, fin_rule, next_p; | |
--- | |
> label move_past, fin_rule, next_p; | |
10003a12421 | |
> @!top_edge: scaled; {the top coordinate for this box} | |
10011a12430 | |
> @!lx:scaled; {extra space between leader boxes} | |
10014,10015c12433,12438 | |
< begin this_box←temp_ptr; g_order←glue_order(this_box); | |
< g_sign←glue_sign(this_box); p←list_ptr(this_box); | |
--- | |
> @!glue_temp:real; {glue value before rounding} | |
> @!cur_glue:real; {glue seen so far} | |
> @!cur_g:scaled; {rounded equivalent of |cur_glue| times the glue ratio} | |
> begin cur_g:=0; cur_glue:=float_constant(0); | |
> this_box:=temp_ptr; g_order:=glue_order(this_box); | |
> g_sign:=glue_sign(this_box); p:=list_ptr(this_box); | |
10017,10021c12440,12448 | |
< if cur_s>max_push then max_push←cur_s; | |
< save_loc←dvi_offset+dvi_ptr; left_edge←cur_h; cur_v←cur_v-height(this_box); | |
< while p≠null do @<Output node |p| for |vlist_out| and move to the next node, | |
< maintaining the condition |cur_h=left_edge|@>; | |
< prune_movements(save_loc); decr(cur_s); | |
--- | |
> if cur_s>0 then dvi_out(push); | |
> if cur_s>max_push then max_push:=cur_s; | |
> save_loc:=dvi_offset+dvi_ptr; left_edge:=cur_h; cur_v:=cur_v-height(this_box); | |
> top_edge:=cur_v; | |
> while p<>null do @<Output node |p| for |vlist_out| and move to the next node, | |
> maintaining the condition |cur_h=left_edge|@>; | |
> prune_movements(save_loc); | |
> if cur_s>0 then dvi_pop(save_loc); | |
> decr(cur_s); | |
10026c12453 | |
< @:confusion vlistout}{\quad vlistout@> | |
--- | |
> @:this can't happen vlistout}{\quad vlistout@> | |
10028c12455 | |
< next_p:p←link(p); | |
--- | |
> next_p:p:=link(p); | |
10034,10036c12461,12463 | |
< rule_node: begin rule_ht←height(p); rule_dp←depth(p); rule_wd←width(p); | |
< goto fin_rule; | |
< end; | |
--- | |
> rule_node: begin rule_ht:=height(p); rule_dp:=depth(p); rule_wd:=width(p); | |
> goto fin_rule; | |
> end; | |
10039c12466 | |
< kern_node:cur_v←cur_v+width(p); | |
--- | |
> kern_node:cur_v:=cur_v+width(p); | |
10044c12471 | |
< advance: cur_v←cur_v+rule_ht; | |
--- | |
> move_past: cur_v:=cur_v+rule_ht; | |
10052,10060c12479,12487 | |
< if list_ptr(p)=null then cur_v←cur_v+height(p)+depth(p) | |
< else begin cur_v←cur_v+height(p); synch_v; | |
< save_h←dvi_h; save_v←dvi_v; dvi_out(push); | |
< cur_h←left_edge+shift_amount(p); {shift the box right} | |
< temp_ptr←p; | |
< if type(p)=vlist_node then vlist_out@+else hlist_out; | |
< dvi_out(pop); dvi_h←save_h; dvi_v←save_v; | |
< cur_v←save_v+depth(p); cur_h←left_edge; | |
< end | |
--- | |
> if list_ptr(p)=null then cur_v:=cur_v+height(p)+depth(p) | |
> else begin cur_v:=cur_v+height(p); synch_v; | |
> save_h:=dvi_h; save_v:=dvi_v; | |
> cur_h:=left_edge+shift_amount(p); {shift the box right} | |
> temp_ptr:=p; | |
> if type(p)=vlist_node then vlist_out@+else hlist_out; | |
> dvi_h:=save_h; dvi_v:=save_v; | |
> cur_v:=save_v+depth(p); cur_h:=left_edge; | |
> end | |
10063,10069c12490,12496 | |
< if is_running(rule_wd) then rule_wd←width(this_box); | |
< rule_ht←rule_ht+rule_dp; {this is the rule thickness} | |
< cur_v←cur_v+rule_ht; | |
< if (rule_ht>0)∧(rule_wd>0) then {we don't output empty rules} | |
< begin synch_h; synch_v; | |
< dvi_out(put_rule); dvi_four(rule_ht); dvi_four(rule_wd); | |
< end; | |
--- | |
> if is_running(rule_wd) then rule_wd:=width(this_box); | |
> rule_ht:=rule_ht+rule_dp; {this is the rule thickness} | |
> cur_v:=cur_v+rule_ht; | |
> if (rule_ht>0)and(rule_wd>0) then {we don't output empty rules} | |
> begin synch_h; synch_v; | |
> dvi_out(put_rule); dvi_four(rule_ht); dvi_four(rule_wd); | |
> end; | |
10073,10086c12500,12520 | |
< begin g←glue_ptr(p); rule_ht←width(g); | |
< if g_sign≠normal then | |
< begin if g_sign=stretching then | |
< begin if stretch_order(g)=g_order then | |
< rule_ht←rule_ht+round(glue_set(this_box)*stretch(g)); | |
< end | |
< else begin if shrink_order(g)=g_order then | |
< rule_ht←rule_ht-round(glue_set(this_box)*shrink(g)); | |
< end; | |
< end; | |
< if subtype(p)≥a_leaders then | |
< @<Output leaders in a vlist, |goto fin_rule| if a rule | |
< or to |next_p| if done@>; | |
< goto advance; | |
--- | |
> begin g:=glue_ptr(p); rule_ht:=width(g)-cur_g; | |
> if g_sign<>normal then | |
> begin if g_sign=stretching then | |
> begin if stretch_order(g)=g_order then | |
> begin cur_glue:=cur_glue+stretch(g); | |
> vet_glue(float(glue_set(this_box))*cur_glue); | |
> @^real multiplication@> | |
> cur_g:=round(glue_temp); | |
> end; | |
> end | |
> else if shrink_order(g)=g_order then | |
> begin cur_glue:=cur_glue-shrink(g); | |
> vet_glue(float(glue_set(this_box))*cur_glue); | |
> cur_g:=round(glue_temp); | |
> end; | |
> end; | |
> rule_ht:=rule_ht+cur_g; | |
> if subtype(p)>=a_leaders then | |
> @<Output leaders in a vlist, |goto fin_rule| if a rule | |
> or to |next_p| if done@>; | |
> goto move_past; | |
10090c12524 | |
< begin leader_box←leader_ptr(p); | |
--- | |
> begin leader_box:=leader_ptr(p); | |
10092,10104c12526,12539 | |
< begin rule_wd←width(leader_box); rule_dp←0; | |
< goto fin_rule; | |
< end; | |
< leader_ht←height(leader_box)+depth(leader_box); | |
< if (leader_ht>0)∧(rule_ht>0) then | |
< begin edge←cur_v+rule_ht; | |
< @<Let |cur_v| be the position of the first box, and set |leader_ht| | |
< to the spacing between corresponding parts of boxes@>; | |
< while cur_v+leader_ht≤edge do | |
< @<Output a leader box at |cur_v|, | |
< then advance |cur_v| by |leader_ht|@>; | |
< cur_v←edge; goto next_p; | |
< end; | |
--- | |
> begin rule_wd:=width(leader_box); rule_dp:=0; | |
> goto fin_rule; | |
> end; | |
> leader_ht:=height(leader_box)+depth(leader_box); | |
> if (leader_ht>0)and(rule_ht>0) then | |
> begin rule_ht:=rule_ht+10; {compensate for floating-point rounding} | |
> edge:=cur_v+rule_ht; lx:=0; | |
> @<Let |cur_v| be the position of the first box, and set |leader_ht+lx| | |
> to the spacing between corresponding parts of boxes@>; | |
> while cur_v+leader_ht<=edge do | |
> @<Output a leader box at |cur_v|, | |
> then advance |cur_v| by |leader_ht+lx|@>; | |
> cur_v:=edge-10; goto next_p; | |
> end; | |
10109,10119c12544,12554 | |
< begin save_v←cur_v; cur_v←leader_ht*(cur_v @!div leader_ht); | |
< if cur_v<save_v then cur_v←cur_v+leader_ht; | |
< end | |
< else begin lq←rule_ht div leader_ht; {the number of box copies} | |
< lr←rule_ht mod leader_ht; {the remaining space} | |
< if subtype(p)=c_leaders then cur_v←cur_v+(lr div 2) | |
< else begin lx←(2*lr+lq+1) div (2*lq+2); {round|(lr/(q+1))|} | |
< leader_ht←leader_ht+lx; | |
< cur_v←cur_v+((lr-(lq-1)*lx) div 2); | |
< end; | |
< end | |
--- | |
> begin save_v:=cur_v; | |
> cur_v:=top_edge+leader_ht*((cur_v-top_edge)@!div leader_ht); | |
> if cur_v<save_v then cur_v:=cur_v+leader_ht; | |
> end | |
> else begin lq:=rule_ht div leader_ht; {the number of box copies} | |
> lr:=rule_ht mod leader_ht; {the remaining space} | |
> if subtype(p)=c_leaders then cur_v:=cur_v+(lr div 2) | |
> else begin lx:=lr div (lq+1); | |
> cur_v:=cur_v+((lr-(lq-1)*lx) div 2); | |
> end; | |
> end | |
10125,10128c12560,12563 | |
< begin cur_h←left_edge+shift_amount(leader_box); synch_h; save_h←dvi_h;@/ | |
< cur_v←cur_v+height(leader_box); synch_v; save_v←dvi_v; | |
< dvi_out(push); temp_ptr←leader_box; | |
< outer_doing_leaders←doing_leaders; doing_leaders←true; | |
--- | |
> begin cur_h:=left_edge+shift_amount(leader_box); synch_h; save_h:=dvi_h;@/ | |
> cur_v:=cur_v+height(leader_box); synch_v; save_v:=dvi_v; | |
> temp_ptr:=leader_box; | |
> outer_doing_leaders:=doing_leaders; doing_leaders:=true; | |
10130,10132c12565,12567 | |
< doing_leaders←outer_doing_leaders; | |
< dvi_out(pop); dvi_v←save_v; dvi_h←save_h; cur_h←save_h; | |
< cur_v←save_v-height(leader_box)+leader_ht; | |
--- | |
> doing_leaders:=outer_doing_leaders; | |
> dvi_v:=save_v; dvi_h:=save_h; cur_h:=left_edge; | |
> cur_v:=save_v-height(leader_box)+leader_ht+lx; | |
10138a12574 | |
> label done; | |
10140,10145c12576,12581 | |
< @!k:0..9; {runs through ten count registers} | |
< begin if tracing_output=0 then | |
< begin if offset>max_print_line-9 then print_ln@+else print_char(" "); | |
< print_char("["); print_int(count(0)); update_terminal; | |
< end | |
< else begin print_nl(""); print_nl("Completed box being shipped out ["); | |
--- | |
> @!j,@!k:0..9; {indices to first ten count registers} | |
> @!s:pool_pointer; {index into |str_pool|} | |
> @!old_setting:0..max_selector; {saved |selector| setting} | |
> begin if tracing_output>0 then | |
> begin print_nl(""); print_ln; | |
> print("Completed box being shipped out"); | |
10147,10153c12583,12596 | |
< for k←0 to 9 do | |
< begin print_int(count(k)); | |
< if k<9 then print_char("."); | |
< end; | |
< print_char("]");@/ | |
< begin_diagnostic; show_box(p); end_diagnostic; | |
< end; | |
--- | |
> end; | |
> if term_offset>max_print_line-9 then print_ln | |
> else if (term_offset>0)or(file_offset>0) then print_char(" "); | |
> print_char("["); j:=9; | |
> while (count(j)=0)and(j>0) do decr(j); | |
> for k:=0 to j do | |
> begin print_int(count(k)); | |
> if k<j then print_char("."); | |
> end; | |
> update_terminal; | |
> if tracing_output>0 then | |
> begin print_char("]"); | |
> begin_diagnostic; show_box(p); end_diagnostic(true); | |
> end; | |
10155c12598,12600 | |
< if tracing_output=0 then print_char("]"); update_terminal; {progress report} | |
--- | |
> if tracing_output<=0 then print_char("]"); | |
> dead_cycles:=0; | |
> update_terminal; {progress report} | |
10160,10164c12605,12610 | |
< stat if tracing_stats≠0 then | |
< begin print_nl("Memory usage before: "); | |
< print_int(var_used); print_char(","); | |
< print_int(dyn_used); print_char(";"); | |
< end; | |
--- | |
> @!stat if tracing_stats>1 then | |
> begin print_nl("Memory usage before: "); | |
> @.Memory usage...@> | |
> print_int(var_used); print_char("&"); | |
> print_int(dyn_used); print_char(";"); | |
> end; | |
10167,10173c12613,12618 | |
< stat if tracing_stats≠0 then | |
< begin print(" after: "); | |
< print_int(var_used); print_char(","); | |
< print_int(dyn_used); print("; max so far: "); | |
< print_int(max_var_used); print_char(","); | |
< print_int(mem_end+1-hi_mem_base); print_ln; | |
< end; | |
--- | |
> @!stat if tracing_stats>1 then | |
> begin print(" after: "); | |
> print_int(var_used); print_char("&"); | |
> print_int(dyn_used); print("; still untouched: "); | |
> print_int(hi_mem_min-lo_mem_max-1); print_ln; | |
> end; | |
10177,10178c12622,12623 | |
< if height(p)+depth(p)>max_v then max_v←height(p)+depth(p); | |
< if width(p)>max_h then max_h←width(p); | |
--- | |
> @<Update the values of |max_h| and |max_v|; but if the page is too large, | |
> |goto done|@>; | |
10180c12625 | |
< page_loc←dvi_offset+dvi_ptr; | |
--- | |
> page_loc:=dvi_offset+dvi_ptr; | |
10182,10184c12627,12629 | |
< for k←0 to 9 do dvi_four(count(k)); | |
< dvi_four(last_bop); last_bop←page_loc; | |
< cur_v←height(p); temp_ptr←p; | |
--- | |
> for k:=0 to 9 do dvi_four(count(k)); | |
> dvi_four(last_bop); last_bop:=page_loc; | |
> cur_v:=height(p)+v_offset; temp_ptr:=p; | |
10186c12631,12657 | |
< dvi_out(eop); incr(total_pages) | |
--- | |
> dvi_out(eop); incr(total_pages); cur_s:=-1; | |
> done: | |
> | |
> @ Sometimes the user will generate a huge page because other error messages | |
> are being ignored. Such pages are not output to the \.{dvi} file, since they | |
> may confuse the printing software. | |
> | |
> @<Update the values of |max_h| and |max_v|; but if the page is too large...@>= | |
> if (height(p)>max_dimen)or@|(depth(p)>max_dimen)or@| | |
> (height(p)+depth(p)+v_offset>max_dimen)or@| | |
> (width(p)+h_offset>max_dimen) then | |
> begin print_err("Huge page cannot be shipped out"); | |
> @.Huge page...@> | |
> help2("The page just created is more than 18 feet tall or")@/ | |
> ("more than 18 feet wide, so I suspect something went wrong."); | |
> error; | |
> if tracing_output<=0 then | |
> begin begin_diagnostic; | |
> print_nl("The following box has been deleted:"); | |
> @.The following...deleted@> | |
> show_box(p); | |
> end_diagnostic(true); | |
> end; | |
> goto done; | |
> end; | |
> if height(p)+depth(p)+v_offset>max_v then max_v:=height(p)+depth(p)+v_offset; | |
> if width(p)+h_offset>max_h then max_h:=width(p)+h_offset | |
10189a12661,12662 | |
> If |total_pages>=65536|, the \.{DVI} file will lie. And if | |
> |max_push>=65536|, the user deserves whatever chaos might ensue. | |
10194,10212c12667,12695 | |
< if total_pages=0 then print_nl("No output file.") | |
< else begin dvi_out(pst); {beginning of the postamble} | |
< dvi_four(last_bop); last_bop←dvi_offset+dvi_ptr-5; {|pst| location} | |
< dvi_four(25400000); dvi_four(473628672); {conversion ratio for sp} | |
< prepare_mag; dvi_four(mag); {magnification factor} | |
< dvi_four(max_v); dvi_four(max_h);@/ | |
< dvi_out(max_push div 256); dvi_out(max_push mod 256);@/ | |
< dvi_out(total_pages div 256); dvi_out(total_pages mod 256);@/ | |
< @<Output the font definitions for all fonts that were used@>; | |
< dvi_four(-1); dvi_four(last_bop); dvi_out(id_byte); | |
< k←4+((dvi_buf_size-dvi_ptr) mod 4); {the number of 223's} | |
< while k>0 do | |
< begin dvi_out(223); decr(k); | |
< end; | |
< @<Empty the last bytes out of |dvi_buf|@>; | |
< print_nl("Output written on "); print(output_file_name); | |
< print(" ("); print_int(total_pages); print(" pages, "); | |
< print_int(dvi_offset+dvi_ptr); print(" bytes)."); b_close(dvi_file); | |
< end | |
--- | |
> while cur_s>-1 do | |
> begin if cur_s>0 then dvi_out(pop) | |
> else begin dvi_out(eop); incr(total_pages); | |
> end; | |
> decr(cur_s); | |
> end; | |
> if total_pages=0 then print_nl("No pages of output.") | |
> @.No pages of output@> | |
> else begin dvi_out(post); {beginning of the postamble} | |
> dvi_four(last_bop); last_bop:=dvi_offset+dvi_ptr-5; {|post| location} | |
> dvi_four(25400000); dvi_four(473628672); {conversion ratio for sp} | |
> prepare_mag; dvi_four(mag); {magnification factor} | |
> dvi_four(max_v); dvi_four(max_h);@/ | |
> dvi_out(max_push div 256); dvi_out(max_push mod 256);@/ | |
> dvi_out((total_pages div 256) mod 256); dvi_out(total_pages mod 256);@/ | |
> @<Output the font definitions for all fonts that were used@>; | |
> dvi_out(post_post); dvi_four(last_bop); dvi_out(id_byte);@/ | |
> k:=4+((dvi_buf_size-dvi_ptr) mod 4); {the number of 223's} | |
> while k>0 do | |
> begin dvi_out(223); decr(k); | |
> end; | |
> @<Empty the last bytes out of |dvi_buf|@>; | |
> print_nl("Output written on "); slow_print(output_file_name); | |
> @.Output written on x@> | |
> print(" ("); print_int(total_pages); print(" page"); | |
> if total_pages<>1 then print_char("s"); | |
> print(", "); print_int(dvi_offset+dvi_ptr); print(" bytes)."); | |
> b_close(dvi_file); | |
> end | |
10216,10234c12699,12703 | |
< begin if font_used[font_ptr] then | |
< begin dvi_four(font_ptr-font_base-1); | |
< dvi_out(qo(font_check[font_ptr].b0)); | |
< dvi_out(qo(font_check[font_ptr].b1)); | |
< dvi_out(qo(font_check[font_ptr].b2)); | |
< dvi_out(qo(font_check[font_ptr].b3)); | |
< dvi_four(font_size[font_ptr]); | |
< dvi_out(length(font_area[font_ptr])); | |
< dvi_out(length(font_name[font_ptr])); | |
< @<Output the font name whose internal number is |font_ptr|@>; | |
< end; | |
< decr(font_ptr); | |
< end | |
< @ @<Output the font name whose internal number is |font_ptr|@>= | |
< for k←str_start[font_area[font_ptr]] to str_start[font_area[font_ptr]+1]-1 do | |
< dvi_out(str_pool[k]); | |
< for k←str_start[font_name[font_ptr]] to str_start[font_name[font_ptr]+1]-1 do | |
< dvi_out(str_pool[k]) | |
< @* \[32] Packaging. | |
--- | |
> begin if font_used[font_ptr] then dvi_font_def(font_ptr); | |
> decr(font_ptr); | |
> end | |
> | |
> @* \[33] Packaging. | |
10245c12714 | |
< inside the new box, but some items may stick out if negative glue is used, | |
--- | |
> inside the new box; but some items may stick out if negative glue is used, | |
10251,10252c12720,12721 | |
< a width; and pa\-ram\-eter |m| is either `|exactly|' or `|additional|'. Thus, | |
< |hpack(p,w,exactly)| pro\-duces a box whose width is exactly |w|, while | |
--- | |
> a width; and parameter |m| is either `|exactly|' or `|additional|'. Thus, | |
> |hpack(p,w,exactly)| produces a box whose width is exactly |w|, while | |
10267c12736 | |
< like `\.{\\hbox} \.{to} \.{300pt}', `\.{\\hbox} \.{expand} \.{10pt}'; note | |
--- | |
> like `\.{\\hbox} \.{to} \.{300pt}', `\.{\\hbox} \.{spread} \.{10pt}'; note | |
10269c12738 | |
< `\.{\\hbox} \.{expand} \.{0pt}'. The |scan_spec| subroutine scans such | |
--- | |
> `\.{\\hbox} \.{spread} \.{0pt}'. The |scan_spec| subroutine scans such | |
10274c12743 | |
< |save_ptr←save_ptr-2;|\cr | |
--- | |
> |save_ptr:=save_ptr-2;|\cr | |
10275a12745,12747 | |
> Special care is necessary to ensure that the special |save_stack| codes | |
> are placed just below the new group code, because scanning can change | |
> |save_stack| when \.{\\csname} appears. | |
10277c12749,12750 | |
< @p procedure scan_spec; {scans a box specification and left brace} | |
--- | |
> @p procedure scan_spec(@!c:group_code;@!three_codes:boolean); | |
> {scans a box specification and left brace} | |
10279,10285c12752,12767 | |
< begin if scan_keyword("to") then saved(0)←exactly | |
< else if scan_keyword("expand") then saved(0)←additional | |
< else begin saved(0)←additional; saved(1)←0; | |
< goto found; | |
< end; | |
< scan_dimen(false,false,false); saved(1)←cur_val; | |
< found: save_ptr←save_ptr+2; scan_left_brace; | |
--- | |
> var @!s:integer; {temporarily saved value} | |
> @!spec_code:exactly..additional; | |
> begin if three_codes then s:=saved(0); | |
> if scan_keyword("to") then spec_code:=exactly | |
> @.to@> | |
> else if scan_keyword("spread") then spec_code:=additional | |
> @.spread@> | |
> else begin spec_code:=additional; cur_val:=0; | |
> goto found; | |
> end; | |
> scan_normal_dimen; | |
> found: if three_codes then | |
> begin saved(0):=s; incr(save_ptr); | |
> end; | |
> saved(0):=spec_code; saved(1):=cur_val; save_ptr:=save_ptr+2; | |
> new_save_level(c); scan_left_brace; | |
10302c12784,12785 | |
< glue of each kind is present. | |
--- | |
> glue of each kind is present. A global variable |last_badness| is used | |
> to implement \.{\\badness}. | |
10306c12789,12795 | |
< {glue found by |hpack| or |vpack|} | |
--- | |
> {glue found by |hpack| or |vpack|} | |
> @!last_badness:integer; {badness of the most recently packaged box} | |
> | |
> @ If the global variable |adjust_tail| is non-null, the |hpack| routine | |
> also removes all occurrences of |ins_node|, |mark_node|, and |adjust_node| | |
> items and appends the resulting material onto the list that ends at | |
> location |adjust_tail|. | |
10308,10315c12797,12798 | |
< @ Here now is |hpack| itself, which contains only one possible surprise: | |
< Be\-sides making a list into a box, |hpack| also removes all occurrences of | |
< |ins_node|, |mark_node|, and |adjust_node| items; it puts the resulting | |
< material into a list that starts at location |adjustments=link(adjust_head)|. | |
< These adjustments will be put into the enclosing vertical list, if |hpack| | |
< is being called to make a line of a paragraph; otherwise such nodes cannot | |
< be present in a horizontal list, since they are syntactically forbidden in | |
< restricted horizontal mode. | |
--- | |
> @< Glob...@>= | |
> @!adjust_tail:pointer; {tail of adjustment list} | |
10317c12800,12802 | |
< @d adjustments==link(adjust_head) | |
--- | |
> @ @<Set init...@>=adjust_tail:=null; last_badness:=0; | |
> | |
> @ Here now is |hpack|, which contains few if any surprises. | |
10329,10339c12814,12823 | |
< @!hd:quarterword; {height and depth indices for a character} | |
< @!t:pointer; {tail of the adjustment list} | |
< @!b:integer; {badness of the new box} | |
< begin r←get_node(box_node_size); type(r)←hlist_node; | |
< subtype(r)←min_quarterword; shift_amount(r)←0; | |
< q←r+list_offset; link(q)←p;@/ | |
< t←adjust_head; h←0; @<Clear dimensions to zero@>; | |
< while p≠null do @<Examine node |p| in the hlist, taking account of its effect | |
< on the dimensions of the new box, or moving it to the adjustment list; | |
< then advance |p| to the next node@>; | |
< link(t)←null; height(r)←h; depth(r)←d;@/ | |
--- | |
> @!hd:eight_bits; {height and depth indices for a character} | |
> begin last_badness:=0; r:=get_node(box_node_size); type(r):=hlist_node; | |
> subtype(r):=min_quarterword; shift_amount(r):=0; | |
> q:=r+list_offset; link(q):=p;@/ | |
> h:=0; @<Clear dimensions to zero@>; | |
> while p<>null do @<Examine node |p| in the hlist, taking account of its effect | |
> on the dimensions of the new box, or moving it to the adjustment list; | |
> then advance |p| to the next node@>; | |
> if adjust_tail<>null then link(adjust_tail):=null; | |
> height(r):=h; depth(r):=d;@/ | |
10341c12825 | |
< then |return| or |goto common_ending|@>; | |
--- | |
> then |return| or |goto common_ending|@>; | |
10343,10344c12827,12828 | |
< for an overfull or underfull hbox@>; | |
< exit: hpack←r; | |
--- | |
> for an overfull or underfull hbox@>; | |
> exit: hpack:=r; | |
10348,10351c12832,12836 | |
< d←0; x←0; | |
< for o←normal to filll do | |
< begin total_stretch[o]←0; total_shrink[o]←0; | |
< end | |
--- | |
> d:=0; x:=0; | |
> total_stretch[normal]:=0; total_shrink[normal]:=0; | |
> total_stretch[fil]:=0; total_shrink[fil]:=0; | |
> total_stretch[fill]:=0; total_shrink[fill]:=0; | |
> total_stretch[filll]:=0; total_shrink[filll]:=0 | |
10353a12839 | |
> @^inner loop@> | |
10355,10372c12841,12858 | |
< @<Incorporate character dimensions into the dimensions of | |
< the hbox that will contain@@it, then move to the next node@>; | |
< if p≠null then | |
< begin case type(p) of | |
< hlist_node,vlist_node,rule_node,unset_node: | |
< @<Incorporate box dimensions into the dimensions of | |
< the hbox that will contain@@it@>; | |
< ins_node,mark_node,adjust_node: | |
< @<Transfer node |p| to the adjustment list@>; | |
< whatsit_node:@<Incorporate a whatsit node into an hbox@>; | |
< glue_node:@<Incorporate glue into the totals@>; | |
< kern_node,math_node: x←x+width(p); | |
< ligature_node: @<Make node |p| look like a |char_node| | |
< and |goto reswitch|@>; | |
< othercases do_nothing | |
< endcases;@/ | |
< p←link(p); | |
< end; | |
--- | |
> @<Incorporate character dimensions into the dimensions of | |
> the hbox that will contain~it, then move to the next node@>; | |
> if p<>null then | |
> begin case type(p) of | |
> hlist_node,vlist_node,rule_node,unset_node: | |
> @<Incorporate box dimensions into the dimensions of | |
> the hbox that will contain~it@>; | |
> ins_node,mark_node,adjust_node: if adjust_tail<>null then | |
> @<Transfer node |p| to the adjustment list@>; | |
> whatsit_node:@<Incorporate a whatsit node into an hbox@>; | |
> glue_node:@<Incorporate glue into the horizontal totals@>; | |
> kern_node,math_node: x:=x+width(p); | |
> ligature_node: @<Make node |p| look like a |char_node| | |
> and |goto reswitch|@>; | |
> othercases do_nothing | |
> endcases;@/ | |
> p:=link(p); | |
> end; | |
10377,10378c12863,12864 | |
< begin mem[lig_trick]←mem[lig_char(p)]; link(lig_trick)←link(p); | |
< p←lig_trick; goto reswitch; | |
--- | |
> begin mem[lig_trick]:=mem[lig_char(p)]; link(lig_trick):=link(p); | |
> p:=lig_trick; goto reswitch; | |
10381,10385c12867,12875 | |
< @ @<Incorporate box dimensions into the dimensions of the hbox...@>= | |
< begin x←x+width(p); | |
< if type(p)≥rule_node then s←0 @+else s←shift_amount(p); | |
< if height(p)-s>h then h←height(p)-s; | |
< if depth(p)+s>d then d←depth(p)+s; | |
--- | |
> @ The code here implicitly uses the fact that running dimensions are | |
> indicated by |null_flag|, which will be ignored in the calculations | |
> because it is a highly negative number. | |
> | |
> @<Incorporate box dimensions into the dimensions of the hbox...@>= | |
> begin x:=x+width(p); | |
> if type(p)>=rule_node then s:=0 @+else s:=shift_amount(p); | |
> if height(p)-s>h then h:=height(p)-s; | |
> if depth(p)+s>d then d:=depth(p)+s; | |
10394,10398c12884,12888 | |
< begin f←font(p); i←char_info(f)(character(p)); hd←height_depth(i); | |
< x←x+char_width(f)(i);@/ | |
< s←char_height(f)(hd);@+if s>h then h←s; | |
< s←char_depth(f)(hd);@+if s>d then d←s; | |
< p←link(p); | |
--- | |
> begin f:=font(p); i:=char_info(f)(character(p)); hd:=height_depth(i); | |
> x:=x+char_width(f)(i);@/ | |
> s:=char_height(f)(hd);@+if s>h then h:=s; | |
> s:=char_depth(f)(hd);@+if s>d then d:=s; | |
> p:=link(p); | |
10405a12896 | |
> @^inner loop@> | |
10408c12899 | |
< begin while link(q)≠p do q←link(q); | |
--- | |
> begin while link(q)<>p do q:=link(q); | |
10410,10422c12901,12918 | |
< begin link(t)←adjust_ptr(p); | |
< while link(t)≠null do t←link(t); | |
< p←link(p); free_node(link(q),small_node_size); | |
< end | |
< else begin link(t)←p; t←p; p←link(p); | |
< end; | |
< link(q)←p; p←q; | |
< end | |
< | |
< @ @<Incorporate glue into the totals@>= | |
< begin g←glue_ptr(p); x←x+width(g);@/ | |
< o←stretch_order(g); total_stretch[o]←total_stretch[o]+stretch(g); | |
< o←shrink_order(g); total_shrink[o]←total_shrink[o]+shrink(g); | |
--- | |
> begin link(adjust_tail):=adjust_ptr(p); | |
> while link(adjust_tail)<>null do adjust_tail:=link(adjust_tail); | |
> p:=link(p); free_node(link(q),small_node_size); | |
> end | |
> else begin link(adjust_tail):=p; adjust_tail:=p; p:=link(p); | |
> end; | |
> link(q):=p; p:=q; | |
> end | |
> | |
> @ @<Incorporate glue into the horizontal totals@>= | |
> begin g:=glue_ptr(p); x:=x+width(g);@/ | |
> o:=stretch_order(g); total_stretch[o]:=total_stretch[o]+stretch(g); | |
> o:=shrink_order(g); total_shrink[o]:=total_shrink[o]+shrink(g); | |
> if subtype(p)>=a_leaders then | |
> begin g:=leader_ptr(p); | |
> if height(g)>h then h:=height(g); | |
> if depth(g)>d then d:=depth(g); | |
> end; | |
10429,10430c12925,12926 | |
< if m=additional then w←x+w; | |
< width(r)←w; x←w-x; {now |x| is the excess to be made up} | |
--- | |
> if m=additional then w:=x+w; | |
> width(r):=w; x:=w-x; {now |x| is the excess to be made up} | |
10432,10434c12928,12931 | |
< begin glue_sign(r)←normal; glue_order(r)←normal; glue_set(r)←0.0; | |
< return; | |
< end | |
--- | |
> begin glue_sign(r):=normal; glue_order(r):=normal; | |
> set_glue_ratio_zero(glue_set(r)); | |
> return; | |
> end | |
10436c12933 | |
< or \hbox{|goto common_ending|}@> | |
--- | |
> or \hbox{|goto common_ending|}@> | |
10438c12935 | |
< or \hbox{|goto common_ending|}@> | |
--- | |
> or \hbox{|goto common_ending|}@> | |
10442,10447c12939,12947 | |
< glue_order(r)←o; glue_sign(r)←stretching; | |
< if total_stretch[o]=0 then glue_set(r)←0.0 {there's nothing to stretch} | |
< else glue_set(r)←x/total_stretch[o]; | |
< if (hbadness<inf_bad)∧(o=normal)∧(list_ptr(r)≠null) then | |
< @<Report an underfull hbox and |goto common_ending|, if this box | |
< is sufficiently bad@>; | |
--- | |
> glue_order(r):=o; glue_sign(r):=stretching; | |
> if total_stretch[o]<>0 then glue_set(r):=unfloat(x/total_stretch[o]) | |
> @^real division@> | |
> else begin glue_sign(r):=normal; | |
> set_glue_ratio_zero(glue_set(r)); {there's nothing to stretch} | |
> end; | |
> if o=normal then if list_ptr(r)<>null then | |
> @<Report an underfull hbox and |goto common_ending|, if this box | |
> is sufficiently bad@>; | |
10452,10455c12952,12955 | |
< if total_stretch[filll]≠0 then o←filll | |
< else if total_stretch[fill]≠0 then o←fill | |
< else if total_stretch[fil]≠0 then o←fil | |
< else o←normal | |
--- | |
> if total_stretch[filll]<>0 then o:=filll | |
> else if total_stretch[fill]<>0 then o:=fill | |
> else if total_stretch[fil]<>0 then o:=fil | |
> else o:=normal | |
10458,10464c12958,12966 | |
< begin b←badness(x,total_stretch[normal]); | |
< if b>hbadness then | |
< begin print_ln; | |
< if b>100 then print_nl("Underfull")@+else print_nl("Loose"); | |
< print(" \hbox (badness "); print_int(b); | |
< goto common_ending; | |
< end; | |
--- | |
> begin last_badness:=badness(x,total_stretch[normal]); | |
> if last_badness>hbadness then | |
> begin print_ln; | |
> if last_badness>100 then print_nl("Underfull")@+else print_nl("Loose"); | |
> print(" \hbox (badness "); print_int(last_badness); | |
> @.Underfull \\hbox...@> | |
> @.Loose \\hbox...@> | |
> goto common_ending; | |
> end; | |
10468,10469c12970,12972 | |
< box originated, we use a global variable |par_begin_line| that is | |
< set nonzero only when |hpack| is being called by the paragraph builder. | |
--- | |
> box originated, we use a global variable |pack_begin_line| that is | |
> set nonzero only when |hpack| is being called by the paragraph builder | |
> or the alignment finishing routine. | |
10472c12975,12976 | |
< @!par_begin_line:integer; {source file line where the current paragraph began} | |
--- | |
> @!pack_begin_line:integer; {source file line where the current paragraph | |
> or alignment began; a negative value denotes alignment} | |
10475c12979 | |
< par_begin_line←0; | |
--- | |
> pack_begin_line:=0; | |
10479,10485c12983,12991 | |
< else begin if par_begin_line≠0 then | |
< begin print(") in paragraph at lines "); print_int(par_begin_line); | |
< print("--"); | |
< end | |
< else print(") detected at line "); | |
< print_int(line); | |
< end; | |
--- | |
> else begin if pack_begin_line<>0 then | |
> begin if pack_begin_line>0 then print(") in paragraph at lines ") | |
> else print(") in alignment at lines "); | |
> print_int(abs(pack_begin_line)); | |
> print("--"); | |
> end | |
> else print(") detected at line "); | |
> print_int(line); | |
> end; | |
10487,10488c12993,12994 | |
< font_in_short_display←undefined_font; short_display(list_ptr(r)); print_ln;@/ | |
< begin_diagnostic; show_box(r); end_diagnostic | |
--- | |
> font_in_short_display:=null_font; short_display(list_ptr(r)); print_ln;@/ | |
> begin_diagnostic; show_box(r); end_diagnostic(true) | |
10492,10502c12998,13012 | |
< glue_order(r)←o; glue_sign(r)←shrinking; | |
< if total_shrink[o]=0 then glue_set(r)←0.0 {there's nothing to shrink} | |
< else glue_set(r)←-x/total_shrink[o]; | |
< if (total_shrink[o]<-x)∧(o=normal)∧(list_ptr(r)≠null) then | |
< begin glue_set(r)←1.0; {this is the maximum shrinkage} | |
< @<Report an overfull hbox and |goto common_ending|, if this box | |
< is sufficiently bad@>; | |
< end | |
< else if (hbadness<100)∧(o=normal)∧(list_ptr(r)≠null) then | |
< @<Report a tight hbox and |goto common_ending|, if this box | |
< is sufficiently bad@>; | |
--- | |
> glue_order(r):=o; glue_sign(r):=shrinking; | |
> if total_shrink[o]<>0 then glue_set(r):=unfloat((-x)/total_shrink[o]) | |
> @^real division@> | |
> else begin glue_sign(r):=normal; | |
> set_glue_ratio_zero(glue_set(r)); {there's nothing to shrink} | |
> end; | |
> if (total_shrink[o]<-x)and(o=normal)and(list_ptr(r)<>null) then | |
> begin last_badness:=1000000; | |
> set_glue_ratio_one(glue_set(r)); {use the maximum shrinkage} | |
> @<Report an overfull hbox and |goto common_ending|, if this box | |
> is sufficiently bad@>; | |
> end | |
> else if o=normal then if list_ptr(r)<>null then | |
> @<Report a tight hbox and |goto common_ending|, if this box | |
> is sufficiently bad@>; | |
10507,10510c13017,13020 | |
< if total_shrink[filll]≠0 then o←filll | |
< else if total_shrink[fill]≠0 then o←fill | |
< else if total_shrink[fil]≠0 then o←fil | |
< else o←normal | |
--- | |
> if total_shrink[filll]<>0 then o:=filll | |
> else if total_shrink[fill]<>0 then o:=fill | |
> else if total_shrink[fil]<>0 then o:=fil | |
> else o:=normal | |
10513,10522c13023,13033 | |
< if -x-total_shrink[normal]>hfuzz then | |
< begin if overfull_rule>0 then | |
< begin while link(q)≠null do q←link(q); | |
< link(q)←new_rule; | |
< width(link(q))←overfull_rule; | |
< end; | |
< print_ln; print_nl("Overfull \hbox ("); | |
< print_scaled(-x-total_shrink[normal]); print("pt too wide"); | |
< goto common_ending; | |
< end | |
--- | |
> if (-x-total_shrink[normal]>hfuzz)or(hbadness<100) then | |
> begin if (overfull_rule>0)and(-x-total_shrink[normal]>hfuzz) then | |
> begin while link(q)<>null do q:=link(q); | |
> link(q):=new_rule; | |
> width(link(q)):=overfull_rule; | |
> end; | |
> print_ln; print_nl("Overfull \hbox ("); | |
> @.Overfull \\hbox...@> | |
> print_scaled(-x-total_shrink[normal]); print("pt too wide"); | |
> goto common_ending; | |
> end | |
10525,10529c13036,13041 | |
< begin b←badness(-x,total_shrink[normal]); | |
< if b>hbadness then | |
< begin print_ln; print_nl("Tight \hbox (badness "); print_int(b); | |
< goto common_ending; | |
< end; | |
--- | |
> begin last_badness:=badness(-x,total_shrink[normal]); | |
> if last_badness>hbadness then | |
> begin print_ln; print_nl("Tight \hbox (badness "); print_int(last_badness); | |
> @.Tight \\hbox...@> | |
> goto common_ending; | |
> end; | |
10542c13054 | |
< pointer; | |
--- | |
> pointer; | |
10549,10556c13061,13067 | |
< @!b:integer; {badness of the new box} | |
< begin r←get_node(box_node_size); type(r)←vlist_node; | |
< subtype(r)←min_quarterword; shift_amount(r)←0; | |
< list_ptr(r)←p;@/ | |
< w←0; @<Clear dimensions to zero@>; | |
< while p≠null do @<Examine node |p| in the vlist, taking account of its effect | |
< on the dimensions of the new box; then advance |p| to the next node@>; | |
< width(r)←w; | |
--- | |
> begin last_badness:=0; r:=get_node(box_node_size); type(r):=vlist_node; | |
> subtype(r):=min_quarterword; shift_amount(r):=0; | |
> list_ptr(r):=p;@/ | |
> w:=0; @<Clear dimensions to zero@>; | |
> while p<>null do @<Examine node |p| in the vlist, taking account of its effect | |
> on the dimensions of the new box; then advance |p| to the next node@>; | |
> width(r):=w; | |
10558,10560c13069,13071 | |
< begin x←x+d-l; depth(r)←l; | |
< end | |
< else depth(r)←d; | |
--- | |
> begin x:=x+d-l; depth(r):=l; | |
> end | |
> else depth(r):=d; | |
10562c13073 | |
< then |return| or |goto common_ending|@>; | |
--- | |
> then |return| or |goto common_ending|@>; | |
10564,10565c13075,13076 | |
< for an overfull or underfull vbox@>; | |
< exit: vpackage←r; | |
--- | |
> for an overfull or underfull vbox@>; | |
> exit: vpackage:=r; | |
10570,10583c13081,13092 | |
< @:confusion vpack}{\quad vpack@> | |
< else case type(p) of | |
< hlist_node,vlist_node,rule_node,unset_node: | |
< @<Incorporate box dimensions into the dimensions of | |
< the vbox that will contain@@it@>; | |
< whatsit_node:@<Incorporate a whatsit node into a vbox@>; | |
< glue_node: begin x←x+d; d←0; | |
< @<Incorporate glue into the totals@>; | |
< end; | |
< kern_node: begin x←x+d+width(p); d←0; | |
< end; | |
< othercases do_nothing | |
< endcases; | |
< p←link(p); | |
--- | |
> @:this can't happen vpack}{\quad vpack@> | |
> else case type(p) of | |
> hlist_node,vlist_node,rule_node,unset_node: | |
> @<Incorporate box dimensions into the dimensions of | |
> the vbox that will contain~it@>; | |
> whatsit_node:@<Incorporate a whatsit node into a vbox@>; | |
> glue_node: @<Incorporate glue into the vertical totals@>; | |
> kern_node: begin x:=x+d+width(p); d:=0; | |
> end; | |
> othercases do_nothing | |
> endcases; | |
> p:=link(p); | |
10587,10589c13096,13109 | |
< begin x←x+d+height(p); d←depth(p); | |
< if type(p)≥rule_node then s←0 @+else s←shift_amount(p); | |
< if width(p)+s>w then w←width(p)+s; | |
--- | |
> begin x:=x+d+height(p); d:=depth(p); | |
> if type(p)>=rule_node then s:=0 @+else s:=shift_amount(p); | |
> if width(p)+s>w then w:=width(p)+s; | |
> end | |
> | |
> @ @<Incorporate glue into the vertical totals@>= | |
> begin x:=x+d; d:=0;@/ | |
> g:=glue_ptr(p); x:=x+width(g);@/ | |
> o:=stretch_order(g); total_stretch[o]:=total_stretch[o]+stretch(g); | |
> o:=shrink_order(g); total_shrink[o]:=total_shrink[o]+shrink(g); | |
> if subtype(p)>=a_leaders then | |
> begin g:=leader_ptr(p); | |
> if width(g)>w then w:=width(g); | |
> end; | |
10596,10597c13116,13117 | |
< if m=additional then h←x+h; | |
< height(r)←h; x←h-x; {now |x| is the excess to be made up} | |
--- | |
> if m=additional then h:=x+h; | |
> height(r):=h; x:=h-x; {now |x| is the excess to be made up} | |
10599,10601c13119,13122 | |
< begin glue_sign(r)←normal; glue_order(r)←normal; glue_set(r)←0.0; | |
< return; | |
< end | |
--- | |
> begin glue_sign(r):=normal; glue_order(r):=normal; | |
> set_glue_ratio_zero(glue_set(r)); | |
> return; | |
> end | |
10603c13124 | |
< or \hbox{|goto common_ending|}@> | |
--- | |
> or \hbox{|goto common_ending|}@> | |
10605c13126 | |
< or \hbox{|goto common_ending|}@> | |
--- | |
> or \hbox{|goto common_ending|}@> | |
10609,10614c13130,13138 | |
< glue_order(r)←o; glue_sign(r)←stretching; | |
< if total_stretch[o]=0 then glue_set(r)←0.0 {there's nothing to stretch} | |
< else glue_set(r)←x/total_stretch[o]; | |
< if (vbadness<inf_bad)∧(o=normal)∧(list_ptr(r)≠null) then | |
< @<Report an underfull vbox and |goto common_ending|, if this box | |
< is sufficiently bad@>; | |
--- | |
> glue_order(r):=o; glue_sign(r):=stretching; | |
> if total_stretch[o]<>0 then glue_set(r):=unfloat(x/total_stretch[o]) | |
> @^real division@> | |
> else begin glue_sign(r):=normal; | |
> set_glue_ratio_zero(glue_set(r)); {there's nothing to stretch} | |
> end; | |
> if o=normal then if list_ptr(r)<>null then | |
> @<Report an underfull vbox and |goto common_ending|, if this box | |
> is sufficiently bad@>; | |
10619,10625c13143,13151 | |
< begin b←badness(x,total_stretch[normal]); | |
< if b>vbadness then | |
< begin print_ln; | |
< if b>100 then print_nl("Underfull")@+else print_nl("Loose"); | |
< print(" \vbox (badness "); print_int(b); | |
< goto common_ending; | |
< end; | |
--- | |
> begin last_badness:=badness(x,total_stretch[normal]); | |
> if last_badness>vbadness then | |
> begin print_ln; | |
> if last_badness>100 then print_nl("Underfull")@+else print_nl("Loose"); | |
> print(" \vbox (badness "); print_int(last_badness); | |
> @.Underfull \\vbox...@> | |
> @.Loose \\vbox...@> | |
> goto common_ending; | |
> end; | |
10630,10633c13156,13165 | |
< else begin print(") detected at line "); print_int(line); | |
< print_ln;@/ | |
< end; | |
< begin_diagnostic; show_box(r); end_diagnostic | |
--- | |
> else begin if pack_begin_line<>0 then {it's actually negative} | |
> begin print(") in alignment at lines "); | |
> print_int(abs(pack_begin_line)); | |
> print("--"); | |
> end | |
> else print(") detected at line "); | |
> print_int(line); | |
> print_ln;@/ | |
> end; | |
> begin_diagnostic; show_box(r); end_diagnostic(true) | |
10637,10647c13169,13183 | |
< glue_order(r)←o; glue_sign(r)←shrinking; | |
< if total_shrink[o]=0 then glue_set(r)←0.0 {there's nothing to shrink} | |
< else glue_set(r)←-x/total_shrink[o]; | |
< if (total_shrink[o]<-x)∧(o=normal)∧(list_ptr(r)≠null) then | |
< begin glue_set(r)←1.0; {this is the maximum shrinkage} | |
< @<Report an overfull vbox and |goto common_ending|, if this box | |
< is sufficiently bad@>; | |
< end | |
< else if (vbadness<100)∧(o=normal)∧(list_ptr(r)≠null) then | |
< @<Report a tight vbox and |goto common_ending|, if this box | |
< is sufficiently bad@>; | |
--- | |
> glue_order(r):=o; glue_sign(r):=shrinking; | |
> if total_shrink[o]<>0 then glue_set(r):=unfloat((-x)/total_shrink[o]) | |
> @^real division@> | |
> else begin glue_sign(r):=normal; | |
> set_glue_ratio_zero(glue_set(r)); {there's nothing to shrink} | |
> end; | |
> if (total_shrink[o]<-x)and(o=normal)and(list_ptr(r)<>null) then | |
> begin last_badness:=1000000; | |
> set_glue_ratio_one(glue_set(r)); {use the maximum shrinkage} | |
> @<Report an overfull vbox and |goto common_ending|, if this box | |
> is sufficiently bad@>; | |
> end | |
> else if o=normal then if list_ptr(r)<>null then | |
> @<Report a tight vbox and |goto common_ending|, if this box | |
> is sufficiently bad@>; | |
10652,10656c13188,13193 | |
< if -x-total_shrink[normal]>vfuzz then | |
< begin print_ln; print_nl("Overfull \vbox ("); | |
< print_scaled(-x-total_shrink[normal]); print("pt too high"); | |
< goto common_ending; | |
< end | |
--- | |
> if (-x-total_shrink[normal]>vfuzz)or(vbadness<100) then | |
> begin print_ln; print_nl("Overfull \vbox ("); | |
> @.Overfull \\vbox...@> | |
> print_scaled(-x-total_shrink[normal]); print("pt too high"); | |
> goto common_ending; | |
> end | |
10659,10663c13196,13201 | |
< begin b←badness(-x,total_shrink[normal]); | |
< if b>vbadness then | |
< begin print_ln; print_nl("Tight \vbox (badness "); print_int(b); | |
< goto common_ending; | |
< end; | |
--- | |
> begin last_badness:=badness(-x,total_shrink[normal]); | |
> if last_badness>vbadness then | |
> begin print_ln; print_nl("Tight \vbox (badness "); print_int(last_badness); | |
> @.Tight \\vbox...@> | |
> goto common_ending; | |
> end; | |
10671,10680c13209,13218 | |
< @!p:pointer; {a new glue specification} | |
< begin if prev_depth≠ignore_depth then | |
< begin d←width(baseline_skip)-prev_depth-height(b); | |
< if d<line_skip_limit then p←new_param_glue(line_skip_code) | |
< else begin p←new_skip_param(baseline_skip_code); | |
< width(temp_ptr)←d; {|temp_ptr=glue_ptr(p)|} | |
< end; | |
< link(tail)←p; tail←p; | |
< end; | |
< link(tail)←b; tail←b; prev_depth←depth(b); | |
--- | |
> @!p:pointer; {a new glue node} | |
> begin if prev_depth>ignore_depth then | |
> begin d:=width(baseline_skip)-prev_depth-height(b); | |
> if d<line_skip_limit then p:=new_param_glue(line_skip_code) | |
> else begin p:=new_skip_param(baseline_skip_code); | |
> width(temp_ptr):=d; {|temp_ptr=glue_ptr(p)|} | |
> end; | |
> link(tail):=p; tail:=p; | |
> end; | |
> link(tail):=b; tail:=b; prev_depth:=depth(b); | |
10682c13220,13221 | |
< @* \[33] Data structures for math mode. | |
--- | |
> | |
> @* \[34] Data structures for math mode. | |
10697c13236 | |
< classi\-fied as a relation, a binary operator, an open parenthesis, etc., | |
--- | |
> classified as a relation, a binary operator, an open parenthesis, etc., | |
10715c13254 | |
< nodes, math nodes, ligature nodes, mark nodes, insert nodes, adjust nodes, | |
--- | |
> nodes, math nodes, ligature nodes, | |
10721c13260 | |
< second, third, and fourth words are called the noad's |operand|, |subscr|, | |
--- | |
> second, third, and fourth words are called the noad's |nucleus|, |subscr|, | |
10724c13263 | |
< Consider, for example, the simple formula `\.{\$x\UA2\$}', which would be | |
--- | |
> Consider, for example, the simple formula `\.{\$x\^2\$}', which would be | |
10726c13265 | |
< The |operand| of this noad is a representation of `\.x', the |subscr| is | |
--- | |
> The |nucleus| of this noad is a representation of `\.x', the |subscr| is | |
10729c13268 | |
< The |operand|, |subscr|, and |supscr| fields are further broken into | |
--- | |
> The |nucleus|, |subscr|, and |supscr| fields are further broken into | |
10737a13277,13282 | |
> \yskip\hang|math_type(q)=math_text_char| is similar, but the character is | |
> unsubscripted and unsuperscripted and it is followed immediately by another | |
> character from the same font. (This |math_type| setting appears only | |
> briefly during the processing; it is used to suppress unwanted italic | |
> corrections.) | |
> | |
10751c13296 | |
< is not the same as |math_type(q)=empty|; for example, `\.{\$P\DA\{\}\$}' | |
--- | |
> is not the same as |math_type(q)=empty|; for example, `\.{\$P\_\{\}\$}' | |
10757c13302 | |
< since a halfword is being used for the |math_type| although only two | |
--- | |
> since a halfword is being used for the |math_type| although only three | |
10764c13309 | |
< @d operand(#)==#+1 {the |operand| field of a noad} | |
--- | |
> @d nucleus(#)==#+1 {the |nucleus| field of a noad} | |
10769d13313 | |
< @d empty=0 {|math_type| when the attribute is absent} | |
10772a13317 | |
> @d math_text_char=4 {|math_type| when italic correction is dubious} | |
10774,10775c13319,13320 | |
< @ Each portion of a formula is classified as Ord, Op, Bin, Rel, Open, | |
< Close, Punct, or Inner, for purposes of spacing and line breaking. An | |
--- | |
> @ Each portion of a formula is classified as Ord, Op, Bin, Rel, Ope, | |
> Clo, Pun, or Inn, for purposes of spacing and line breaking. An | |
10779c13324 | |
< |rel_noad| whose |operand| field is a representation of an equals sign | |
--- | |
> |rel_noad| whose |nucleus| field is a representation of an equals sign | |
10788c13333 | |
< A noad of type |ord_noad|, |op_noad|, $\ldotss$, |inner_noad| usually | |
--- | |
> A noad of type |ord_noad|, |op_noad|, \dots, |inner_noad| usually | |
10790,10791c13335,13336 | |
< have |subtype=switched|, if \.{\\limitswitch} has been applied to this | |
< operator. | |
--- | |
> have |subtype=limits| or |no_limits|, if the normal positioning of | |
> limits has been overridden for this operator. | |
10793c13338 | |
< @d ord_noad=unset_node+2 {|type| of a noad classified Ord} | |
--- | |
> @d ord_noad=unset_node+3 {|type| of a noad classified Ord} | |
10797,10801c13342,13347 | |
< @d open_noad=ord_noad+4 {|type| of a noad classified Open} | |
< @d close_noad=ord_noad+5 {|type| of a noad classified Close} | |
< @d punct_noad=ord_noad+6 {|type| of a noad classified Punct} | |
< @d inner_noad=ord_noad+7 {|type| of a noad classified Inner} | |
< @d switched=1 {|subtype| of a limit-switched |op_noad|} | |
--- | |
> @d open_noad=ord_noad+4 {|type| of a noad classified Ope} | |
> @d close_noad=ord_noad+5 {|type| of a noad classified Clo} | |
> @d punct_noad=ord_noad+6 {|type| of a noad classified Pun} | |
> @d inner_noad=ord_noad+7 {|type| of a noad classified Inn} | |
> @d limits=1 {|subtype| of |op_noad| whose scripts are to be above, below} | |
> @d no_limits=2 {|subtype| of |op_noad| whose scripts are to be normal} | |
10812c13358,13359 | |
< starting characters, as explained in the manual. | |
--- | |
> starting characters, as explained in Chapter~17 of {\sl The \TeX book}. | |
> @:TeXbook}{\sl The \TeX book@> | |
10816c13363 | |
< |numerator| fields instead of |operand|, |subscr|, and |supscr|. The | |
--- | |
> |numerator| fields instead of |nucleus|, |subscr|, and |supscr|. The | |
10825c13372,13373 | |
< \.{\\atop}, \.{\\above}, \.{\\xoverx}, \.{\\xatopx}, and \.{\\xabovex}. | |
--- | |
> \.{\\atop}, \.{\\above}, \.{\\overwithdelims}, \.{\\atopwithdelims}, and | |
> \.{\\abovewithdelims}. | |
10844,10847c13392 | |
< of delimiter fields; we can use the fact that a null delimiter is the same | |
< as an empty word of character information. | |
< | |
< @d null_delimiter==null_character | |
--- | |
> of delimiter fields. | |
10850a13396 | |
> @!null_delimiter:four_quarters; | |
10853c13399,13401 | |
< empty_field.rh←empty; empty_field.lh←null; | |
--- | |
> empty_field.rh:=empty; empty_field.lh:=null;@/ | |
> null_delimiter.b0:=0; null_delimiter.b1:=min_quarterword;@/ | |
> null_delimiter.b2:=0; null_delimiter.b3:=min_quarterword; | |
10855c13403 | |
< @ The |new_noad| function creates an |inner_noad| that is completely null. | |
--- | |
> @ The |new_noad| function creates an |ord_noad| that is completely null. | |
10859,10864c13407,13412 | |
< begin p←get_node(noad_size); | |
< type(p)←inner_noad; subtype(p)←normal; | |
< mem[operand(p)].hh←empty_field; | |
< mem[subscr(p)].hh←empty_field; | |
< mem[supscr(p)].hh←empty_field; | |
< new_noad←p; | |
--- | |
> begin p:=get_node(noad_size); | |
> type(p):=ord_noad; subtype(p):=normal; | |
> mem[nucleus(p)].hh:=empty_field; | |
> mem[subscr(p)].hh:=empty_field; | |
> mem[supscr(p)].hh:=empty_field; | |
> new_noad:=p; | |
10868,10869c13416,13417 | |
< operand underlined; an |over_noad| has it overlined. An |accent_noad| places | |
< an accent over its operand; the accent character appears as | |
--- | |
> nucleus underlined; an |over_noad| has it overlined. An |accent_noad| places | |
> an accent over its nucleus; the accent character appears as | |
10871,10872c13419,13420 | |
< centers its operand vertically with respect to the axis of the formula; | |
< we always have |math_type(operand(p))=sub_box| in this case. | |
--- | |
> centers its nucleus vertically with respect to the axis of the formula; | |
> in such noads we always have |math_type(nucleus(p))=sub_box|. | |
10875c13423 | |
< \TeX's \.{\\left} and \.{\\right}. The |operand| of such noads is | |
--- | |
> \TeX's \.{\\left} and \.{\\right}. The |nucleus| of such noads is | |
10892c13440,13441 | |
< @d delimiter==operand {|delimiter| field in left and right noads} | |
--- | |
> @d delimiter==nucleus {|delimiter| field in left and right noads} | |
> @d scripts_allowed(#)==(type(#)>=ord_noad)and(type(#)<left_noad) | |
10896c13445 | |
< data structure to record such instructions; it is two words long, so it | |
--- | |
> data structure to record such instructions; it is three words long, so it | |
10899c13448,13449 | |
< second word of a |style_node| is not used. | |
--- | |
> second and third words of a |style_node| are not used, but they are | |
> present because a |choice_node| is converted to a |style_node|. | |
10902,10903c13452,13456 | |
< |display_style|, $\ldotss$, |script_script_style|, and adds@@1 to get the | |
< ``cramped'' versions of these styles. | |
--- | |
> |display_style|, \dots, |script_script_style|, and adds~1 to get the | |
> ``cramped'' versions of these styles. This gives a numerical order that | |
> is backwards from the convention of Appendix~G in {\sl The \TeX book\/}; | |
> i.e., a smaller style has a larger numerical value. | |
> @:TeXbook}{\sl The \TeX book@> | |
10905a13459 | |
> @d style_node_size=3 {number of words in a style node} | |
10914,10916c13468,13489 | |
< begin p←get_node(small_node_size); type(p)←style_node; | |
< subtype(p)←s; width(p)←0; {the |width| is not used} | |
< new_style←p; | |
--- | |
> begin p:=get_node(style_node_size); type(p):=style_node; | |
> subtype(p):=s; width(p):=0; depth(p):=0; {the |width| and |depth| are not used} | |
> new_style:=p; | |
> end; | |
> | |
> @ Finally, the \.{\\mathchoice} primitive creates a |choice_node|, which | |
> has special subfields |display_mlist|, |text_mlist|, |script_mlist|, | |
> and |script_script_mlist| pointing to the mlists for each style. | |
> | |
> @d choice_node=unset_node+2 {|type| of a choice node} | |
> @d display_mlist(#)==info(#+1) {mlist to be used in display style} | |
> @d text_mlist(#)==link(#+1) {mlist to be used in text style} | |
> @d script_mlist(#)==info(#+2) {mlist to be used in script style} | |
> @d script_script_mlist(#)==link(#+2) {mlist to be used in scriptscript style} | |
> | |
> @p function new_choice:pointer; {create a choice node} | |
> var p:pointer; {the new node} | |
> begin p:=get_node(style_node_size); type(p):=choice_node; | |
> subtype(p):=0; {the |subtype| is not used} | |
> display_mlist(p):=null; text_mlist(p):=null; script_mlist(p):=null; | |
> script_script_mlist(p):=null; | |
> new_choice:=p; | |
10920c13493 | |
< that displays the things that can only be present in mlists; this | |
--- | |
> that displays the things that can only be present in mlists; this | |
10927,10928c13500,13501 | |
< subsidiary to the |operand| field of some noad; the dot is replaced by | |
< `\.[' or `\.(' or `\./' or `\.\\' if |p| is descended from the |subscr| | |
--- | |
> subsidiary to the |nucleus| field of some noad; the dot is replaced by | |
> `\.\_' or `\.\^' or `\./' or `\.\\' if |p| is descended from the |subscr| | |
10930,10932c13503,13505 | |
< the current string would be `\.{.(.[/}' if |p| points to the |ord_noad| for | |
< |x| in the (ridiculous) formula `\.{\$\\sqrt\{a\UA\{\{b\DA\{c\\over x+y\} | |
< \}\}\}\$}'. | |
--- | |
> the current string would be `\.{.\^.\_/}' if |p| points to the |ord_noad| for | |
> |x| in the (ridiculous) formula | |
> `\.{\$\\sqrt\{a\^\{\\mathinner\{b\_\{c\\over x+y\}\}\}\}\$}'. | |
10936,10938c13509,13512 | |
< ord_noad,op_noad,bin_noad,rel_noad,open_noad,close_noad,punct_noad, | |
< radical_noad,over_noad,under_noad,vcenter_noad,accent_noad, | |
< left_noad,right_noad:@<Display normal noad |p|@>; | |
--- | |
> choice_node:@<Display choice node |p|@>; | |
> ord_noad,op_noad,bin_noad,rel_noad,open_noad,close_noad,punct_noad,inner_noad, | |
> radical_noad,over_noad,under_noad,vcenter_noad,accent_noad, | |
> left_noad,right_noad:@<Display normal noad |p|@>; | |
10946c13520 | |
< print_ascii(qo(character(p))); | |
--- | |
> print_ASCII(qo(character(p))); | |
10949c13523 | |
< procedure print_delimiter(@!p:pointer); {prints a delimiter as 24-bit octal} | |
--- | |
> procedure print_delimiter(@!p:pointer); {prints a delimiter as 24-bit hex value} | |
10951,10952c13525,13526 | |
< begin a←small_fam(p)*256+qo(small_char(p)); | |
< a←a*@'10000+large_fam(p)*256+qo(large_char(p)); | |
--- | |
> begin a:=small_fam(p)*256+qo(small_char(p)); | |
> a:=a*@"1000+large_fam(p)*256+qo(large_char(p)); | |
10954c13528 | |
< else print_octal(a); | |
--- | |
> else print_hex(a); | |
10966,10982c13540,13558 | |
< procedure print_subsidiary_data(@!p:pointer;@!c:ascii_code); | |
< {display a noad field} | |
< begin if cur_length<depth_threshold then | |
< begin append_char(c); {include |c| in the recursion history} | |
< temp_ptr←p; {prepare for |show_info| if recursion is needed} | |
< case math_type(p) of | |
< math_char: begin print_ln; print_current_string; print_fam_and_char(p); | |
< end; | |
< sub_box: show_info; {recursive call} | |
< sub_mlist: if info(p)=null then | |
< begin print_ln; print_current_string; print("{}"); | |
< end | |
< else show_info; {recursive call} | |
< othercases do_nothing {|empty|} | |
< endcases;@/ | |
< flush_char; {remove |c| from the recursion history} | |
< end; | |
--- | |
> procedure print_subsidiary_data(@!p:pointer;@!c:ASCII_code); | |
> {display a noad field} | |
> begin if cur_length>=depth_threshold then | |
> begin if math_type(p)<>empty then print(" []"); | |
> end | |
> else begin append_char(c); {include |c| in the recursion history} | |
> temp_ptr:=p; {prepare for |show_info| if recursion is needed} | |
> case math_type(p) of | |
> math_char: begin print_ln; print_current_string; print_fam_and_char(p); | |
> end; | |
> sub_box: show_info; {recursive call} | |
> sub_mlist: if info(p)=null then | |
> begin print_ln; print_current_string; print("{}"); | |
> end | |
> else show_info; {recursive call} | |
> othercases do_nothing {|empty|} | |
> endcases;@/ | |
> flush_char; {remove |c| from the recursion history} | |
> end; | |
11009a13586,13593 | |
> @ @<Display choice node |p|@>= | |
> begin print_esc("mathchoice"); | |
> append_char("D"); show_node_list(display_mlist(p)); flush_char; | |
> append_char("T"); show_node_list(text_mlist(p)); flush_char; | |
> append_char("S"); show_node_list(script_mlist(p)); flush_char; | |
> append_char("s"); show_node_list(script_script_mlist(p)); flush_char; | |
> end | |
> | |
11018a13603 | |
> inner_noad: print_esc("mathinner"); | |
11023c13608 | |
< end; | |
--- | |
> end; | |
11025,11034c13610,13621 | |
< end; | |
< left_noad: begin print_esc("left"); print_delimiter(operand(p)); | |
< end; | |
< right_noad: begin print_esc("right"); print_delimiter(operand(p)); | |
< end; | |
< end; | |
< if subtype(p)≠normal then print_esc("limitswitch"); | |
< if type(p)<left_noad then print_subsidiary_data(operand(p),"."); | |
< print_subsidiary_data(supscr(p),"("); | |
< print_subsidiary_data(subscr(p),"["); | |
--- | |
> end; | |
> left_noad: begin print_esc("left"); print_delimiter(delimiter(p)); | |
> end; | |
> right_noad: begin print_esc("right"); print_delimiter(delimiter(p)); | |
> end; | |
> end; | |
> if subtype(p)<>normal then | |
> if subtype(p)=limits then print_esc("limits") | |
> else print_esc("nolimits"); | |
> if type(p)<left_noad then print_subsidiary_data(nucleus(p),"."); | |
> print_subsidiary_data(supscr(p),"^"); | |
> print_subsidiary_data(subscr(p),"_"); | |
11038c13625 | |
< begin print_esc("xabovex"); print(" thickness "); | |
--- | |
> begin print_esc("fraction, thickness "); | |
11041,11052c13628,13639 | |
< if (small_fam(left_delimiter(p))≠0)∨@+ | |
< (small_char(left_delimiter(p))≠min_quarterword)∨@| | |
< (large_fam(left_delimiter(p))≠0)∨@| | |
< (large_char(left_delimiter(p))≠min_quarterword) then | |
< begin print(", left-delimiter "); print_delimiter(left_delimiter(p)); | |
< end; | |
< if (small_fam(right_delimiter(p))≠0)∨@| | |
< (small_char(right_delimiter(p))≠min_quarterword)∨@| | |
< (large_fam(right_delimiter(p))≠0)∨@| | |
< (large_char(right_delimiter(p))≠min_quarterword) then | |
< begin print(", right-delimiter "); print_delimiter(right_delimiter(p)); | |
< end; | |
--- | |
> if (small_fam(left_delimiter(p))<>0)or@+ | |
> (small_char(left_delimiter(p))<>min_quarterword)or@| | |
> (large_fam(left_delimiter(p))<>0)or@| | |
> (large_char(left_delimiter(p))<>min_quarterword) then | |
> begin print(", left-delimiter "); print_delimiter(left_delimiter(p)); | |
> end; | |
> if (small_fam(right_delimiter(p))<>0)or@| | |
> (small_char(right_delimiter(p))<>min_quarterword)or@| | |
> (large_fam(right_delimiter(p))<>0)or@| | |
> (large_char(right_delimiter(p))<>min_quarterword) then | |
> begin print(", right-delimiter "); print_delimiter(right_delimiter(p)); | |
> end; | |
11056c13643,13675 | |
< @* \[34] Subroutines for math mode. | |
--- | |
> | |
> @ That which can be displayed can also be destroyed. | |
> | |
> @<Cases of |flush_node_list| that arise...@>= | |
> style_node: begin free_node(p,style_node_size); goto done; | |
> end; | |
> choice_node:begin flush_node_list(display_mlist(p)); | |
> flush_node_list(text_mlist(p)); | |
> flush_node_list(script_mlist(p)); | |
> flush_node_list(script_script_mlist(p)); | |
> free_node(p,style_node_size); goto done; | |
> end; | |
> ord_noad,op_noad,bin_noad,rel_noad,open_noad,close_noad,punct_noad,inner_noad, | |
> radical_noad,over_noad,under_noad,vcenter_noad,accent_noad:@t@>@;@/ | |
> begin if math_type(nucleus(p))>=sub_box then | |
> flush_node_list(info(nucleus(p))); | |
> if math_type(supscr(p))>=sub_box then | |
> flush_node_list(info(supscr(p))); | |
> if math_type(subscr(p))>=sub_box then | |
> flush_node_list(info(subscr(p))); | |
> if type(p)=radical_noad then free_node(p,radical_noad_size) | |
> else if type(p)=accent_noad then free_node(p,accent_noad_size) | |
> else free_node(p,noad_size); | |
> goto done; | |
> end; | |
> left_noad,right_noad: begin free_node(p,noad_size); goto done; | |
> end; | |
> fraction_noad: begin flush_node_list(info(numerator(p))); | |
> flush_node_list(info(denominator(p))); | |
> free_node(p,fraction_noad_size); goto done; | |
> end; | |
> | |
> @* \[35] Subroutines for math mode. | |
11072c13691 | |
< begin if s=0 then print_esc("textfont") | |
--- | |
> begin if s=text_size then print_esc("textfont") | |
11077,11080c13696,13699 | |
< @ Before an mlist is created, \TeX\ makes sure that | |
< the fonts in family@@2 have enough parameters to be math-symbol | |
< fonts, and that the text font in family@@3 has enough parameters to be a | |
< math-extension font. The math-symbol parameters are referred to by using the | |
--- | |
> @ Before an mlist is converted to an hlist, \TeX\ makes sure that | |
> the fonts in family~2 have enough parameters to be math-symbol | |
> fonts, and that the fonts in family~3 have enough parameters to be | |
> math-extension fonts. The math-symbol parameters are referred to by using the | |
11102,11103c13721,13723 | |
< @d delim1==mathsy(20) {size of \.{\\xatopx} delimiters in display styles} | |
< @d delim2==mathsy(21) {size of \.{\\xatopx} delimiters in non-displays} | |
--- | |
> @d delim1==mathsy(20) {size of \.{\\atopwithdelims} delimiters | |
> in display styles} | |
> @d delim2==mathsy(21) {size of \.{\\atopwithdelims} delimiters in non-displays} | |
11123c13743 | |
< an overlined operand (|und_style|), for a subscript or a superscript | |
--- | |
> an overlined nucleus (|cramped_style|), for a subscript or a superscript | |
11127c13747 | |
< @d und_style(#)==2*(# div 2)+cramped {cramp the style} | |
--- | |
> @d cramped_style(#)==2*(# div 2)+cramped {cramp the style} | |
11137,11139c13757,13759 | |
< begin if cur_style<script_style then cur_size←text_size | |
< else cur_size←16*((cur_style-text_style) div 2); | |
< cur_mu←x_over_n(math_quad(cur_style),18); | |
--- | |
> begin if cur_style<script_style then cur_size:=text_size | |
> else cur_size:=16*((cur_style-text_style) div 2); | |
> cur_mu:=x_over_n(math_quad(cur_size),18); | |
11147c13767 | |
< {construct the bar for a fraction} | |
--- | |
> {construct the bar for a fraction} | |
11149c13769 | |
< begin p←new_rule; height(p)←t; depth(p)←0; fraction_rule←p; | |
--- | |
> begin p:=new_rule; height(p):=t; depth(p):=0; fraction_rule:=p; | |
11158,11159c13778,13779 | |
< begin p←new_kern(k); link(p)←b; q←fraction_rule(t); link(q)←p; | |
< p←new_kern(t); link(p)←q; overbar←vpack(p,natural); | |
--- | |
> begin p:=new_kern(k); link(p):=b; q:=fraction_rule(t); link(q):=p; | |
> p:=new_kern(t); link(p):=q; overbar:=vpack(p,natural); | |
11189d13808 | |
< @!p: pointer; {character nodes constructed} | |
11192,11206c13811,13825 | |
< begin f←undefined_font; w←0; large_attempt←false; | |
< z←small_fam(d); x←small_char(d); | |
< loop@+ begin @<Look at the variants of |(z,x)|; set |f| and |c| whenever | |
< a better character is found; |goto found| as soon as a | |
< large enough variant is encountered@>; | |
< if large_attempt then goto found; {there were none large enough} | |
< large_attempt←true; z←large_fam(d); x←large_char(d); | |
< end; | |
< found: if f≠undefined_font then | |
< @<Make variable |b| point to a box for |(f,c)|@> | |
< else begin b←new_null_box; | |
< width(b)←null_delimiter_space; {use this width if no delimiter was found} | |
< end; | |
< shift_amount(b)←half(height(b)-depth(b)) - axis_height(s); | |
< var_delimiter←b; | |
--- | |
> begin f:=null_font; w:=0; large_attempt:=false; | |
> z:=small_fam(d); x:=small_char(d); | |
> loop@+ begin @<Look at the variants of |(z,x)|; set |f| and |c| whenever | |
> a better character is found; |goto found| as soon as a | |
> large enough variant is encountered@>; | |
> if large_attempt then goto found; {there were none large enough} | |
> large_attempt:=true; z:=large_fam(d); x:=large_char(d); | |
> end; | |
> found: if f<>null_font then | |
> @<Make variable |b| point to a box for |(f,c)|@> | |
> else begin b:=new_null_box; | |
> width(b):=null_delimiter_space; {use this width if no delimiter was found} | |
> end; | |
> shift_amount(b):=half(height(b)-depth(b)) - axis_height(s); | |
> var_delimiter:=b; | |
11214,11223c13833,13842 | |
< if (z≠0)∨(x≠min_quarterword) then | |
< begin z←z+s+16; | |
< repeat z←z-16; g←fam_fnt(z); | |
< if g≠undefined_font then | |
< @<Look at the list of characters starting with |x| in | |
< font |g|; set |f| and |c| whenever | |
< a better character is found; |goto found| as soon as a | |
< large enough variant is encountered@>; | |
< until z<16; | |
< end | |
--- | |
> if (z<>0)or(x<>min_quarterword) then | |
> begin z:=z+s+16; | |
> repeat z:=z-16; g:=fam_fnt(z); | |
> if g<>null_font then | |
> @<Look at the list of characters starting with |x| in | |
> font |g|; set |f| and |c| whenever | |
> a better character is found; |goto found| as soon as a | |
> large enough variant is encountered@>; | |
> until z<16; | |
> end | |
11226,11242c13845,13880 | |
< begin y←x; | |
< continue: if (qo(y)≥font_bc[g])∧(qo(y)≤font_ec[g]) then | |
< begin q←char_info(g)(y); | |
< if char_exists(q) then | |
< begin if char_tag(q)=ext_tag then goto found; | |
< hd←height_depth(q); | |
< u←char_height(g)(hd)+char_depth(g)(hd); | |
< if u>w then | |
< begin f←g; c←y; w←u; | |
< if u≥v then goto found; | |
< end; | |
< if char_tag(q)=list_tag then | |
< begin y←rem_byte(q); goto continue; | |
< end; | |
< end; | |
< end; | |
< end | |
--- | |
> begin y:=x; | |
> if (qo(y)>=font_bc[g])and(qo(y)<=font_ec[g]) then | |
> begin continue: q:=char_info(g)(y); | |
> if char_exists(q) then | |
> begin if char_tag(q)=ext_tag then | |
> begin f:=g; c:=y; goto found; | |
> end; | |
> hd:=height_depth(q); | |
> u:=char_height(g)(hd)+char_depth(g)(hd); | |
> if u>w then | |
> begin f:=g; c:=y; w:=u; | |
> if u>=v then goto found; | |
> end; | |
> if char_tag(q)=list_tag then | |
> begin y:=rem_byte(q); goto continue; | |
> end; | |
> end; | |
> end; | |
> end | |
> | |
> @ Here is a subroutine that creates a new box, whose list contains a | |
> single character, and whose width includes the italic correction for | |
> that character. The height or depth of the box will be negative, if | |
> the height or depth of the character is negative; thus, this routine | |
> may deliver a slightly different result than |hpack| would produce. | |
> | |
> @<Declare subprocedures for |var_delimiter|@>= | |
> function char_box(@!f:internal_font_number;@!c:quarterword):pointer; | |
> var q:four_quarters; | |
> @!hd:eight_bits; {|height_depth| byte} | |
> @!b,@!p:pointer; {the new box and its character node} | |
> begin q:=char_info(f)(c); hd:=height_depth(q); | |
> b:=new_null_box; width(b):=char_width(f)(q)+char_italic(f)(q); | |
> height(b):=char_height(f)(hd); depth(b):=char_depth(f)(hd); | |
> p:=get_avail; character(p):=c; font(p):=f; list_ptr(b):=p; char_box:=b; | |
> end; | |
11249,11252c13887,13889 | |
< @<Construct an extensible character for |(f,c)| in box |b|@> | |
< else begin p←get_avail; font(p)←f; character(p)←c; list_ptr(b)←p; | |
< b←hpack(p,natural); | |
< end | |
--- | |
> @<Construct an extensible character in a new box |b|, | |
> using recipe |rem_byte(q)| and font |f|@> | |
> else b:=char_box(f,c) | |
11260c13897 | |
< @!c:quarterword); | |
--- | |
> @!c:quarterword); | |
11262,11264c13899,13900 | |
< begin p←get_avail; font(p)←f; character(p)←c; p←hpack(p,natural); | |
< link(p)←list_ptr(b); list_ptr(b)←p; | |
< height(b)←height(p); | |
--- | |
> begin p:=char_box(f,c); link(p):=list_ptr(b); list_ptr(b):=p; | |
> height(b):=height(p); | |
11274,11275c13910,13911 | |
< begin q←char_info(f)(c); hd←height_depth(q); | |
< height_plus_depth←char_height(f)(hd)+char_depth(f)(hd); | |
--- | |
> begin q:=char_info(f)(c); hd:=height_depth(q); | |
> height_plus_depth:=char_height(f)(hd)+char_depth(f)(hd); | |
11279,11281c13915,13917 | |
< begin b←new_null_box; | |
< type(b)←vlist_node; | |
< r←font_info[exten_base[f]+rem_byte(q)].qqqq;@/ | |
--- | |
> begin b:=new_null_box; | |
> type(b):=vlist_node; | |
> r:=font_info[exten_base[f]+rem_byte(q)].qqqq;@/ | |
11283,11295c13919,13931 | |
< number of extension steps, |n|; also set |width(b)|@>; | |
< c←ext_bot(r); | |
< if c≠min_quarterword then stack_into_box(b,f,c); | |
< c←ext_rep(r); | |
< for m←1 to n do stack_into_box(b,f,c); | |
< c←ext_mid(r); | |
< if c≠min_quarterword then | |
< begin stack_into_box(b,f,c); c←ext_rep(r); | |
< for m←1 to n do stack_into_box(b,f,c); | |
< end; | |
< c←ext_top(r); | |
< if c≠min_quarterword then stack_into_box(b,f,c); | |
< depth(b)←w-height(b); | |
--- | |
> number of extension steps, |n|; also set |width(b)|@>; | |
> c:=ext_bot(r); | |
> if c<>min_quarterword then stack_into_box(b,f,c); | |
> c:=ext_rep(r); | |
> for m:=1 to n do stack_into_box(b,f,c); | |
> c:=ext_mid(r); | |
> if c<>min_quarterword then | |
> begin stack_into_box(b,f,c); c:=ext_rep(r); | |
> for m:=1 to n do stack_into_box(b,f,c); | |
> end; | |
> c:=ext_top(r); | |
> if c<>min_quarterword then stack_into_box(b,f,c); | |
> depth(b):=w-height(b); | |
11299c13935 | |
< mod\-ule. If this module does not have positive height plus depth, | |
--- | |
> module. If this module does not have positive height plus depth, | |
11304,11309c13940,13945 | |
< c←ext_rep(r); u←height_plus_depth(f,c); | |
< w←0; width(b)←char_width(f)(char_info(f)(c));@/ | |
< c←ext_bot(r);@+if c≠min_quarterword then w←w+height_plus_depth(f,c); | |
< c←ext_mid(r);@+if c≠min_quarterword then w←w+height_plus_depth(f,c); | |
< c←ext_top(r);@+if c≠min_quarterword then w←w+height_plus_depth(f,c); | |
< n←0; | |
--- | |
> c:=ext_rep(r); u:=height_plus_depth(f,c); | |
> w:=0; q:=char_info(f)(c); width(b):=char_width(f)(q)+char_italic(f)(q);@/ | |
> c:=ext_bot(r);@+if c<>min_quarterword then w:=w+height_plus_depth(f,c); | |
> c:=ext_mid(r);@+if c<>min_quarterword then w:=w+height_plus_depth(f,c); | |
> c:=ext_top(r);@+if c<>min_quarterword then w:=w+height_plus_depth(f,c); | |
> n:=0; | |
11311,11313c13947,13949 | |
< begin w←w+u; incr(n); | |
< if ext_mid(r)≠min_quarterword then w←w+u; | |
< end | |
--- | |
> begin w:=w+u; incr(n); | |
> if ext_mid(r)<>min_quarterword then w:=w+u; | |
> end | |
11317,11318c13953,13954 | |
< their limits above and below. It takes a given hlist box |b| and | |
< changes it so that the new box is centered in a box of width |w|. | |
--- | |
> their limits above and below. It takes a given box~|b| and | |
> changes it so that the new box is centered in a box of width~|w|. | |
11323a13960,13963 | |
> The given box might contain a single character whose italic correction | |
> has been added to the width of the box; in this case a compensating | |
> kern is inserted. | |
> | |
11326,11334c13966,13982 | |
< begin if (width(b)≠w)∧(list_ptr(b)≠null) then | |
< begin p←list_ptr(b); free_node(b,box_node_size); | |
< b←new_glue(ss_glue); link(b)←p; | |
< while link(p)≠null do p←link(p); | |
< link(p)←new_glue(ss_glue); | |
< rebox←hpack(b,w,exactly); | |
< end | |
< else begin width(b)←w; rebox←b; | |
< end; | |
--- | |
> @!f:internal_font_number; {font in a one-character box} | |
> @!v:scaled; {width of a character without italic correction} | |
> begin if (width(b)<>w)and(list_ptr(b)<>null) then | |
> begin if type(b)=vlist_node then b:=hpack(b,natural); | |
> p:=list_ptr(b); | |
> if (is_char_node(p))and(link(p)=null) then | |
> begin f:=font(p); v:=char_width(f)(char_info(f)(character(p))); | |
> if v<>width(b) then link(p):=new_kern(width(b)-v); | |
> end; | |
> free_node(b,box_node_size); | |
> b:=new_glue(ss_glue); link(b):=p; | |
> while link(p)<>null do p:=link(p); | |
> link(p):=new_glue(ss_glue); | |
> rebox:=hpack(b,w,exactly); | |
> end | |
> else begin width(b):=w; rebox:=b; | |
> end; | |
11339a13988,13989 | |
> @d mu_mult(#)==nx_plus_y(n,#,xn_over_d(#,f,@'200000)) | |
> | |
11344,11353c13994,14006 | |
< begin n←x_over_n(m,@'200000); f←remainder;@/ | |
< p←get_node(glue_spec_size); | |
< width(p)←nx_plus_y(n,width(g),f); {convert \.{mu} to \.{pt}} | |
< stretch_order(p)←stretch_order(g); | |
< if stretch_order(p)=normal then stretch(p)←nx_plus_y(n,stretch(g),f) | |
< else stretch(p)←stretch(g); | |
< shrink_order(p)←shrink_order(g); | |
< if shrink_order(p)=normal then shrink(p)←nx_plus_y(n,shrink(g),f) | |
< else shrink(p)←shrink(g); | |
< math_glue←p; | |
--- | |
> begin n:=x_over_n(m,@'200000); f:=remainder;@/ | |
> if f<0 then | |
> begin decr(n); f:=f+@'200000; | |
> end; | |
> p:=get_node(glue_spec_size); | |
> width(p):=mu_mult(width(g)); {convert \.{mu} to \.{pt}} | |
> stretch_order(p):=stretch_order(g); | |
> if stretch_order(p)=normal then stretch(p):=mu_mult(stretch(g)) | |
> else stretch(p):=stretch(g); | |
> shrink_order(p):=shrink_order(g); | |
> if shrink_order(p)=normal then shrink(p):=mu_mult(shrink(g)) | |
> else shrink(p):=shrink(g); | |
> math_glue:=p; | |
11363,11376c14016,14041 | |
< begin n←x_over_n(m,@'200000); f←remainder;@/ | |
< width(p)←nx_plus_y(n,width(p),f); subtype(p)←normal; | |
< end; | |
< end; | |
< @* \[35] Typesetting math formulas. | |
< \TeX's major routine for dealing with formulas is called |mlist_to_hlist|. | |
< After a formula has been scanned and represented as an mlist, this routine | |
< converts it to an hlist that can be placed into a box or incorporated into | |
< the text of a paragraph. There are three implicit parameters, passed in | |
< global variables: |cur_mlist| points to the first node or noad in the | |
< given mlist (and it might be |null|); |cur_style| is a style code; and | |
< |mlist_penalties| is |true| if penalty nodes for potential line breaks are | |
< to be inserted into the resulting hlist. After |mlist_to_hlist| has | |
< acted, |link(temp_head)| points to the translated hlist. | |
--- | |
> begin n:=x_over_n(m,@'200000); f:=remainder;@/ | |
> if f<0 then | |
> begin decr(n); f:=f+@'200000; | |
> end; | |
> width(p):=mu_mult(width(p)); subtype(p):=explicit; | |
> end; | |
> end; | |
> | |
> @ Sometimes it is necessary to destroy an mlist. The following | |
> subroutine empties the current list, assuming that |abs(mode)=mmode|. | |
> | |
> @p procedure flush_math; | |
> begin flush_node_list(link(head)); flush_node_list(incompleat_noad); | |
> link(head):=null; tail:=head; incompleat_noad:=null; | |
> end; | |
> | |
> @* \[36] Typesetting math formulas. | |
> \TeX's most important routine for dealing with formulas is called | |
> |mlist_to_hlist|. After a formula has been scanned and represented as an | |
> mlist, this routine converts it to an hlist that can be placed into a box | |
> or incorporated into the text of a paragraph. There are three implicit | |
> parameters, passed in global variables: |cur_mlist| points to the first | |
> node or noad in the given mlist (and it might be |null|); |cur_style| is a | |
> style code; and |mlist_penalties| is |true| if penalty nodes for potential | |
> line breaks are to be inserted into the resulting hlist. After | |
> |mlist_to_hlist| has acted, |link(temp_head)| points to the translated hlist. | |
11393c14058,14061 | |
< |mlist_to_hlist|. The box returned by |clean_box| is ``clean'' in the | |
--- | |
> |mlist_to_hlist|. | |
> @^recursion@> | |
> | |
> The box returned by |clean_box| is ``clean'' in the | |
11396c14064 | |
< @p procedure mlist_to_hlist; forward;@t\2@>@/ | |
--- | |
> @p procedure@?mlist_to_hlist; forward;@t\2@>@/ | |
11398c14066 | |
< label found,exit; | |
--- | |
> label found; | |
11400a14069,14070 | |
> @!x:pointer; {box to be returned} | |
> @!r:pointer; {temporary pointer} | |
11402,11413c14072,14078 | |
< math_char: begin cur_mlist←new_noad; mem[operand(cur_mlist)]←mem[p]; | |
< type(cur_mlist)←ord_noad; | |
< end; | |
< sub_box: begin q←info(p); | |
< if shift_amount(q)=0 then {already clean} | |
< begin clean_box←q; return; | |
< end | |
< else goto found; | |
< end; | |
< sub_mlist: cur_mlist←info(p); | |
< othercases begin q←null; goto found; | |
< end | |
--- | |
> math_char: begin cur_mlist:=new_noad; mem[nucleus(cur_mlist)]:=mem[p]; | |
> end; | |
> sub_box: begin q:=info(p); goto found; | |
> end; | |
> sub_mlist: cur_mlist:=info(p); | |
> othercases begin q:=new_null_box; goto found; | |
> end | |
11415,11417c14080,14082 | |
< save_style←cur_style; cur_style←s; mlist_penalties←false; | |
< mlist_to_hlist; q←link(temp_head); {recursive call} | |
< cur_style←save_style; {restore the style} | |
--- | |
> save_style:=cur_style; cur_style:=s; mlist_penalties:=false;@/ | |
> mlist_to_hlist; q:=link(temp_head); {recursive call} | |
> cur_style:=save_style; {restore the style} | |
11419,11420c14084,14102 | |
< found: clean_box←hpack(q,natural); | |
< exit:end; | |
--- | |
> found: if is_char_node(q)or(q=null) then x:=hpack(q,natural) | |
> else if (link(q)=null)and(type(q)<=vlist_node)and(shift_amount(q)=0) then | |
> x:=q {it's already clean} | |
> else x:=hpack(q,natural); | |
> @<Simplify a trivial box@>; | |
> clean_box:=x; | |
> end; | |
> | |
> @ Here we save memory space in a common case. | |
> | |
> @<Simplify a trivial box@>= | |
> q:=list_ptr(x); | |
> if is_char_node(q) then | |
> begin r:=link(q); | |
> if r<>null then if link(r)=null then if not is_char_node(r) then | |
> if type(r)=kern_node then {unneeded italic correction} | |
> begin free_node(r,small_node_size); link(q):=null; | |
> end; | |
> end | |
11430,11440c14112,14122 | |
< begin cur_c←character(a); cur_f←fam_fnt(fam(a)+cur_size); | |
< if cur_f=undefined_font then | |
< @<Complain about an undefined family and set |cur_i| null@> | |
< else begin if (qo(cur_c)≥font_bc[cur_f])∧(qo(cur_c)≤font_ec[cur_f]) then | |
< cur_i←char_info(cur_f)(cur_c) | |
< else cur_i←null_character; | |
< if not(char_exists(cur_i)) then | |
< begin char_warning(cur_f,cur_c); | |
< math_type(a)←empty; | |
< end; | |
< end; | |
--- | |
> begin cur_c:=character(a); cur_f:=fam_fnt(fam(a)+cur_size); | |
> if cur_f=null_font then | |
> @<Complain about an undefined family and set |cur_i| null@> | |
> else begin if (qo(cur_c)>=font_bc[cur_f])and(qo(cur_c)<=font_ec[cur_f]) then | |
> cur_i:=char_info(cur_f)(cur_c) | |
> else cur_i:=null_character; | |
> if not(char_exists(cur_i)) then | |
> begin char_warning(cur_f,qo(cur_c)); | |
> math_type(a):=empty; | |
> end; | |
> end; | |
11444,11452c14126,14133 | |
< begin print_nl("! "); print_size(cur_size); print(" "); | |
< print_int(fam(a)); print(" is undefined"); | |
< @:text_font_}{\.{\\textfont x is undefined}@> | |
< @:script_font_}{\.{\\scriptfont x is undefined}@> | |
< @:script_script_font_}{\.{\\scriptscriptfont x is undefined}@> | |
< help3("You have to define families outside of a math")@/ | |
< ("subformula that uses them. Proceed, and I'll")@/ | |
< ("ignore the nonexistent font you referred to."); | |
< error; cur_i←null_character; math_type(a)←empty; | |
--- | |
> begin print_err(""); print_size(cur_size); print_char(" "); | |
> print_int(fam(a)); print(" is undefined (character "); | |
> print_ASCII(qo(cur_c)); print_char(")"); | |
> help4("Somewhere in the math formula just ended, you used the")@/ | |
> ("stated character from an undefined font family. For example,")@/ | |
> ("plain TeX doesn't allow \it or \sl in subscripts. Proceed,")@/ | |
> ("and I'll try to forget that I needed that character."); | |
> error; cur_i:=null_character; math_type(a):=empty; | |
11461c14142 | |
< or a lig/kern instruction} | |
--- | |
> or a lig/kern instruction} | |
11473c14154,14155 | |
< field, an integer field that replaces the |operand| or |thickness|. | |
--- | |
> field, an integer field that replaces the |nucleus| or |thickness|. | |
> @^recursion@> | |
11476c14158 | |
< penal\-ties between nodes. | |
--- | |
> penalties between nodes. | |
11478c14160 | |
< @d new_hlist(#)==mem[operand(#)].int {the translation of an mlist} | |
--- | |
> @d new_hlist(#)==mem[nucleus(#)].int {the translation of an mlist} | |
11491c14173 | |
< done; | |
--- | |
> done; | |
11500c14182 | |
< @!p,@!v,@!x,@!y,@!z: pointer; {temporary registers for list construction} | |
--- | |
> @!p,@!x,@!y,@!z: pointer; {temporary registers for list construction} | |
11505,11507c14187,14189 | |
< begin mlist←cur_mlist; penalties←mlist_penalties; | |
< style←cur_style; {tuck global parameters away} | |
< q←mlist; r←null; r_type←op_noad; max_h←0; max_d←0; | |
--- | |
> begin mlist:=cur_mlist; penalties:=mlist_penalties; | |
> style:=cur_style; {tuck global parameters away as local variables} | |
> q:=mlist; r:=null; r_type:=op_noad; max_h:=0; max_d:=0; | |
11509,11511c14191,14194 | |
< while q≠null do @<Process node-or-noad |q| as much as possible in preparation | |
< for the second pass of |mlist_to_hlist|, then move to the next | |
< item in the mlist@>; | |
--- | |
> while q<>null do @<Process node-or-noad |q| as much as possible in preparation | |
> for the second pass of |mlist_to_hlist|, then move to the next | |
> item in the mlist@>; | |
> @<Convert \(a)a final |bin_noad| to an |ord_noad|@>; | |
11513c14196 | |
< proper spacing and penalties@>; | |
--- | |
> proper spacing and penalties@>; | |
11516c14199 | |
< @ We use the fact that no character nodes appear in an mlist, hence | |
--- | |
> @ We use the fact that no character nodes appear in an mlist, hence | |
11521,11526c14204,14209 | |
< if a noad has been fully processed, |goto check_dimensions| if it | |
< has been translated into |new_hlist(q)|, or |goto done_with_node| | |
< if a node has been fully processed@>; | |
< check_dimensions: z←hpack(new_hlist(q),natural); | |
< if height(z)>max_h then max_h←height(z); | |
< if depth(z)>max_d then max_d←depth(z); | |
--- | |
> if a noad has been fully processed, |goto check_dimensions| if it | |
> has been translated into |new_hlist(q)|, or |goto done_with_node| | |
> if a node has been fully processed@>; | |
> check_dimensions: z:=hpack(new_hlist(q),natural); | |
> if height(z)>max_h then max_h:=height(z); | |
> if depth(z)>max_d then max_d:=depth(z); | |
11528,11529c14211,14212 | |
< done_with_noad: r←q; r_type←type(r); | |
< done_with_node: q←link(q); | |
--- | |
> done_with_noad: r:=q; r_type:=type(r); | |
> done_with_node: q:=link(q); | |
11537c14220 | |
< reswitch: delta←0; | |
--- | |
> reswitch: delta:=0; | |
11540,11544c14223,14227 | |
< bin_noad,op_noad,rel_noad,open_noad,punct_noad,left_noad: | |
< begin type(q)←ord_noad; goto reswitch; | |
< end; | |
< othercases do_nothing | |
< endcases; | |
--- | |
> bin_noad,op_noad,rel_noad,open_noad,punct_noad,left_noad: | |
> begin type(q):=ord_noad; goto reswitch; | |
> end; | |
> othercases do_nothing | |
> endcases; | |
11546,11548c14229,14231 | |
< if r_type=bin_noad then type(r)←ord_noad; | |
< if type(q)=right_noad then goto done_with_noad; | |
< end; | |
--- | |
> @<Convert \(a)a final |bin_noad| to an |ord_noad|@>; | |
> if type(q)=right_noad then goto done_with_noad; | |
> end; | |
11551c14234 | |
< |goto done_with_node|@>@; | |
--- | |
> |goto done_with_node|@>@; | |
11553,11555c14236,14241 | |
< @:confusion mlist1}{\quad mlist1@> | |
< endcases; | |
< @<Convert \(o)|operand(q)| to an hlist and attach the sub/superscripts@> | |
--- | |
> @:this can't happen mlist1}{\quad mlist1@> | |
> endcases;@/ | |
> @<Convert \(n)|nucleus(q)| to an hlist and attach the sub/superscripts@> | |
> | |
> @ @<Convert \(a)a final |bin_noad| to an |ord_noad|@>= | |
> if r_type=bin_noad then type(r):=ord_noad | |
11558,11565c14244,14254 | |
< style_node: begin cur_style←subtype(q); | |
< @<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>; | |
< goto done_with_node; | |
< end; | |
< whatsit_node,penalty_node,disc_node: goto done_with_node; | |
< rule_node: begin if height(q)>max_h then max_h←height(q); | |
< if depth(q)>max_d then max_d←depth(q); goto done_with_node; | |
< end; | |
--- | |
> style_node: begin cur_style:=subtype(q); | |
> @<Set up the values of |cur_size| and |cur_mu|, based on |cur_style|@>; | |
> goto done_with_node; | |
> end; | |
> choice_node: @<Change this node to a style node followed by the correct choice, | |
> then |goto done_with_node|@>; | |
> ins_node,mark_node,adjust_node, | |
> whatsit_node,penalty_node,disc_node: goto done_with_node; | |
> rule_node: begin if height(q)>max_h then max_h:=height(q); | |
> if depth(q)>max_d then max_d:=depth(q); goto done_with_node; | |
> end; | |
11567,11568c14256,14257 | |
< goto done_with_node; | |
< end; | |
--- | |
> goto done_with_node; | |
> end; | |
11570c14259,14281 | |
< end; | |
--- | |
> end; | |
> | |
> @ @d choose_mlist(#)==begin p:=#(q); #(q):=null;@+end | |
> | |
> @<Change this node to a style node...@>= | |
> begin case cur_style div 2 of | |
> 0: choose_mlist(display_mlist); {|display_style=0|} | |
> 1: choose_mlist(text_mlist); {|text_style=2|} | |
> 2: choose_mlist(script_mlist); {|script_style=4|} | |
> 3: choose_mlist(script_script_mlist); {|script_script_style=6|} | |
> end; {there are no other cases} | |
> flush_node_list(display_mlist(q)); | |
> flush_node_list(text_mlist(q)); | |
> flush_node_list(script_mlist(q)); | |
> flush_node_list(script_script_mlist(q));@/ | |
> type(q):=style_node; subtype(q):=cur_style; width(q):=0; depth(q):=0; | |
> if p<>null then | |
> begin z:=link(q); link(q):=p; | |
> while link(p)<>null do p:=link(p); | |
> link(p):=z; | |
> end; | |
> goto done_with_node; | |
> end | |
11576c14287 | |
< (`\.{\\mskip}') is converted to normal glue by multiplying the dimensions | |
--- | |
> (`\.{\\muskip}') is converted to normal glue by multiplying the dimensions | |
11577a14289 | |
> @!@:non_script_}{\.{\\nonscript} primitive@> | |
11581,11589c14293,14302 | |
< begin x←glue_ptr(q); | |
< y←math_glue(x,cur_mu); delete_glue_ref(x); glue_ptr(q)←y; | |
< end | |
< else if (cur_size>text_size)∧(subtype(q)=cond_math_glue) then | |
< begin p←link(q); | |
< if p≠null then if (type(p)=glue_node)∨(type(p)=kern_node) then | |
< begin link(q)←link(p); link(p)←null; flush_node_list(p); | |
< end; | |
< end | |
--- | |
> begin x:=glue_ptr(q); | |
> y:=math_glue(x,cur_mu); delete_glue_ref(x); glue_ptr(q):=y; | |
> subtype(q):=normal; | |
> end | |
> else if (cur_size<>text_size)and(subtype(q)=cond_math_glue) then | |
> begin p:=link(q); | |
> if p<>null then if (type(p)=glue_node)or(type(p)=kern_node) then | |
> begin link(q):=link(p); link(p):=null; flush_node_list(p); | |
> end; | |
> end | |
11594,11597c14307,14310 | |
< end; | |
< op_noad: begin delta←make_op(q); | |
< if subtype(q)=switched then goto check_dimensions; | |
< end; | |
--- | |
> end; | |
> op_noad: begin delta:=make_op(q); | |
> if subtype(q)=limits then goto check_dimensions; | |
> end; | |
11607c14320,14321 | |
< by procedures like |make_fraction|, |make_radical|, etc. To illustrate | |
--- | |
> by procedures with names | |
> like |make_fraction|, |make_radical|, etc. To illustrate | |
11613,11615c14327,14330 | |
< begin info(operand(q))←@|overbar(clean_box(operand(q),und_style(cur_style)),@| | |
< 3*default_rule_thickness,default_rule_thickness); | |
< math_type(operand(q))←sub_box; | |
--- | |
> begin info(nucleus(q)):=@| | |
> overbar(clean_box(nucleus(q),cramped_style(cur_style)),@| | |
> 3*default_rule_thickness,default_rule_thickness); | |
> math_type(nucleus(q)):=sub_box; | |
11622,11628c14337,14343 | |
< begin x←clean_box(operand(q),cur_style); | |
< p←new_kern(3*default_rule_thickness); link(x)←p; | |
< link(p)←fraction_rule(default_rule_thickness); | |
< y←vpack(x,natural); | |
< delta←height(y)+depth(y)+default_rule_thickness; | |
< height(y)←height(x); depth(y)←delta-height(y); | |
< info(operand(q))←y; math_type(operand(q))←sub_box; | |
--- | |
> begin x:=clean_box(nucleus(q),cur_style); | |
> p:=new_kern(3*default_rule_thickness); link(x):=p; | |
> link(p):=fraction_rule(default_rule_thickness); | |
> y:=vpack(x,natural); | |
> delta:=height(y)+depth(y)+default_rule_thickness; | |
> height(y):=height(x); depth(y):=delta-height(y); | |
> info(nucleus(q)):=y; math_type(nucleus(q)):=sub_box; | |
11635,11640c14350,14355 | |
< begin v←info(operand(q)); | |
< if type(v)≠vlist_node then confusion("vcenter"); | |
< @:confusion vcenter}{\quad vcenter@> | |
< delta←height(v)+depth(v); | |
< height(v)←axis_height(cur_size)+half(delta); | |
< depth(v)←height(v)-delta; | |
--- | |
> begin v:=info(nucleus(q)); | |
> if type(v)<>vlist_node then confusion("vcenter"); | |
> @:this can't happen vcenter}{\quad vcenter@> | |
> delta:=height(v)+depth(v); | |
> height(v):=axis_height(cur_size)+half(delta); | |
> depth(v):=delta-height(v); | |
11645c14360 | |
< between a square root sign and the rule above its operand by assuming that the | |
--- | |
> between a square root sign and the rule above its nucleus by assuming that the | |
11649c14364 | |
< of the operand plus a certain minimum clearance@@|clr|. The symbol will be | |
--- | |
> of the nucleus plus a certain minimum clearance~|clr|. The symbol will be | |
11656,11668c14371,14382 | |
< begin x←clean_box(operand(q),und_style(cur_style)); | |
< if cur_style<text_style then | |
< clr←default_rule_thickness+(math_x_height(cur_size) div 4) | |
< else begin clr←default_rule_thickness; clr←clr + (clr div 4); | |
< end; | |
< y←var_delimiter(left_delimiter(q),cur_size,height(x)+depth(x)+clr+ | |
< default_rule_thickness); | |
< if height(y)≤0 then height(y)←default_rule_thickness; | |
< delta←depth(y)-(height(x)+depth(x)+clr); | |
< if delta>0 then clr←clr+half(delta); {increase the actual clearance} | |
< shift_amount(y)←-(height(x)+clr); | |
< link(y)←overbar(x,clr,height(y)); | |
< info(operand(q))←hpack(y,natural); math_type(operand(q))←sub_box; | |
--- | |
> begin x:=clean_box(nucleus(q),cramped_style(cur_style)); | |
> if cur_style<text_style then {display style} | |
> clr:=default_rule_thickness+(abs(math_x_height(cur_size)) div 4) | |
> else begin clr:=default_rule_thickness; clr:=clr + (abs(clr) div 4); | |
> end; | |
> y:=var_delimiter(left_delimiter(q),cur_size,height(x)+depth(x)+clr+ | |
> default_rule_thickness); | |
> delta:=depth(y)-(height(x)+depth(x)+clr); | |
> if delta>0 then clr:=clr+half(delta); {increase the actual clearance} | |
> shift_amount(y):=-(height(x)+clr); | |
> link(y):=overbar(x,clr,height(y)); | |
> info(nucleus(q)):=hpack(y,natural); math_type(nucleus(q)):=sub_box; | |
11677c14391 | |
< label done; | |
--- | |
> label done,done1; | |
11679c14393,14400 | |
< @!delta:scaled; {amount to raise the accent} | |
--- | |
> @!a:integer; {address of lig/kern instruction} | |
> @!c:quarterword; {accent character} | |
> @!f:internal_font_number; {its font} | |
> @!i:four_quarters; {its |char_info|} | |
> @!s:scaled; {amount to skew the accent to the right} | |
> @!h:scaled; {height of character being accented} | |
> @!delta:scaled; {space to remove between accent and accentee} | |
> @!w:scaled; {width of the accentee, not including sub/superscripts} | |
11682,11693c14403,14424 | |
< begin x←clean_box(operand(q),und_style(cur_style)); | |
< @<Switch to a larger accent if available and appropriate@>; | |
< delta←height(x)-x_height(cur_f); | |
< if delta<0 then delta←0; | |
< y←hpack(new_character(cur_f,cur_c),natural); | |
< shift_amount(y)←half(width(x)-width(y)); | |
< width(y)←0; p←new_kern(delta-height(x)); link(p)←x; link(y)←p; | |
< y←vpack(y,natural); width(y)←width(x); | |
< info(operand(q))←y; | |
< math_type(operand(q))←sub_box; | |
< end; | |
< end; | |
--- | |
> begin i:=cur_i; c:=cur_c; f:=cur_f;@/ | |
> @<Compute the amount of skew@>; | |
> x:=clean_box(nucleus(q),cramped_style(cur_style)); w:=width(x); h:=height(x); | |
> @<Switch to a larger accent if available and appropriate@>; | |
> if h<x_height(f) then delta:=h@+else delta:=x_height(f); | |
> if (math_type(supscr(q))<>empty)or(math_type(subscr(q))<>empty) then | |
> if math_type(nucleus(q))=math_char then | |
> @<Swap the subscript and superscript into box |x|@>; | |
> y:=char_box(f,c); | |
> shift_amount(y):=s+half(w-width(y)); | |
> width(y):=0; p:=new_kern(-delta); link(p):=x; link(y):=p; | |
> y:=vpack(y,natural); width(y):=width(x); | |
> if height(y)<h then @<Make the height of box |y| equal to |h|@>; | |
> info(nucleus(q)):=y; | |
> math_type(nucleus(q)):=sub_box; | |
> end; | |
> end; | |
> | |
> @ @<Make the height of box |y|...@>= | |
> begin p:=new_kern(h-height(y)); link(p):=list_ptr(y); list_ptr(y):=p; | |
> height(y):=h; | |
> end | |
11696,11701c14427,14433 | |
< loop@+ begin if char_tag(cur_i)≠list_tag then goto done; | |
< y←rem_byte(cur_i); | |
< cur_i←char_info(cur_f)(y); | |
< if char_width(cur_f)(cur_i)>width(x) then goto done; | |
< cur_c←y; | |
< end; | |
--- | |
> loop@+ begin if char_tag(i)<>list_tag then goto done; | |
> y:=rem_byte(i); | |
> i:=char_info(f)(y); | |
> if not char_exists(i) then goto done; | |
> if char_width(f)(i)>w then goto done; | |
> c:=y; | |
> end; | |
11703a14436,14470 | |
> @ @<Compute the amount of skew@>= | |
> s:=0; | |
> if math_type(nucleus(q))=math_char then | |
> begin fetch(nucleus(q)); | |
> if char_tag(cur_i)=lig_tag then | |
> begin a:=lig_kern_start(cur_f)(cur_i); | |
> cur_i:=font_info[a].qqqq; | |
> if skip_byte(cur_i)>stop_flag then | |
> begin a:=lig_kern_restart(cur_f)(cur_i); | |
> cur_i:=font_info[a].qqqq; | |
> end; | |
> loop@+ begin if qo(next_char(cur_i))=skew_char[cur_f] then | |
> begin if op_byte(cur_i)>=kern_flag then | |
> if skip_byte(cur_i)<=stop_flag then s:=char_kern(cur_f)(cur_i); | |
> goto done1; | |
> end; | |
> if skip_byte(cur_i)>=stop_flag then goto done1; | |
> a:=a+qo(skip_byte(cur_i))+1; | |
> cur_i:=font_info[a].qqqq; | |
> end; | |
> end; | |
> end; | |
> done1: | |
> | |
> @ @<Swap the subscript and superscript into box |x|@>= | |
> begin flush_node_list(x); x:=new_noad; | |
> mem[nucleus(x)]:=mem[nucleus(q)]; | |
> mem[supscr(x)]:=mem[supscr(q)]; | |
> mem[subscr(x)]:=mem[subscr(q)];@/ | |
> mem[supscr(q)].hh:=empty_field; | |
> mem[subscr(q)].hh:=empty_field;@/ | |
> math_type(nucleus(q)):=sub_mlist; info(nucleus(q)):=x; | |
> x:=clean_box(nucleus(q),cur_style); delta:=delta+height(x)-h; h:=height(x); | |
> end | |
> | |
11711,11714c14478,14482 | |
< {dimensions for box calculations} | |
< begin @<Create equal-width boxes |x| and |z| for the numerator and denominator, | |
< and compute the default amounts |shift_up| and |shift_down| by which they | |
< are displaced from the baseline@>; | |
--- | |
> {dimensions for box calculations} | |
> begin if thickness(q)=default_code then thickness(q):=default_rule_thickness; | |
> @<Create equal-width boxes |x| and |z| for the numerator and denominator, | |
> and compute the default amounts |shift_up| and |shift_down| by which they | |
> are displaced from the baseline@>; | |
11716c14484 | |
< of no fraction line@> | |
--- | |
> of no fraction line@> | |
11719c14487 | |
< |shift_down|@>; | |
--- | |
> |shift_down|@>; | |
11721c14489 | |
< point to it@>; | |
--- | |
> point to it@>; | |
11725,11735c14493,14503 | |
< x←clean_box(numerator(q),num_style(cur_style)); | |
< z←clean_box(denominator(q),denom_style(cur_style)); | |
< if width(x)<width(z) then x←rebox(x,width(z)) | |
< else z←rebox(z,width(x)); | |
< if cur_style<text_style then | |
< begin shift_up←num1(cur_size); shift_down←denom1(cur_size); | |
< end | |
< else begin shift_down←denom2(cur_size); | |
< if thickness(q)≠0 then shift_up←num2(cur_size) | |
< else shift_up←num3(cur_size); | |
< end | |
--- | |
> x:=clean_box(numerator(q),num_style(cur_style)); | |
> z:=clean_box(denominator(q),denom_style(cur_style)); | |
> if width(x)<width(z) then x:=rebox(x,width(z)) | |
> else z:=rebox(z,width(x)); | |
> if cur_style<text_style then {display style} | |
> begin shift_up:=num1(cur_size); shift_down:=denom1(cur_size); | |
> end | |
> else begin shift_down:=denom2(cur_size); | |
> if thickness(q)<>0 then shift_up:=num2(cur_size) | |
> else shift_up:=num3(cur_size); | |
> end | |
11742,11744c14510,14512 | |
< begin if cur_style<text_style then clr←7*default_rule_thickness | |
< else clr←3*default_rule_thickness; | |
< delta←half(clr-((shift_up-depth(x))-(height(z)-shift_down))); | |
--- | |
> begin if cur_style<text_style then clr:=7*default_rule_thickness | |
> else clr:=3*default_rule_thickness; | |
> delta:=half(clr-((shift_up-depth(x))-(height(z)-shift_down))); | |
11746,11748c14514,14516 | |
< begin shift_up←shift_up+delta; | |
< shift_down←shift_down-delta; | |
< end; | |
--- | |
> begin shift_up:=shift_up+delta; | |
> shift_down:=shift_down+delta; | |
> end; | |
11755,11762c14523,14529 | |
< begin if thickness(q)=default_code then thickness(q)←default_rule_thickness; | |
< if cur_style<text_style then clr←3*thickness(q) | |
< else clr←thickness(q); | |
< delta←half(thickness(q)); | |
< delta1←clr-((shift_up-depth(x))-(axis_height(cur_size)+delta)); | |
< delta2←clr-((axis_height(cur_size)-delta)-(height(z)-shift_down)); | |
< if delta1>0 then shift_up←shift_up+delta1; | |
< if delta2>0 then shift_down←shift_down+delta2; | |
--- | |
> begin if cur_style<text_style then clr:=3*thickness(q) | |
> else clr:=thickness(q); | |
> delta:=half(thickness(q)); | |
> delta1:=clr-((shift_up-depth(x))-(axis_height(cur_size)+delta)); | |
> delta2:=clr-((axis_height(cur_size)-delta)-(height(z)-shift_down)); | |
> if delta1>0 then shift_up:=shift_up+delta1; | |
> if delta2>0 then shift_down:=shift_down+delta2; | |
11766,11768c14533,14535 | |
< v←new_null_box; type(v)←vlist_node; | |
< height(v)←shift_up+height(x); depth(v)←depth(z)+shift_down; | |
< width(v)←width(x); {this also equals |width(z)|} | |
--- | |
> v:=new_null_box; type(v):=vlist_node; | |
> height(v):=shift_up+height(x); depth(v):=depth(z)+shift_down; | |
> width(v):=width(x); {this also equals |width(z)|} | |
11770,11779c14537,14546 | |
< begin p←new_kern((shift_up-depth(x))-(height(z)-shift_down)); | |
< link(p)←z; | |
< end | |
< else begin y←fraction_rule(thickness(q));@/ | |
< p←new_kern((axis_height(cur_size)-delta)-@|(height(z)-shift_down));@/ | |
< link(y)←p;@/ | |
< p←new_kern((shift_up-depth(x))-(axis_height(cur_size)+delta)); | |
< link(p)←y; | |
< end; | |
< link(x)←p; list_ptr(v)←x | |
--- | |
> begin p:=new_kern((shift_up-depth(x))-(height(z)-shift_down)); | |
> link(p):=z; | |
> end | |
> else begin y:=fraction_rule(thickness(q));@/ | |
> p:=new_kern((axis_height(cur_size)-delta)-@|(height(z)-shift_down));@/ | |
> link(y):=p; link(p):=z;@/ | |
> p:=new_kern((shift_up-depth(x))-(axis_height(cur_size)+delta)); | |
> link(p):=y; | |
> end; | |
> link(x):=p; list_ptr(v):=x | |
11782,11795c14549,14559 | |
< if cur_style<text_style then delta←delim1(cur_size) | |
< else delta←delim2(cur_size); | |
< x←var_delimiter(left_delimiter(q), cur_size, delta); link(x)←v;@/ | |
< z←var_delimiter(right_delimiter(q), cur_size, delta); link(v)←z;@/ | |
< new_hlist(q)←hpack(x,natural) | |
< | |
< @ An |op_noad| is a bit confusing because its |operand| is really an | |
< ``operator.'' We shall occasionally call the operator an operand, since | |
< that is where the information appears in the data structure. If such an | |
< operand is a single character, it is to be centered vertically with | |
< respect to the axis, after first being enlarged (via a character list in | |
< the font) if we are in display style. The normal convention for placing | |
< displayed limits is to put them to the right only when the character has a | |
< nonzero italic correction. | |
--- | |
> if cur_style<text_style then delta:=delim1(cur_size) | |
> else delta:=delim2(cur_size); | |
> x:=var_delimiter(left_delimiter(q), cur_size, delta); link(x):=v;@/ | |
> z:=var_delimiter(right_delimiter(q), cur_size, delta); link(v):=z;@/ | |
> new_hlist(q):=hpack(x,natural) | |
> | |
> @ If the nucleus of an |op_noad| is a single character, it is to be | |
> centered vertically with respect to the axis, after first being enlarged | |
> (via a character list in the font) if we are in display style. The normal | |
> convention for placing displayed limits is to put them above and below the | |
> operator in display style. | |
11797,11798c14561,14562 | |
< The italic correction is removed from the character unless the limits are | |
< being placed at the right and there is no subscript. The |make_op| | |
--- | |
> The italic correction is removed from the character if there is a subscript | |
> and the limits are not being displayed. The |make_op| | |
11802,11803c14566,14567 | |
< After |make_op| has acted, |subtype(q)| will be |switched| if and only if | |
< the limits have been set above and below the operand. In that case, | |
--- | |
> After |make_op| has acted, |subtype(q)| will be |limits| if and only if | |
> the limits have been set above and below the operator. In that case, | |
11809a14574 | |
> @!c:quarterword;@+@!i:four_quarters; {registers for character examination} | |
11811,11832c14576,14596 | |
< begin if math_type(operand(q))=math_char then | |
< begin fetch(operand(q)); | |
< if (cur_style<text_style)∧(char_tag(cur_i)=list_tag) then {make it larger} | |
< begin cur_c←rem_byte(cur_i); character(operand(q))←cur_c; | |
< cur_i←char_info(cur_f)(cur_c); | |
< end; | |
< delta←char_italic(cur_f)(cur_i); x←clean_box(operand(q),cur_style); | |
< width(x)←width(x)-delta; {remove italic correction} | |
< shift_amount(x)←half(height(x)-depth(x)) - axis_height(cur_size); | |
< {center vertically} | |
< math_type(operand(q))←sub_box; info(operand(q))←x; | |
< end | |
< else delta←0; | |
< if cur_style<text_style then {display styles} | |
< if ((delta=0)∧(subtype(q)=normal))∨@| | |
< ((delta≠0)∧(subtype(q)=switched)) then subtype(q)←switched | |
< else subtype(q)←normal | |
< else subtype(q)←normal; | |
< if subtype(q)=switched then | |
< @<Construct a box with limits above and below it, skewed by |delta|@> | |
< else if (delta≠0)∧(math_type(subscr(q))=empty) then width(x)←width(x)+delta; | |
< make_op←delta; | |
--- | |
> begin if (subtype(q)=normal)and(cur_style<text_style) then | |
> subtype(q):=limits; | |
> if math_type(nucleus(q))=math_char then | |
> begin fetch(nucleus(q)); | |
> if (cur_style<text_style)and(char_tag(cur_i)=list_tag) then {make it larger} | |
> begin c:=rem_byte(cur_i); i:=char_info(cur_f)(c); | |
> if char_exists(i) then | |
> begin cur_c:=c; cur_i:=i; character(nucleus(q)):=c; | |
> end; | |
> end; | |
> delta:=char_italic(cur_f)(cur_i); x:=clean_box(nucleus(q),cur_style); | |
> if (math_type(subscr(q))<>empty)and(subtype(q)<>limits) then | |
> width(x):=width(x)-delta; {remove italic correction} | |
> shift_amount(x):=half(height(x)-depth(x)) - axis_height(cur_size); | |
> {center vertically} | |
> math_type(nucleus(q)):=sub_box; info(nucleus(q)):=x; | |
> end | |
> else delta:=0; | |
> if subtype(q)=limits then | |
> @<Construct a box with limits above and below it, skewed by |delta|@>; | |
> make_op:=delta; | |
11839,11847c14603,14611 | |
< begin x←clean_box(supscr(q),sup_style(cur_style)); | |
< y←clean_box(operand(q),cur_style); | |
< z←clean_box(subscr(q),sub_style(cur_style)); | |
< v←new_null_box; type(v)←vlist_node; width(v)←width(y); | |
< if width(x)>width(v) then width(v)←width(x); | |
< if width(z)>width(v) then width(v)←width(z); | |
< x←rebox(x,width(v)); y←rebox(y,width(v)); z←rebox(z,width(v));@/ | |
< shift_amount(x)←half(delta); shift_amount(z)←-shift_amount(x); | |
< height(v)←height(y); depth(v)←depth(y); | |
--- | |
> begin x:=clean_box(supscr(q),sup_style(cur_style)); | |
> y:=clean_box(nucleus(q),cur_style); | |
> z:=clean_box(subscr(q),sub_style(cur_style)); | |
> v:=new_null_box; type(v):=vlist_node; width(v):=width(y); | |
> if width(x)>width(v) then width(v):=width(x); | |
> if width(z)>width(v) then width(v):=width(z); | |
> x:=rebox(x,width(v)); y:=rebox(y,width(v)); z:=rebox(z,width(v));@/ | |
> shift_amount(x):=half(delta); shift_amount(z):=-shift_amount(x); | |
> height(v):=height(y); depth(v):=depth(y); | |
11849,11850c14613,14614 | |
< account for their presence@>; | |
< new_hlist(q)←v; | |
--- | |
> account for their presence@>; | |
> new_hlist(q):=v; | |
11860,11867c14624,14631 | |
< begin free_node(x,box_node_size); list_ptr(v)←y; | |
< end | |
< else begin shift_up←big_op_spacing3-depth(x); | |
< if shift_up<big_op_spacing1 then shift_up←big_op_spacing1; | |
< p←new_kern(shift_up); link(p)←y; link(x)←p;@/ | |
< p←new_kern(big_op_spacing5); link(p)←x; list_ptr(v)←p; | |
< height(v)←height(v)+big_op_spacing5+height(x)+depth(x)+shift_up; | |
< end; | |
--- | |
> begin free_node(x,box_node_size); list_ptr(v):=y; | |
> end | |
> else begin shift_up:=big_op_spacing3-depth(x); | |
> if shift_up<big_op_spacing1 then shift_up:=big_op_spacing1; | |
> p:=new_kern(shift_up); link(p):=y; link(x):=p;@/ | |
> p:=new_kern(big_op_spacing5); link(p):=x; list_ptr(v):=p; | |
> height(v):=height(v)+big_op_spacing5+height(x)+depth(x)+shift_up; | |
> end; | |
11869,11874c14633,14638 | |
< else begin shift_down←big_op_spacing4-height(z); | |
< if shift_down<big_op_spacing2 then shift_down←big_op_spacing2; | |
< p←new_kern(shift_down); link(y)←p; link(p)←z;@/ | |
< p←new_kern(big_op_spacing5); link(z)←p; | |
< depth(v)←depth(v)+big_op_spacing5+height(z)+depth(z)+shift_down; | |
< end | |
--- | |
> else begin shift_down:=big_op_spacing4-height(z); | |
> if shift_down<big_op_spacing2 then shift_down:=big_op_spacing2; | |
> p:=new_kern(shift_down); link(y):=p; link(p):=z;@/ | |
> p:=new_kern(big_op_spacing5); link(z):=p; | |
> depth(v):=depth(v)+big_op_spacing5+height(z)+depth(z)+shift_down; | |
> end | |
11879a14644,14649 | |
> The |math_type| is converted to |math_text_char| here if we would not want to | |
> apply an italic correction to the current character unless it belongs | |
> to a math font (i.e., a font with |space=0|). | |
> | |
> No boundary characters enter into these ligatures. | |
> | |
11882c14652 | |
< label restart; | |
--- | |
> label restart,exit; | |
11884,11907c14654,14684 | |
< @!p:pointer; {temporary register for list manipulation} | |
< begin restart:@;@/ | |
< if (math_type(subscr(q))=empty)∧(math_type(supscr(q))=empty)∧@| | |
< (math_type(operand(q))=math_char) then | |
< begin p←link(q); | |
< if p≠null then if (type(p)≥ord_noad)∧(type(p)≤punct_noad) then | |
< if math_type(operand(p))=math_char then | |
< if fam(operand(p))=fam(operand(q)) then | |
< begin fetch(operand(q)); | |
< if char_tag(cur_i)=lig_tag then | |
< begin a←lig_kern_start(cur_f)(cur_i); | |
< cur_c←character(operand(p)); | |
< repeat cur_i←font_info[a].qqqq;@/ | |
< @<If instruction |cur_i| is a kern with |cur_c|, | |
< attach the kern after |q|; | |
< or if it is a ligature with |cur_c|, combine | |
< noads |q| and |p| and |goto restart|@>; | |
< incr(a); | |
< until stop_bit(cur_i)≥stop_flag; | |
< end; | |
< end; | |
< end; | |
< end; | |
< | |
--- | |
> @!p,@!r:pointer; {temporary registers for list manipulation} | |
> begin restart:@t@>@;@/ | |
> if math_type(subscr(q))=empty then if math_type(supscr(q))=empty then | |
> if math_type(nucleus(q))=math_char then | |
> begin p:=link(q); | |
> if p<>null then if (type(p)>=ord_noad)and(type(p)<=punct_noad) then | |
> if math_type(nucleus(p))=math_char then | |
> if fam(nucleus(p))=fam(nucleus(q)) then | |
> begin math_type(nucleus(q)):=math_text_char; | |
> fetch(nucleus(q)); | |
> if char_tag(cur_i)=lig_tag then | |
> begin a:=lig_kern_start(cur_f)(cur_i); | |
> cur_c:=character(nucleus(p)); | |
> cur_i:=font_info[a].qqqq; | |
> if skip_byte(cur_i)>stop_flag then | |
> begin a:=lig_kern_restart(cur_f)(cur_i); | |
> cur_i:=font_info[a].qqqq; | |
> end; | |
> loop@+ begin @<If instruction |cur_i| is a kern with |cur_c|, attach | |
> the kern after~|q|; or if it is a ligature with |cur_c|, combine | |
> noads |q| and~|p| appropriately; then |return| if the cursor has | |
> moved past a noad, or |goto restart|@>; | |
> if skip_byte(cur_i)>=stop_flag then return; | |
> a:=a+qo(skip_byte(cur_i))+1; | |
> cur_i:=font_info[a].qqqq; | |
> end; | |
> end; | |
> end; | |
> end; | |
> exit:end; | |
> | |
11909c14686,14688 | |
< is replaced by an |ord_noad|. Presumably a font designer will define such | |
--- | |
> is replaced by an |ord_noad|, when the two noads collapse into one. | |
> But we could make a parenthesis (say) change shape when it follows | |
> certain letters. Presumably a font designer will define such | |
11911a14691,14692 | |
> \chardef\?='174 % vertical line to indicate character retention | |
> | |
11913,11922c14694,14718 | |
< if next_char(cur_i)=cur_c then | |
< if op_bit(cur_i)≥kern_flag then | |
< begin p←new_kern(char_kern(cur_f)(cur_i)); | |
< link(p)←link(q); link(q)←p; | |
< end | |
< else begin link(q)←link(p); character(operand(q))←rem_byte(cur_i);@/ | |
< mem[subscr(q)]←mem[subscr(p)]; | |
< mem[supscr(q)]←mem[supscr(p)]; | |
< free_node(p,noad_size); goto restart; | |
< end | |
--- | |
> if next_char(cur_i)=cur_c then if skip_byte(cur_i)<=stop_flag then | |
> if op_byte(cur_i)>=kern_flag then | |
> begin p:=new_kern(char_kern(cur_f)(cur_i)); | |
> link(p):=link(q); link(q):=p; return; | |
> end | |
> else begin check_interrupt; {allow a way out of infinite ligature loop} | |
> case op_byte(cur_i) of | |
> qi(1),qi(5): character(nucleus(q)):=rem_byte(cur_i); {\.{=:\?}, \.{=:\?>}} | |
> qi(2),qi(6): character(nucleus(p)):=rem_byte(cur_i); {\.{\?=:}, \.{\?=:>}} | |
> qi(3),qi(7),qi(11):begin r:=new_noad; {\.{\?=:\?}, \.{\?=:\?>}, \.{\?=:\?>>}} | |
> character(nucleus(r)):=rem_byte(cur_i); | |
> fam(nucleus(r)):=fam(nucleus(q));@/ | |
> link(q):=r; link(r):=p; | |
> if op_byte(cur_i)<qi(11) then math_type(nucleus(r)):=math_char | |
> else math_type(nucleus(r)):=math_text_char; {prevent combination} | |
> end; | |
> othercases begin link(q):=link(p); | |
> character(nucleus(q)):=rem_byte(cur_i); {\.{=:}} | |
> mem[subscr(q)]:=mem[subscr(p)]; mem[supscr(q)]:=mem[supscr(p)];@/ | |
> free_node(p,noad_size); | |
> end | |
> endcases; | |
> if op_byte(cur_i)>qi(3) then return; | |
> math_type(nucleus(q)):=math_char; goto restart; | |
> end | |
11926c14722 | |
< |done_with_node|. Thus, |q|@@points to a noad whose operand may need to be | |
--- | |
> |done_with_node|. Thus, |q|~points to a noad whose nucleus may need to be | |
11930c14726 | |
< If |operand(q)| is not a |math_char|, the variable |delta| is the amount | |
--- | |
> If |nucleus(q)| is not a |math_char|, the variable |delta| is the amount | |
11936,11947c14732,14745 | |
< @<Convert \(o)|operand(q)| to an hlist and attach the sub/superscripts@>= | |
< case math_type(operand(q)) of | |
< math_char: @<Create a character node |p| for |operand(q)|, possibly followed | |
< by a kern node for the italic correction, and set |delta| to the | |
< italic correction if a subscript is present@>; | |
< empty: p←null; | |
< sub_box: p←info(operand(q)); | |
< sub_mlist: begin cur_mlist←info(operand(q)); save_style←cur_style; | |
< mlist_penalties←false; mlist_to_hlist; {recursive call} | |
< cur_style←save_style; @<Set up the values...@>; | |
< p←hpack(link(temp_head),natural); | |
< end; | |
--- | |
> @<Convert \(n)|nucleus(q)| to an hlist and attach the sub/superscripts@>= | |
> case math_type(nucleus(q)) of | |
> math_char, math_text_char: | |
> @<Create a character node |p| for |nucleus(q)|, possibly followed | |
> by a kern node for the italic correction, and set |delta| to the | |
> italic correction if a subscript is present@>; | |
> empty: p:=null; | |
> sub_box: p:=info(nucleus(q)); | |
> sub_mlist: begin cur_mlist:=info(nucleus(q)); save_style:=cur_style; | |
> mlist_penalties:=false; mlist_to_hlist; {recursive call} | |
> @^recursion@> | |
> cur_style:=save_style; @<Set up the values...@>; | |
> p:=hpack(link(temp_head),natural); | |
> end; | |
11949c14747 | |
< @:confusion mlist2}{\quad mlist2@> | |
--- | |
> @:this can't happen mlist2}{\quad mlist2@> | |
11951,11953c14749,14751 | |
< new_hlist(q)←p; | |
< if (math_type(subscr(q))=empty)∧(math_type(supscr(q))=empty) then | |
< goto check_dimensions; | |
--- | |
> new_hlist(q):=p; | |
> if (math_type(subscr(q))=empty)and(math_type(supscr(q))=empty) then | |
> goto check_dimensions; | |
11956,11957c14754,14755 | |
< @ @<Create a character node |p| for |operand(q)|...@>= | |
< begin fetch(operand(q)); | |
--- | |
> @ @<Create a character node |p| for |nucleus(q)|...@>= | |
> begin fetch(nucleus(q)); | |
11959,11964c14757,14764 | |
< begin delta←char_italic(cur_f)(cur_i); p←new_character(cur_f,cur_c); | |
< if (math_type(subscr(q))=empty)∧(delta≠0) then | |
< begin link(p)←new_kern(delta); delta←0; | |
< end; | |
< end | |
< else p←null; | |
--- | |
> begin delta:=char_italic(cur_f)(cur_i); p:=new_character(cur_f,qo(cur_c)); | |
> if (math_type(nucleus(q))=math_text_char)and(space(cur_f)<>0) then | |
> delta:=0; {no italic correction in mid-word of text font} | |
> if (math_type(subscr(q))=empty)and(delta<>0) then | |
> begin link(p):=new_kern(delta); delta:=0; | |
> end; | |
> end | |
> else p:=null; | |
11969c14769 | |
< given that subscript and superscript aren't both empty. The superscript | |
--- | |
> given that the subscript and superscript aren't both empty. The superscript | |
11973c14773 | |
< baseline of subscripts and superscripts based on the given operand. | |
--- | |
> baseline of subscripts and superscripts based on the given nucleus. | |
11980c14780 | |
< begin p←new_hlist(q); | |
--- | |
> begin p:=new_hlist(q); | |
11982,11989c14782,14789 | |
< begin shift_up←0; shift_down←0; | |
< end | |
< else begin z←hpack(p,natural); | |
< if cur_style<script_style then t←script_size@+else t←script_script_size; | |
< shift_up←height(z)-sup_drop(t); | |
< shift_down←depth(z)+sub_drop(t); | |
< free_node(z,box_node_size); | |
< end; | |
--- | |
> begin shift_up:=0; shift_down:=0; | |
> end | |
> else begin z:=hpack(p,natural); | |
> if cur_style<script_style then t:=script_size@+else t:=script_script_size; | |
> shift_up:=height(z)-sup_drop(t); | |
> shift_down:=depth(z)+sub_drop(t); | |
> free_node(z,box_node_size); | |
> end; | |
11991,12001c14791,14801 | |
< @<Construct a subscript box |x| when there is no superscript@> | |
< else begin @<Construct a superscript box |x|@>; | |
< if math_type(subscr(q))=empty then shift_amount(x)←-shift_up | |
< else @<Construct a sub/superscript combination box |x|, with the | |
< superscript offset by |delta|@>; | |
< end; | |
< if new_hlist(q)=null then new_hlist(q)←x | |
< else begin p←new_hlist(q); | |
< while link(p)≠null do p←link(p); | |
< link(p)←x; | |
< end; | |
--- | |
> @<Construct a subscript box |x| when there is no superscript@> | |
> else begin @<Construct a superscript box |x|@>; | |
> if math_type(subscr(q))=empty then shift_amount(x):=-shift_up | |
> else @<Construct a sub/superscript combination box |x|, with the | |
> superscript offset by |delta|@>; | |
> end; | |
> if new_hlist(q)=null then new_hlist(q):=x | |
> else begin p:=new_hlist(q); | |
> while link(p)<>null do p:=link(p); | |
> link(p):=x; | |
> end; | |
12008,12013c14808,14813 | |
< begin x←clean_box(subscr(q),sub_style(cur_style)); | |
< width(x)←width(x)+script_space; | |
< if shift_down<sub1(cur_size) then shift_down←sub1(cur_size); | |
< clr←height(x)-((math_x_height(cur_size)*4) div 5); | |
< if shift_down<clr then shift_down←clr; | |
< shift_amount(x)←shift_down; | |
--- | |
> begin x:=clean_box(subscr(q),sub_style(cur_style)); | |
> width(x):=width(x)+script_space; | |
> if shift_down<sub1(cur_size) then shift_down:=sub1(cur_size); | |
> clr:=height(x)-(abs(math_x_height(cur_size)*4) div 5); | |
> if shift_down<clr then shift_down:=clr; | |
> shift_amount(x):=shift_down; | |
12020,12027c14820,14827 | |
< begin x←clean_box(supscr(q),sup_style(cur_style)); | |
< width(x)←width(x)+script_space; | |
< if odd(cur_style) then clr←sup3(cur_size) | |
< else if cur_style<text_style then clr←sup1(cur_size) | |
< else clr←sup2(cur_size); | |
< if shift_up<clr then shift_up←clr; | |
< clr←depth(x)+(math_x_height(cur_size) div 4); | |
< if shift_up<clr then shift_up←clr; | |
--- | |
> begin x:=clean_box(supscr(q),sup_style(cur_style)); | |
> width(x):=width(x)+script_space; | |
> if odd(cur_style) then clr:=sup3(cur_size) | |
> else if cur_style<text_style then clr:=sup1(cur_size) | |
> else clr:=sup2(cur_size); | |
> if shift_up<clr then shift_up:=clr; | |
> clr:=depth(x)+(abs(math_x_height(cur_size)) div 4); | |
> if shift_up<clr then shift_up:=clr; | |
12031c14831 | |
< at least four times |default_rule_thickness| away from the superscript. | |
--- | |
> separated from the superscript by at least four times |default_rule_thickness|. | |
12037,12041c14837,14841 | |
< begin y←clean_box(subscr(q),sub_style(cur_style)); | |
< width(y)←width(y)+script_space; | |
< if shift_down<sub2(cur_size) then shift_down←sub2(cur_size); | |
< clr←4*default_rule_thickness- | |
< ((shift_up-depth(x))-(height(y)-shift_down)); | |
--- | |
> begin y:=clean_box(subscr(q),sub_style(cur_style)); | |
> width(y):=width(y)+script_space; | |
> if shift_down<sub2(cur_size) then shift_down:=sub2(cur_size); | |
> clr:=4*default_rule_thickness- | |
> ((shift_up-depth(x))-(height(y)-shift_down)); | |
12043,12052c14843,14852 | |
< begin shift_down←shift_down+clr; | |
< clr←(4*math_x_height(cur_size) div 5)-(shift_up-depth(x)); | |
< if clr>0 then | |
< begin shift_up←shift_up+clr; | |
< shift_down←shift_down-clr; | |
< end; | |
< end; | |
< shift_amount(x)←delta; {superscript is |delta| to the right of the subscript} | |
< p←new_kern((shift_up-depth(x))-(height(y)-shift_down)); link(x)←p; link(p)←y; | |
< x←vpack(x,natural); shift_amount(x)←shift_down; | |
--- | |
> begin shift_down:=shift_down+clr; | |
> clr:=(abs(math_x_height(cur_size)*4) div 5)-(shift_up-depth(x)); | |
> if clr>0 then | |
> begin shift_up:=shift_up+clr; | |
> shift_down:=shift_down-clr; | |
> end; | |
> end; | |
> shift_amount(x):=delta; {superscript is |delta| to the right of the subscript} | |
> p:=new_kern((shift_up-depth(x))-(height(y)-shift_down)); link(x):=p; link(p):=y; | |
> x:=vpack(x,natural); shift_amount(x):=shift_down; | |
12054c14854 | |
< | |
--- | |
> | |
12062c14862 | |
< p←temp_head; link(p)←null; q←mlist; r_type←0; cur_style←style; | |
--- | |
> p:=temp_head; link(p):=null; q:=mlist; r_type:=0; cur_style:=style; | |
12064,12074c14864,14874 | |
< while q≠null do | |
< begin @<If node |q| is a style node, change the style and |goto delete_q|; | |
< otherwise if it is not a noad, put it into the hlist, | |
< advance |q|, and |goto done|; otherwise set |s| to the size | |
< of noad |q|, set |t| to the associated type (|ord_noad.. | |
< inner_noad|), and set |pen| to the associated penalty@>; | |
< @<Append inter-element spacing based on |r_type| and |t|@>; | |
< @<Append any |new_hlist| entries for |q|, and any appropriate penalties@>; | |
< r_type←t; | |
< delete_q: r←q; q←link(q); free_node(r,s); | |
< done: end | |
--- | |
> while q<>null do | |
> begin @<If node |q| is a style node, change the style and |goto delete_q|; | |
> otherwise if it is not a noad, put it into the hlist, | |
> advance |q|, and |goto done|; otherwise set |s| to the size | |
> of noad |q|, set |t| to the associated type (|ord_noad.. | |
> inner_noad|), and set |pen| to the associated penalty@>; | |
> @<Append inter-element spacing based on |r_type| and |t|@>; | |
> @<Append any |new_hlist| entries for |q|, and any appropriate penalties@>; | |
> r_type:=t; | |
> delete_q: r:=q; q:=link(q); free_node(r,s); | |
> done: end | |
12076,12077c14876,14877 | |
< @ Before we do the big |case| switch in the second pass, we set the default | |
< values so that most of the branches are short. | |
--- | |
> @ Just before doing the big |case| switch in the second pass, the program | |
> sets up default values so that most of the branches are short. | |
12080c14880 | |
< t←inner_noad; s←noad_size; pen←inf_penalty; | |
--- | |
> t:=ord_noad; s:=noad_size; pen:=inf_penalty; | |
12082,12091c14882,14892 | |
< ord_noad,op_noad,open_noad,close_noad,punct_noad: t←type(q); | |
< bin_noad: begin t←bin_noad; pen←bin_op_penalty; | |
< end; | |
< rel_noad: begin t←rel_noad; pen←rel_penalty; | |
< end; | |
< inner_noad,vcenter_noad,over_noad,under_noad: do_nothing; | |
< radical_noad: s←radical_noad_size; | |
< accent_noad: s←accent_noad_size; | |
< fraction_noad: s←fraction_noad_size; | |
< left_noad,right_noad: t←make_left_right(q,style,max_d,max_h); | |
--- | |
> op_noad,open_noad,close_noad,punct_noad,inner_noad: t:=type(q); | |
> bin_noad: begin t:=bin_noad; pen:=bin_op_penalty; | |
> end; | |
> rel_noad: begin t:=rel_noad; pen:=rel_penalty; | |
> end; | |
> ord_noad,vcenter_noad,over_noad,under_noad: do_nothing; | |
> radical_noad: s:=radical_noad_size; | |
> accent_noad: s:=accent_noad_size; | |
> fraction_noad: begin t:=inner_noad; s:=fraction_noad_size; | |
> end; | |
> left_noad,right_noad: t:=make_left_right(q,style,max_d,max_h); | |
12093,12096c14894,14897 | |
< whatsit_node,penalty_node,rule_node,disc_node, | |
< glue_node,kern_node: begin@t@>@;@/ | |
< link(p)←q; q←link(q); link(p)←null; goto done; | |
< end; | |
--- | |
> whatsit_node,penalty_node,rule_node,disc_node,adjust_node,ins_node,mark_node, | |
> glue_node,kern_node:@t@>@;@/ | |
> begin link(p):=q; p:=q; q:=link(q); link(p):=null; goto done; | |
> end; | |
12098c14899 | |
< @:confusion mlist3}{\quad mlist3@> | |
--- | |
> @:this can't happen mlist3}{\quad mlist3@> | |
12101,12104c14902,14905 | |
< @ The |make_left_right| function constructs a delimiter of the required size | |
< and returns the value |open_noad| or |close_noad|. The |right_noad| and | |
< |left_noad| will both be based on the original |style|, so they will | |
< have consistent sizes. | |
--- | |
> @ The |make_left_right| function constructs a left or right delimiter of | |
> the required size and returns the value |open_noad| or |close_noad|. The | |
> |right_noad| and |left_noad| will both be based on the original |style|, | |
> so they will have consistent sizes. | |
12110c14911 | |
< @!max_d,@!max_h:scaled):small_number; | |
--- | |
> @!max_d,@!max_h:scaled):small_number; | |
12112,12121c14913,14922 | |
< begin if style<script_style then cur_size←text_size | |
< else cur_size←16*((style-text_style) div 2); | |
< delta2←max_d+axis_height(cur_size); | |
< delta1←max_h+max_d-delta2; | |
< if delta2>delta1 then delta1←delta2; {|delta1| is max distance from axis} | |
< delta←(delimiter_factor*delta1) div 500; | |
< delta2←delta1+delta1-delimiter_limit; | |
< if delta<delta2 then delta←delta2; | |
< new_hlist(q)←var_delimiter(delimiter(q),cur_size,delta); | |
< make_left_right←type(q)-(left_noad-open_noad); {|open_noad| or |close_noad|} | |
--- | |
> begin if style<script_style then cur_size:=text_size | |
> else cur_size:=16*((style-text_style) div 2); | |
> delta2:=max_d+axis_height(cur_size); | |
> delta1:=max_h+max_d-delta2; | |
> if delta2>delta1 then delta1:=delta2; {|delta1| is max distance from axis} | |
> delta:=(delta1 div 500)*delimiter_factor; | |
> delta2:=delta1+delta1-delimiter_shortfall; | |
> if delta<delta2 then delta:=delta2; | |
> new_hlist(q):=var_delimiter(delimiter(q),cur_size,delta); | |
> make_left_right:=type(q)-(left_noad-open_noad); {|open_noad| or |close_noad|} | |
12125c14926 | |
< begin cur_style←subtype(q); s←small_node_size; | |
--- | |
> begin cur_style:=subtype(q); s:=style_node_size; | |
12135,12138c14936,14941 | |
< \.1 means a conditional thin space (\.{\\nonscript\\mskip\\the\\thinmskip});\cr | |
< \.2 means a thin space (\.{\\mskip\\the\\thinmskip});\cr | |
< \.3 means a conditional medium space (\.{\\nonscript\\mskip\\the\\medmskip});\cr | |
< \.4 means a thick space (\.{\\mskip\\the\\thickmskip});\cr | |
--- | |
> \.1 means a conditional thin space (\.{\\nonscript\\mskip\\thinmuskip});\cr | |
> \.2 means a thin space (\.{\\mskip\\thinmuskip});\cr | |
> \.3 means a conditional medium space | |
> (\.{\\nonscript\\mskip\\medmuskip});\cr | |
> \.4 means a conditional thick space | |
> (\.{\\nonscript\\mskip\\thickmuskip});\cr | |
12140,12141c14943,14945 | |
< This is all pretty cryptic, but the \TeX\ manual explains what is supposed to | |
< happen, and the string makes it happen. | |
--- | |
> This is all pretty cryptic, but {\sl The \TeX book\/} explains what is | |
> supposed to happen, and the string makes it happen. | |
> @:TeXbook}{\sl The \TeX book@> | |
12153,12154c14957,14958 | |
< "0234000022*4000033**3**344*0400400*000000234000011*4111102340000" | |
< @t\hskip-35pt@> | |
--- | |
> "0234000122*4000133**3**344*0400400*000000234000111*1111112341011" | |
> @t$ \hskip-35pt$@> | |
12160c14964 | |
< magic_offset←str_start[math_spacing]-9*ord_noad | |
--- | |
> magic_offset:=str_start[math_spacing]-9*ord_noad | |
12164,12178c14968,14982 | |
< begin case str_pool[r_type*8+t+magic_offset] of | |
< "0": x←0; | |
< "1": if cur_style<script_style then x←thin_mskip_code@+else x←0; | |
< "2": x←thin_mskip_code; | |
< "3": if cur_style<script_style then x←med_mskip_code@+else x←0; | |
< "4": x←thick_mskip_code; | |
< othercases confusion("mlist4") | |
< @:confusion mlist4}{\quad mlist4@> | |
< endcases; | |
< if x≠0 then | |
< begin y←math_glue(glue_par(x),cur_mu); | |
< z←new_glue(y); glue_ref_count(y)←null; link(p)←z; p←z;@/ | |
< subtype(z)←x+1; {store a symbolic subtype} | |
< end; | |
< end | |
--- | |
> begin case so(str_pool[r_type*8+t+magic_offset]) of | |
> "0": x:=0; | |
> "1": if cur_style<script_style then x:=thin_mu_skip_code@+else x:=0; | |
> "2": x:=thin_mu_skip_code; | |
> "3": if cur_style<script_style then x:=med_mu_skip_code@+else x:=0; | |
> "4": if cur_style<script_style then x:=thick_mu_skip_code@+else x:=0; | |
> othercases confusion("mlist4") | |
> @:this can't happen mlist4}{\quad mlist4@> | |
> endcases; | |
> if x<>0 then | |
> begin y:=math_glue(glue_par(x),cur_mu); | |
> z:=new_glue(y); glue_ref_count(y):=null; link(p):=z; p:=z;@/ | |
> subtype(z):=x+1; {store a symbolic subtype} | |
> end; | |
> end | |
12185,12196c14989,15001 | |
< if new_hlist(q)≠null then | |
< begin link(p)←new_hlist(q); | |
< repeat p←link(p); | |
< until link(p)=null; | |
< end; | |
< if (pen<inf_penalty)∧ penalties ∧(link(q)≠null) then | |
< begin r_type←type(link(q)); | |
< if (r_type≠penalty_node)∧(r_type≠rel_noad) then | |
< begin z←new_penalty(pen); link(p)←z; p←z; | |
< end; | |
< end | |
< @* \[36] Alignment. | |
--- | |
> if new_hlist(q)<>null then | |
> begin link(p):=new_hlist(q); | |
> repeat p:=link(p); | |
> until link(p)=null; | |
> end; | |
> if penalties then if link(q)<>null then if pen<inf_penalty then | |
> begin r_type:=type(link(q)); | |
> if r_type<>penalty_node then if r_type<>rel_noad then | |
> begin z:=new_penalty(pen); link(p):=z; p:=z; | |
> end; | |
> end | |
> | |
> @* \[37] Alignment. | |
12198c15003,15005 | |
< they cut across so many of the control structures of \TeX. There\-fore the | |
--- | |
> they cut across so many of the control structures of \TeX. | |
> | |
> Therefore the | |
12220,12221c15027,15028 | |
< places the 300pt dimension onto |save_stack|, and the code |align_group| | |
< is placed above it. This will make it possible to complete the alignment | |
--- | |
> places the 300pt dimension onto the |save_stack|, and an |align_group| | |
> code is placed above it. This will make it possible to complete the alignment | |
12247c15054 | |
< token list `\.{u1}', i.e., the template preceding the `\.\#' for column@@1. | |
--- | |
> token list `\.{u1}', i.e., the template preceding the `\.\#' for column~1. | |
12258c15065 | |
< alignrecord for column@@1; in general, the alignrecords will record the | |
--- | |
> alignrecord for column~1; in general, the alignrecords will record the | |
12261c15068 | |
< (3) Since `\.{\\omit}' folows the `\.\&', the templates for column@@2 | |
--- | |
> (3) Since `\.{\\omit}' follows the `\.\&', the templates for column~2 | |
12265c15072 | |
< is remembered in the |width| field of the alignrecord for column@@2. | |
--- | |
> is remembered in the |width| field of the alignrecord for column~2. | |
12268c15075 | |
< mecha\-nism that worked for column@@1; this unset box contains `\.{u3\\vrule | |
--- | |
> mechanism that worked for column~1; this unset box contains `\.{u3\\vrule | |
12281c15088 | |
< {}\\unsetbox for 1 column: u3\vrule v3\cr | |
--- | |
> {}\\unsetbox for 1 column: u3\\vrule v3\cr | |
12299c15106 | |
< The natural width of the unset box that spans columns 1@@and@@2 is stored | |
--- | |
> The natural width of the unset box that spans columns 1~and~2 is stored | |
12301c15108 | |
< alignrecord for column@@1 now points to the new span node, and the |info| | |
--- | |
> alignrecord for column~1 now points to the new span node, and the |info| | |
12330,12331c15137,15138 | |
< @d u_part(#)==mem[#+height_offset].int {pointer to \<u↓j> token list} | |
< @d v_part(#)==mem[#+depth_offset].int {pointer to \<v↓j> token list} | |
--- | |
> @d u_part(#)==mem[#+height_offset].int {pointer to \<u_j> token list} | |
> @d v_part(#)==mem[#+depth_offset].int {pointer to \<v_j> token list} | |
12339,12341c15146,15152 | |
< spanned columns; and the |align_state| variable, which indicates the nesting | |
< of braces so that \.{\\cr} and \.{\\span} and tab marks are properly | |
< intercepted. | |
--- | |
> spanned columns; a |cur_loop| pointer, indicating the tabskip glue before | |
> an alignrecord that should be copied next if the current list is extended; | |
> and the |align_state| variable, which indicates the nesting of braces so | |
> that \.{\\cr} and \.{\\span} and tab marks are properly intercepted. | |
> There also are pointers |cur_head| and |cur_tail| to the head and tail | |
> of a list of adjustments being moved out from horizontal mode to | |
> vertical~mode. | |
12343,12344c15154,15155 | |
< The current values of these four quantities appear in global variables; | |
< when they have to be pushed down, they are stored in 3-word nodes, and | |
--- | |
> The current values of these seven quantities appear in global variables; | |
> when they have to be pushed down, they are stored in 5-word nodes, and | |
12348c15159 | |
< @d align_stack_node_size=3 {number of |mem| words to save alignment states} | |
--- | |
> @d align_stack_node_size=5 {number of |mem| words to save alignment states} | |
12352a15164 | |
> @!cur_loop:pointer; {place to copy when extending a periodic preamble} | |
12353a15166 | |
> @!cur_head,@!cur_tail:pointer; {adjustment list pointers} | |
12358c15171,15172 | |
< align_ptr←null; cur_align←null; cur_span←null; | |
--- | |
> align_ptr:=null; cur_align:=null; cur_span:=null; cur_loop:=null; | |
> cur_head:=null; cur_tail:=null; | |
12365,12368c15179,15185 | |
< begin p←get_node(align_stack_node_size); | |
< link(p)←align_ptr; info(p)←cur_align; | |
< llink(p)←preamble; rlink(p)←cur_span; | |
< mem[p+2].int←align_state; align_ptr←p; | |
--- | |
> begin p:=get_node(align_stack_node_size); | |
> link(p):=align_ptr; info(p):=cur_align; | |
> llink(p):=preamble; rlink(p):=cur_span; | |
> mem[p+2].int:=cur_loop; mem[p+3].int:=align_state; | |
> info(p+4):=cur_head; link(p+4):=cur_tail; | |
> align_ptr:=p; | |
> cur_head:=get_avail; | |
12373,12375c15190,15195 | |
< begin p←align_ptr; align_state←mem[p+2].int; | |
< cur_span←rlink(p); preamble←llink(p); | |
< cur_align←info(p); align_ptr←link(p); | |
--- | |
> begin free_avail(cur_head); | |
> p:=align_ptr; | |
> cur_tail:=link(p+4); cur_head:=info(p+4); | |
> align_state:=mem[p+3].int; cur_loop:=mem[p+2].int; | |
> cur_span:=rlink(p); preamble:=llink(p); | |
> cur_align:=info(p); align_ptr:=link(p); | |
12399c15219 | |
< procedure@?off_save; forward;@t\2@>@/ | |
--- | |
> procedure@?normal_paragraph; forward;@t\2@>@/ | |
12404,12405c15224,15225 | |
< begin save_cs_ptr←cs_ptr; {\.{\\halign} or \.{\\valign}, usually} | |
< push_alignment; align_state←-1000000; {enter a new alignment level} | |
--- | |
> begin save_cs_ptr:=cur_cs; {\.{\\halign} or \.{\\valign}, usually} | |
> push_alignment; align_state:=-1000000; {enter a new alignment level} | |
12409c15229 | |
< scan_spec; new_save_level(align_group); | |
--- | |
> scan_spec(align_group,false);@/ | |
12410a15231,15232 | |
> new_save_level(align_group); | |
> if every_cr<>null then begin_token_list(every_cr,every_cr_text); | |
12421,12425c15243,15245 | |
< begin mode←-vmode; prev_depth←nest[nest_ptr-2].aux_field; | |
< end | |
< else begin if mode>0 then mode←-mode; | |
< if mode=-hmode then space_factor←1000; | |
< end | |
--- | |
> begin mode:=-vmode; prev_depth:=nest[nest_ptr-2].aux_field.sc; | |
> end | |
> else if mode>0 then negate(mode) | |
12428,12430c15248 | |
< no other pieces of mlists present. Incomplete mlists need to be | |
< deleted; and we must convert them to hlists first, since the | |
< |flush_node_list| procedure doesn't know about noads. | |
--- | |
> no other pieces of mlists present. | |
12433,12445c15251,15258 | |
< if (mode=mmode)∧((tail≠head)∨(incompleat_noad≠null)) then | |
< begin print_nl("! Improper \halign"); | |
< @.Improper \\halign@> | |
< help3("Displays can use special alignments (like \eqalignno)")@/ | |
< ("only if nothing but the alignment itself is between $$'s.")@/ | |
< ("So I've deleted the formulas that preceded this alignment."); | |
< error;@/ | |
< cur_style←display_style; mlist_penalties←false; | |
< cur_mlist←link(head); mlist_to_hlist; flush_node_list(link(temp_head));@/ | |
< cur_style←display_style; cur_mlist←incompleat_noad; | |
< mlist_to_hlist; {|mlist_penalties=true|} | |
< flush_node_list(link(temp_head)); | |
< end | |
--- | |
> if (mode=mmode)and((tail<>head)or(incompleat_noad<>null)) then | |
> begin print_err("Improper "); print_esc("halign"); print(" inside $$'s"); | |
> @.Improper \\halign...@> | |
> help3("Displays can use special alignments (like \eqalignno)")@/ | |
> ("only if nothing but the alignment itself is between $$'s.")@/ | |
> ("So I've deleted the formulas that preceded this alignment."); | |
> error; flush_math; | |
> end | |
12448,12457c15261,15270 | |
< preamble←null; cur_align←align_head; scanner_status←aligning; | |
< warning_index←save_cs_ptr; | |
< {at this point, |cur_cmd=left_brace| and |align_state=-999999|} | |
< loop@+ begin @<Append the current tabskip glue to the preamble list@>; | |
< if cur_cmd=car_ret then goto done; {\.{\\cr} ends the preamble} | |
< @<Scan preamble text until |cur_cmd| is |tab_mark| or |car_ret|, | |
< looking for changes in the tabskip glue; append an | |
< alignrecord to the preamble list@>; | |
< end; | |
< done: scanner_status←normal | |
--- | |
> preamble:=null; cur_align:=align_head; cur_loop:=null; scanner_status:=aligning; | |
> warning_index:=save_cs_ptr; align_state:=-1000000; | |
> {at this point, |cur_cmd=left_brace|} | |
> loop@+ begin @<Append the current tabskip glue to the preamble list@>; | |
> if cur_cmd=car_ret then goto done; {\.{\\cr} ends the preamble} | |
> @<Scan preamble text until |cur_cmd| is |tab_mark| or |car_ret|, | |
> looking for changes in the tabskip glue; append an | |
> alignrecord to the preamble list@>; | |
> end; | |
> done: scanner_status:=normal | |
12460,12461c15273,15274 | |
< link(cur_align)←new_param_glue(tab_skip_code); | |
< cur_align←link(cur_align) | |
--- | |
> link(cur_align):=new_param_glue(tab_skip_code); | |
> cur_align:=link(cur_align) | |
12464,12469c15277,15282 | |
< @<Scan the template \<u↓j>, putting the resulting token list in |hold_head|@>; | |
< link(cur_align)←new_null_box; cur_align←link(cur_align); {a new alignrecord} | |
< info(cur_align)←end_span; width(cur_align)←null_flag; | |
< u_part(cur_align)←link(hold_head); | |
< @<Scan the template \<v↓j>, putting the resulting token list in |hold_head|@>; | |
< v_part(cur_align)←link(hold_head) | |
--- | |
> @<Scan the template \<u_j>, putting the resulting token list in |hold_head|@>; | |
> link(cur_align):=new_null_box; cur_align:=link(cur_align); {a new alignrecord} | |
> info(cur_align):=end_span; width(cur_align):=null_flag; | |
> u_part(cur_align):=link(hold_head); | |
> @<Scan the template \<v_j>, putting the resulting token list in |hold_head|@>; | |
> v_part(cur_align):=link(hold_head) | |
12472c15285 | |
< and with |span_code| as the operand modifier. This makes \TeX\ interpret it | |
--- | |
> and with |span_code| as the command modifier. This makes \TeX\ interpret it | |
12475c15288,15289 | |
< It also turns out to be useful to give a special |cr_code| to `\.{\\cr}'. | |
--- | |
> It also turns out to be useful to give a special |cr_code| to `\.{\\cr}', | |
> and an even larger |cr_cr_code| to `\.{\\crcr}'. | |
12477,12478c15291,15300 | |
< @d span_code=128 {distinct from any character} | |
< @d cr_code=129 {distinct from |span_code| and from any character} | |
--- | |
> The end of a template is represented by two ``frozen'' control sequences | |
> called \.{\\endtemplate}. The first has the command code |end_template|, which | |
> is |>outer_call|, so it will not easily disappear in the presence of errors. | |
> The |get_x_token| routine converts the first into the second, which has |endv| | |
> as its command code. | |
> | |
> @d span_code=256 {distinct from any character} | |
> @d cr_code=257 {distinct from |span_code| and from any character} | |
> @d cr_cr_code=cr_code+1 {this distinguishes \.{\\crcr} from \.{\\cr}} | |
> @d end_template_token==cs_token_flag+frozen_end_template | |
12481c15303 | |
< primitive("span",tab_mark,span_code); | |
--- | |
> primitive("span",tab_mark,span_code);@/ | |
12484a15307,15314 | |
> text(frozen_cr):="cr"; eqtb[frozen_cr]:=eqtb[cur_val];@/ | |
> primitive("crcr",car_ret,cr_cr_code); | |
> @!@:cr_cr_}{\.{\\crcr} primitive@> | |
> text(frozen_end_template):="endtemplate"; text(frozen_endv):="endtemplate"; | |
> eq_type(frozen_endv):=endv; equiv(frozen_endv):=null_list; | |
> eq_level(frozen_endv):=level_one;@/ | |
> eqtb[frozen_end_template]:=eqtb[frozen_endv]; | |
> eq_type(frozen_end_template):=end_template; | |
12486c15316,15322 | |
< @ The preamble is copied directly, except that \.{\\tabskip} causes a change | |
--- | |
> @ @<Cases of |print_cmd_chr|...@>= | |
> tab_mark: if chr_code=span_code then print_esc("span") | |
> else chr_cmd("alignment tab character "); | |
> car_ret: if chr_code=cr_code then print_esc("cr") | |
> else print_esc("crcr"); | |
> | |
> @ The preamble is copied directly, except that \.{\\tabskip} causes a change | |
12488c15324 | |
< follow it. | |
--- | |
> follow it. An appearance of \.{\\span} also causes such an expansion. | |
12496,12509c15332,15348 | |
< label reswitch; | |
< begin reswitch: get_token; | |
< if (cur_cmd=assign_glue)∧(cur_chr=tab_skip_code) then | |
< begin scan_optional_equals; scan_glue(false); | |
< eq_define(glue_base+tab_skip_code,glue_ref,cur_val); | |
< goto reswitch; | |
< end; | |
< if (cur_chr=span_code)∧(cur_cmd=tab_mark) then | |
< begin print_nl("! Illegal preamble"); | |
< @.Illegal preamble@> | |
< help2("You mustn't say \span in an alignment until after the \cr")@/ | |
< ("that ends the preamble. But proceed; I'll ignore this \span.");@/ | |
< error; goto reswitch; | |
< end; | |
--- | |
> label restart; | |
> begin restart: get_token; | |
> while (cur_chr=span_code)and(cur_cmd=tab_mark) do | |
> begin get_token; {this token will be expanded once} | |
> if cur_cmd>max_command then | |
> begin expand; get_token; | |
> end; | |
> end; | |
> if cur_cmd=endv then | |
> fatal_error("(interwoven alignment preambles are not allowed)"); | |
> @.interwoven alignment preambles...@> | |
> if (cur_cmd=assign_glue)and(cur_chr=glue_base+tab_skip_code) then | |
> begin scan_optional_equals; scan_glue(glue_val); | |
> if global_defs>0 then geq_define(glue_base+tab_skip_code,glue_ref,cur_val) | |
> else eq_define(glue_base+tab_skip_code,glue_ref,cur_val); | |
> goto restart; | |
> end; | |
12514,12529c15353,15370 | |
< @<Scan the template \<u↓j>...@>= | |
< p←hold_head; link(p)←null; | |
< loop@+ begin get_preamble_token; | |
< if cur_cmd=mac_param then goto done1; | |
< if (cur_cmd≤car_ret)∧(cur_cmd≥tab_mark) then | |
< begin print_nl("! Missing # inserted in alignment preamble"); | |
< @.Missing {\#} inserted...@> | |
< help3("There should be exactly one # between &'s, when an")@/ | |
< ("\halign or \valign is being set up. In this case you had")@/ | |
< ("none, so I've put one in; maybe that will work."); | |
< back_error; goto done1; | |
< end; | |
< if (cur_cmd≠spacer)∨(p≠hold_head) then | |
< begin link(p)←get_avail; p←link(p); info(p)←cur_tok; | |
< end; | |
< end; | |
--- | |
> @<Scan the template \<u_j>...@>= | |
> p:=hold_head; link(p):=null; | |
> loop@+ begin get_preamble_token; | |
> if cur_cmd=mac_param then goto done1; | |
> if (cur_cmd<=car_ret)and(cur_cmd>=tab_mark)and(align_state=-1000000) then | |
> if (p=hold_head)and(cur_loop=null)and(cur_cmd=tab_mark) | |
> then cur_loop:=cur_align | |
> else begin print_err("Missing # inserted in alignment preamble"); | |
> @.Missing \# inserted...@> | |
> help3("There should be exactly one # between &'s, when an")@/ | |
> ("\halign or \valign is being set up. In this case you had")@/ | |
> ("none, so I've put one in; maybe that will work."); | |
> back_error; goto done1; | |
> end | |
> else if (cur_cmd<>spacer)or(p<>hold_head) then | |
> begin link(p):=get_avail; p:=link(p); info(p):=cur_tok; | |
> end; | |
> end; | |
12532,12548c15373,15389 | |
< @ @<Scan the template \<v↓j>...@>= | |
< p←hold_head; link(p)←null; | |
< loop@+ begin continue: get_preamble_token; | |
< if (cur_cmd≤car_ret)∧(cur_cmd≥tab_mark)∧(align_state=-1000000) then | |
< goto done2; | |
< if cur_cmd=mac_param then | |
< begin print_nl("! Only one # is allowed per tab"); | |
< @.Only one {\#} is allowed...@> | |
< help3("There should be exactly one # between &'s, when an")@/ | |
< ("\halign or \valign is being set up. In this case you had")@/ | |
< ("more than one, so I'm ignoring all but the first."); | |
< goto continue; | |
< end; | |
< link(p)←get_avail; p←link(p); info(p)←cur_tok; | |
< end; | |
< done2: link(p)←get_avail; p←link(p); | |
< info(p)←endv_token {put |endv| at the end} | |
--- | |
> @ @<Scan the template \<v_j>...@>= | |
> p:=hold_head; link(p):=null; | |
> loop@+ begin continue: get_preamble_token; | |
> if (cur_cmd<=car_ret)and(cur_cmd>=tab_mark)and(align_state=-1000000) then | |
> goto done2; | |
> if cur_cmd=mac_param then | |
> begin print_err("Only one # is allowed per tab"); | |
> @.Only one \# is allowed...@> | |
> help3("There should be exactly one # between &'s, when an")@/ | |
> ("\halign or \valign is being set up. In this case you had")@/ | |
> ("more than one, so I'm ignoring all but the first."); | |
> error; goto continue; | |
> end; | |
> link(p):=get_avail; p:=link(p); info(p):=cur_tok; | |
> end; | |
> done2: link(p):=get_avail; p:=link(p); | |
> info(p):=end_template_token {put \.{\\endtemplate} at the end} | |
12562c15403,15404 | |
< begin @<Get the next non-blank non-call token@>; | |
--- | |
> label restart; | |
> begin restart: align_state:=1000000; @<Get the next non-blank non-call token@>; | |
12564,12565c15406,15408 | |
< begin scan_left_brace; new_save_level(no_align_group); | |
< end | |
--- | |
> begin scan_left_brace; new_save_level(no_align_group); | |
> if mode=-vmode then normal_paragraph; | |
> end | |
12567,12569c15410,15414 | |
< else begin init_row; {start a new row} | |
< init_col; {start a new column and replace what we peeked at} | |
< end; | |
--- | |
> else if (cur_cmd=car_ret)and(cur_chr=cr_cr_code) then | |
> goto restart {ignore \.{\\crcr}} | |
> else begin init_row; {start a new row} | |
> init_col; {start a new column and replace what we peeked at} | |
> end; | |
12574a15420,15421 | |
> The |space_factor| and |prev_depth| are not used on this semantic level, | |
> but we clear them to zero just to be tidy. | |
12578c15425,15426 | |
< begin push_nest; mode←(-hmode-vmode)-mode; | |
--- | |
> begin push_nest; mode:=(-hmode-vmode)-mode; | |
> if mode=-hmode then space_factor:=0 @+else prev_depth:=0; | |
12580,12581c15428,15429 | |
< subtype(tail)←tab_skip_code+1;@/ | |
< cur_align←link(preamble); init_span(cur_align); | |
--- | |
> subtype(tail):=tab_skip_code+1;@/ | |
> cur_align:=link(preamble); cur_tail:=cur_head; init_span(cur_align); | |
12591,12593c15439,15442 | |
< if mode=-vmode then prev_depth←ignore_depth | |
< else space_factor←1000; | |
< cur_span←p; | |
--- | |
> if mode=-hmode then space_factor:=1000 | |
> else begin prev_depth:=ignore_depth; normal_paragraph; | |
> end; | |
> cur_span:=p; | |
12597,12599c15446,15450 | |
< the current token should be put back into the input until the \<u↓j> template | |
< has been scanned. We remain in the same mode, and start the template if | |
< it is called for. | |
--- | |
> the current token should be put back into the input until the \<u_j> | |
> template has been scanned. (Note that |cur_cmd| might be |tab_mark| or | |
> |car_ret|.) We also assume that |align_state| is approximately 1000000 at | |
> this time. We remain in the same mode, and start the template if it is | |
> called for. | |
12602,12606c15453,15456 | |
< begin extra_info(cur_align)←cur_cmd; | |
< if cur_cmd=omit then align_state←0 | |
< else begin back_input; begin_token_list(u_part(cur_align),u_template); | |
< align_state←1000000; | |
< end; | |
--- | |
> begin extra_info(cur_align):=cur_cmd; | |
> if cur_cmd=omit then align_state:=0 | |
> else begin back_input; begin_token_list(u_part(cur_align),u_template); | |
> end; {now |align_state=1000000|} | |
12609c15459 | |
< @ The scanner sets |align_state| to zero when the \<u↓j> template ends. When | |
--- | |
> @ The scanner sets |align_state| to zero when the \<u_j> template ends. When | |
12611,12616c15461,15472 | |
< the scanner activates the following code, which fires up the \<v↓j> template. | |
< We need to remember the |cur_chr|, which is either |cr_code|, |span_code|, | |
< or a character code, depending on how the column text has ended. | |
< | |
< @<Insert the \(v)\<v↓j>...@>= | |
< begin cur_cmd←extra_info(cur_align); extra_info(cur_align)←cur_chr; | |
--- | |
> the scanner activates the following code, which fires up the \<v_j> template. | |
> We need to remember the |cur_chr|, which is either |cr_cr_code|, |cr_code|, | |
> |span_code|, or a character code, depending on how the column text has ended. | |
> | |
> This part of the program had better not be activated when the preamble | |
> to another alignment is being scanned, or when no alignment preamble is active. | |
> | |
> @<Insert the \(v)\<v_j>...@>= | |
> begin if (scanner_status=aligning) or (cur_align=null) then | |
> fatal_error("(interwoven alignment preambles are not allowed)"); | |
> @.interwoven alignment preambles...@> | |
> cur_cmd:=extra_info(cur_align); extra_info(cur_align):=cur_chr; | |
12619c15475 | |
< align_state←1000000; goto restart; | |
--- | |
> align_state:=1000000; goto restart; | |
12623c15479 | |
< list that contains |endv| only. | |
--- | |
> list that contains the special control sequence \.{\\endtemplate} only. | |
12626c15482 | |
< info(omit_template)←endv_token; {|link(omit_template)=null|} | |
--- | |
> info(omit_template):=end_template_token; {|link(omit_template)=null|} | |
12628c15484 | |
< @ When the |endv| token at the end of a \<v↓j> template comes through the | |
--- | |
> @ When the |endv| command at the end of a \<v_j> template comes through the | |
12636c15492 | |
< @!q:pointer; {runs through spanned alignrecords and span nodes} | |
--- | |
> @!q,@!r:pointer; {temporary pointers for list manipulation} | |
12642,12644c15498,15504 | |
< begin if (cur_align=null)∨(link(cur_align)=null) then confusion("endv"); | |
< @:confusion endv}{\quad endv@> | |
< p←link(link(cur_align)); | |
--- | |
> begin if cur_align=null then confusion("endv"); | |
> q:=link(cur_align);@+if q=null then confusion("endv"); | |
> @:this can't happen endv}{\quad endv@> | |
> if align_state<500000 then | |
> fatal_error("(interwoven alignment preambles are not allowed)"); | |
> @.interwoven alignment preambles...@> | |
> p:=link(q); | |
12646,12657c15506,15517 | |
< if extra_info(cur_align)≠span_code then | |
< begin @<Package an unset box for the current column and | |
< record its width@>; | |
< @<Copy the tabskip glue between columns@>; | |
< if extra_info(cur_align)=cr_code then | |
< @<Package any omitted columns as dummies, | |
< then |return| with |fin_col=true|@>; | |
< init_span(p); | |
< end; | |
< @<Get the next non-blank non-call token@>; | |
< cur_align←p; | |
< init_col; fin_col←false; | |
--- | |
> if extra_info(cur_align)<>span_code then | |
> begin unsave; new_save_level(align_group);@/ | |
> @<Package an unset box for the current column and record its width@>; | |
> @<Copy the tabskip glue between columns@>; | |
> if extra_info(cur_align)>=cr_code then | |
> begin fin_col:=true; return; | |
> end; | |
> init_span(p); | |
> end; | |
> align_state:=1000000; @<Get the next non-blank non-call token@>; | |
> cur_align:=p; | |
> init_col; fin_col:=false; | |
12661,12662c15521,15523 | |
< if (p=null)∧(extra_info(cur_align)≠cr_code) then | |
< begin print_nl("! Extra alignment tab has been changed to \cr"); | |
--- | |
> if (p=null)and(extra_info(cur_align)<cr_code) then | |
> if cur_loop<>null then @<Lengthen the preamble periodically@> | |
> else begin print_err("Extra alignment tab has been changed to "); | |
12664,12668c15525,15550 | |
< help3("You have given more \span or & marks than there were")@/ | |
< ("in the preamble to the \halign or \valign now in progress.")@/ | |
< ("So I'll assume that you meant to type \cr instead."); | |
< extra_info(cur_align)←cr_code; error; | |
< end | |
--- | |
> print_esc("cr"); | |
> help3("You have given more \span or & marks than there were")@/ | |
> ("in the preamble to the \halign or \valign now in progress.")@/ | |
> ("So I'll assume that you meant to type \cr instead."); | |
> extra_info(cur_align):=cr_code; error; | |
> end | |
> | |
> @ @<Lengthen the preamble...@>= | |
> begin link(q):=new_null_box; p:=link(q); {a new alignrecord} | |
> info(p):=end_span; width(p):=null_flag; cur_loop:=link(cur_loop); | |
> @<Copy the templates from node |cur_loop| into node |p|@>; | |
> cur_loop:=link(cur_loop); | |
> link(p):=new_glue(glue_ptr(cur_loop)); | |
> end | |
> | |
> @ @<Copy the templates from node |cur_loop| into node |p|@>= | |
> q:=hold_head; r:=u_part(cur_loop); | |
> while r<>null do | |
> begin link(q):=get_avail; q:=link(q); info(q):=info(r); r:=link(r); | |
> end; | |
> link(q):=null; u_part(p):=link(hold_head); | |
> q:=hold_head; r:=v_part(cur_loop); | |
> while r<>null do | |
> begin link(q):=get_avail; q:=link(q); info(q):=info(r); r:=link(r); | |
> end; | |
> link(q):=null; v_part(p):=link(hold_head) | |
12672,12684c15554 | |
< subtype(tail)←tab_skip_code+1 | |
< | |
< @ @<Package any omitted columns...@>= | |
< begin cur_align←p; | |
< while cur_align≠null do | |
< begin tail_append(new_null_box); | |
< type(tail)←unset_node; | |
< if width(cur_align)<0 then width(cur_align)←0; | |
< @<Copy the tabskip glue...@>; | |
< cur_align←link(link(cur_align)); | |
< end; | |
< fin_col←true; return; | |
< end | |
--- | |
> subtype(tail):=tab_skip_code+1 | |
12688,12695c15558,15566 | |
< begin u←hpack(head,natural); w←width(u); | |
< end | |
< else begin u←vpackage(head,natural,0); w←height(u); | |
< end; | |
< n←min_quarterword; {this represents a span count of 1} | |
< if cur_span≠cur_align then @<Update width entry for spanned columns@> | |
< else if w>width(cur_align) then width(cur_align)←w; | |
< type(u)←unset_node; span_count(u)←n;@/ | |
--- | |
> begin adjust_tail:=cur_tail; u:=hpack(link(head),natural); w:=width(u); | |
> cur_tail:=adjust_tail; adjust_tail:=null; | |
> end | |
> else begin u:=vpackage(link(head),natural,0); w:=height(u); | |
> end; | |
> n:=min_quarterword; {this represents a span count of 1} | |
> if cur_span<>cur_align then @<Update width entry for spanned columns@> | |
> else if w>width(cur_align) then width(cur_align):=w; | |
> type(u):=unset_node; span_count(u):=n;@/ | |
12697c15568 | |
< glue_order(u)←o; glue_stretch(u)←total_stretch[o];@/ | |
--- | |
> glue_order(u):=o; glue_stretch(u):=total_stretch[o];@/ | |
12699,12700c15570,15571 | |
< glue_sign(u)←o; glue_shrink(u)←total_shrink[o];@/ | |
< pop_nest; link(tail)←u; tail←u; | |
--- | |
> glue_sign(u):=o; glue_shrink(u):=total_shrink[o];@/ | |
> pop_nest; link(tail):=u; tail:=u; | |
12703c15574 | |
< @ A span node is a 2-word record contining |width|, |info|, and |link| | |
--- | |
> @ A span node is a 2-word record containing |width|, |info|, and |link| | |
12717c15588 | |
< link(end_span)←max_quarterword+1; info(end_span)←null; | |
--- | |
> link(end_span):=max_quarterword+1; info(end_span):=null; | |
12720,12721c15591,15592 | |
< q←cur_span; | |
< repeat incr(n); q←link(link(q)); | |
--- | |
> begin q:=cur_span; | |
> repeat incr(n); q:=link(link(q)); | |
12724,12725c15595,15597 | |
< @:confusion 256 spans}{\quad 256 spans@> | |
< q←cur_span; while link(info(q))<n do q←info(q); | |
--- | |
> @^system dependencies@> | |
> @:this can't happen 256 spans}{\quad 256 spans@> | |
> q:=cur_span; while link(info(q))<n do q:=info(q); | |
12727,12730c15599,15603 | |
< begin s←get_node(span_node_size); info(s)←info(q); link(s)←n; | |
< info(q)←s; width(s)←w; | |
< end | |
< else if width(info(q))<w then width(info(q))←w | |
--- | |
> begin s:=get_node(span_node_size); info(s):=info(q); link(s):=n; | |
> info(q):=s; width(s):=w; | |
> end | |
> else if width(info(q))<w then width(info(q)):=w; | |
> end | |
12740,12745c15613,15623 | |
< begin p←hpack(link(head),natural); pop_nest; append_to_vlist(p); | |
< end | |
< else begin p←vpack(link(head),natural); pop_nest; | |
< link(tail)←p; tail←p; space_factor←1000; | |
< end; | |
< type(p)←unset_node; glue_stretch(p)←0; | |
--- | |
> begin p:=hpack(link(head),natural); | |
> pop_nest; append_to_vlist(p); | |
> if cur_head<>cur_tail then | |
> begin link(tail):=link(cur_head); tail:=cur_tail; | |
> end; | |
> end | |
> else begin p:=vpack(link(head),natural); pop_nest; | |
> link(tail):=p; tail:=p; space_factor:=1000; | |
> end; | |
> type(p):=unset_node; glue_stretch(p):=0; | |
> if every_cr<>null then begin_token_list(every_cr,every_cr_text); | |
12747c15625 | |
< end; | |
--- | |
> end; {note that |glue_shrink(p)=0| since |glue_shrink==shift_amount|} | |
12757,12758c15635,15637 | |
< var @!p,@!q,@!r,@!s,@!u: pointer; {registers for the list operations} | |
< @!t:scaled; {width of column plus tabskip} | |
--- | |
> var @!p,@!q,@!r,@!s,@!u,@!v: pointer; {registers for the list operations} | |
> @!t,@!w:scaled; {width of column} | |
> @!o:scaled; {shift offset for unset boxes} | |
12760,12762c15639,15647 | |
< begin if cur_group≠align_group then confusion("align"); | |
< @:confusion align}{\quad align@> | |
< unsave;@/ | |
--- | |
> @!rule_save:scaled; {temporary storage for |overfull_rule|} | |
> @!aux_save:memory_word; {temporary storage for |aux|} | |
> begin if cur_group<>align_group then confusion("align1"); | |
> @:this can't happen align}{\quad align@> | |
> unsave; {that |align_group| was for individual entries} | |
> if cur_group<>align_group then confusion("align0"); | |
> unsave; {that |align_group| was for the whole alignment} | |
> if nest[nest_ptr-1].mode_field=mmode then o:=display_indent | |
> else o:=0; | |
12764c15649 | |
< changing the alignrecords to dummy unset boxes@>; | |
--- | |
> changing the alignrecords to dummy unset boxes@>; | |
12766c15651 | |
< and let |p| point to this prototype box@>; | |
--- | |
> and let |p| point to this prototype box@>; | |
12771c15656 | |
< @<Declare the procedure called |align_peek|@> | |
--- | |
> @t\4@>@<Declare the procedure called |align_peek|@> | |
12774,12779c15659,15664 | |
< widths. Let $w↓{ij}$ be the maximum of the natural widths of all entries | |
< that span columns $i$ through $j$, inclusive. The alignrecord for column@@$i$ | |
< contains $w↓{ii}$ in its |width| field, and there is also a linked list of | |
< the nonzero $w↓{ij}$ for increasing $j$, accessible via the |info| field; | |
< these span nodes contain the value $j-i-1+|min_quarterword|$ in their | |
< |link| fields. The values of $w↓{ii}$ were initialized to |null_flag|, which | |
--- | |
> widths. Let $w_{ij}$ be the maximum of the natural widths of all entries | |
> that span columns $i$ through $j$, inclusive. The alignrecord for column~$i$ | |
> contains $w_{ii}$ in its |width| field, and there is also a linked list of | |
> the nonzero $w_{ij}$ for increasing $j$, accessible via the |info| field; | |
> these span nodes contain the value $j-i+|min_quarterword|$ in their | |
> |link| fields. The values of $w_{ii}$ were initialized to |null_flag|, which | |
12783,12793c15668,15679 | |
< $$w↓j=\max↓{1\L i\L j}\bigglp(w↓{ij}-\sum↓{i\L k<j}(t↓k+w↓k)\biggrp,$$ | |
< where $t↓k$ is the natural width of the tabskip glue between columns | |
< $k$ and@@$k+1$. However, if $w↓{ij}=-\infty$ for all |i| in the range | |
< |1≤i≤j| (i.e., if every entry that involved column@@|j| also involved | |
< column@@|j+1|), we let $w↓j=0$. | |
< | |
< \TeX\ computes these values by using the following scheme: First $w↓1=w↓{11}$. | |
< Then replace $w↓{2j}$ by $\max(w↓{2j},w↓{1j}-t↓1-w↓1)$, for all $j>1$. | |
< Then $w↓2=w↓{22}$. Then replace $w↓{3j}$ by $\max(w↓{3j},w↓{2j}-t↓2-w↓2)$ | |
< for all $j>2$; and so on. If any $w↓j$ turns out to be $-\infty$, its | |
< value is changed to zero. | |
--- | |
> $$w_j=\max_{1\L i\L j}\biggl( w_{ij}-\sum_{i\L k<j}(t_k+w_k)\biggr),$$ | |
> where $t_k$ is the natural width of the tabskip glue between columns | |
> $k$ and~$k+1$. However, if $w_{ij}=-\infty$ for all |i| in the range | |
> |1<=i<=j| (i.e., if every entry that involved column~|j| also involved | |
> column~|j+1|), we let $w_j=0$, and we zero out the tabskip glue after | |
> column~|j|. | |
> | |
> \TeX\ computes these values by using the following scheme: First $w_1=w_{11}$. | |
> Then replace $w_{2j}$ by $\max(w_{2j},w_{1j}-t_1-w_1)$, for all $j>1$. | |
> Then $w_2=w_{22}$. Then replace $w_{3j}$ by $\max(w_{3j},w_{2j}-t_2-w_2)$ | |
> for all $j>2$; and so on. If any $w_j$ turns out to be $-\infty$, its | |
> value is changed to zero and so is the next tabskip. | |
12796c15682 | |
< q←link(preamble); | |
--- | |
> q:=link(preamble); | |
12798,12804c15684,15692 | |
< p←link(link(q)); | |
< if width(q)=null_flag then width(q)←0; | |
< if (p≠null)∧(info(q)≠end_span) then | |
< @<Merge the widths in the span nodes of |q| with those of |p|, | |
< destroying the span nodes of |q|@>; | |
< type(q)←unset_node; span_count(q)←min_quarterword; height(q)←width(q); | |
< depth(q)←0; glue_order(q)←normal; glue_sign(q)←normal; q←p; | |
--- | |
> p:=link(link(q)); | |
> if width(q)=null_flag then | |
> @<Nullify |width(q)| and the tabskip glue following this column@>; | |
> if info(q)<>end_span then | |
> @<Merge the widths in the span nodes of |q| with those of |p|, | |
> destroying the span nodes of |q|@>; | |
> type(q):=unset_node; span_count(q):=min_quarterword; height(q):=0; | |
> depth(q):=0; glue_order(q):=normal; glue_sign(q):=normal; | |
> glue_stretch(q):=0; glue_shrink(q):=0; q:=p; | |
12806a15695,15702 | |
> @ @<Nullify |width(q)| and the tabskip glue following this column@>= | |
> begin width(q):=0; r:=link(q); s:=glue_ptr(r); | |
> if s<>zero_glue then | |
> begin add_glue_ref(zero_glue); delete_glue_ref(s); | |
> glue_ptr(r):=zero_glue; | |
> end; | |
> end | |
> | |
12815,12817c15711,15713 | |
< begin t←width(q)+width(glue_ptr(link(q))); | |
< r←info(q); s←end_span; info(s)←p; n←min_quarterword+1; | |
< repeat width(r)←width(r)-t; u←info(r); | |
--- | |
> begin t:=width(q)+width(glue_ptr(link(q))); | |
> r:=info(q); s:=end_span; info(s):=p; n:=min_quarterword+1; | |
> repeat width(r):=width(r)-t; u:=info(r); | |
12819,12820c15715,15716 | |
< begin s←info(s); n←link(info(s))+1; | |
< end; | |
--- | |
> begin s:=info(s); n:=link(info(s))+1; | |
> end; | |
12822,12827c15718,15723 | |
< begin info(r)←info(s); info(s)←r; decr(link(r)); s←r; | |
< end | |
< else begin if width(r)>width(info(s)) then width(info(s))←width(r); | |
< free_node(r,span_node_size); | |
< end; | |
< r←u; | |
--- | |
> begin info(r):=info(s); info(s):=r; decr(link(r)); s:=r; | |
> end | |
> else begin if width(r)>width(info(s)) then width(info(s)):=width(r); | |
> free_node(r,span_node_size); | |
> end; | |
> r:=u; | |
12832,12837c15728,15731 | |
< boxes and tabskip glue, where the box heights and widths are both equal | |
< to the final column sizes. This list is both an hlist and a vlist, and | |
< both |hpack| and |vpack| will set its glue in the same way; but we should | |
< choose the correct alternative, because it is important to produce the | |
< correct error messages when an alignment is overfull or underfull. | |
< The following program changes the tabskip amounts to equivalent kerns. | |
--- | |
> boxes and tabskip glue, where the box widths are equal to the final | |
> column sizes. In case of \.{\\valign}, we change the widths to heights, | |
> so that a correct error message will be produced if the alignment is | |
> overfull or underfull. | |
12840,12853c15734,15748 | |
< save_ptr←save_ptr-2; | |
< if mode=-hmode then | |
< p←hpack(preamble,saved(1),saved(0)) | |
< else p←vpack(preamble,saved(1),saved(0)); | |
< q←p+list_offset; | |
< repeat q←link(q); r←glue_ptr(q); type(q)←kern_node; subtype(q)←normal; | |
< if glue_sign(p)=normal then width(q)←width(r) | |
< else if glue_sign(p)=stretching then | |
< if stretch_order(r)≠glue_order(p) then width(q)←width(r) | |
< else width(q)←width(q)+round(glue_set(p)*stretch(r)) | |
< else if shrink_order(r)≠glue_order(p) then width(q)←width(r) | |
< else width(q)←width(q)-round(glue_set(p)*shrink(r)); | |
< delete_glue_ref(r); q←link(q); | |
< until q=null | |
--- | |
> save_ptr:=save_ptr-2; pack_begin_line:=-mode_line; | |
> if mode=-vmode then | |
> begin rule_save:=overfull_rule; | |
> overfull_rule:=0; {prevent rule from being packaged} | |
> p:=hpack(preamble,saved(1),saved(0)); overfull_rule:=rule_save; | |
> end | |
> else begin q:=link(preamble); | |
> repeat height(q):=width(q); width(q):=0; q:=link(link(q)); | |
> until q=null; | |
> p:=vpack(preamble,saved(1),saved(0)); | |
> q:=link(preamble); | |
> repeat width(q):=height(q); height(q):=0; q:=link(link(q)); | |
> until q=null; | |
> end; | |
> pack_begin_line:=0 | |
12856,12861c15751,15773 | |
< q←link(head); | |
< while q≠null do | |
< begin if type(q)=unset_node then | |
< @<Set the unset box |q| and the unset boxes in it@>; | |
< q←link(q); | |
< end | |
--- | |
> q:=link(head); s:=head; | |
> while q<>null do | |
> begin if not is_char_node(q) then | |
> if type(q)=unset_node then | |
> @<Set the unset box |q| and the unset boxes in it@> | |
> else if type(q)=rule_node then | |
> @<Make the running dimensions in rule |q| extend to the | |
> boundaries of the alignment@>; | |
> s:=q; q:=link(q); | |
> end | |
> | |
> @ @<Make the running dimensions in rule |q| extend...@>= | |
> begin if is_running(width(q)) then width(q):=width(p); | |
> if is_running(height(q)) then height(q):=height(p); | |
> if is_running(depth(q)) then depth(q):=depth(p); | |
> if o<>0 then | |
> begin r:=link(q); link(q):=null; q:=hpack(q,natural); | |
> shift_amount(q):=o; link(q):=r; link(s):=q; | |
> end; | |
> end | |
> | |
> @ The unset box |q| represents a row that contains one or more unset boxes, | |
> depending on how soon \.{\\cr} occurred in that row. | |
12863c15775 | |
< @ @<Set the unset box |q| and the unset boxes in it@>= | |
--- | |
> @<Set the unset box |q| and the unset boxes in it@>= | |
12865,12871c15777,15783 | |
< begin type(q)←hlist_node; width(q)←width(p); | |
< end | |
< else begin type(q)←vlist_node; height(q)←height(p); | |
< end; | |
< glue_order(q)←glue_order(p); glue_sign(q)←glue_sign(p); | |
< glue_set(q)←glue_set(p); shift_amount(q)←0;@/ | |
< r←link(list_ptr(q)); s←link(list_ptr(p)); | |
--- | |
> begin type(q):=hlist_node; width(q):=width(p); | |
> end | |
> else begin type(q):=vlist_node; height(q):=height(p); | |
> end; | |
> glue_order(q):=glue_order(p); glue_sign(q):=glue_sign(p); | |
> glue_set(q):=glue_set(p); shift_amount(q):=o; | |
> r:=link(list_ptr(q)); s:=link(list_ptr(p)); | |
12873c15785 | |
< r←link(link(r)); s←link(link(s)); | |
--- | |
> r:=link(link(r)); s:=link(link(s)); | |
12877,12878c15789,15795 | |
< @ @<Set the glue in node |r|...@>= | |
< n←span_count(r); t←width(s); | |
--- | |
> @ A box made from spanned columns will be followed by tabskip glue nodes and | |
> by empty boxes as if there were no spanning. This permits perfect alignment | |
> of subsequent entries, and it prevents values that depend on floating point | |
> arithmetic from entering into the dimensions of any boxes. | |
> | |
> @<Set the glue in node |r|...@>= | |
> n:=span_count(r); t:=width(s); w:=t; u:=hold_head; | |
12880,12882c15797,15800 | |
< begin decr(n); s←link(s); t←t+width(s); | |
< s←link(s); t←t+width(s); | |
< end; | |
--- | |
> begin decr(n); | |
> @<Append tabskip glue and an empty box to list |u|, | |
> and update |s| and |t| as the prototype nodes are passed@>; | |
> end; | |
12884,12886c15802,15826 | |
< @<Make the unset node |r| into an |hlist_node| of width |t|@> | |
< else @<Make the unset node |r| into a |vlist_node| of height |t|@>; | |
< shift_amount(r)←0; | |
--- | |
> @<Make the unset node |r| into an |hlist_node| of width |w|, | |
> setting the glue as if the width were |t|@> | |
> else @<Make the unset node |r| into a |vlist_node| of height |w|, | |
> setting the glue as if the height were |t|@>; | |
> shift_amount(r):=0; | |
> if u<>hold_head then {append blank boxes to account for spanned nodes} | |
> begin link(u):=link(r); link(r):=link(hold_head); r:=u; | |
> end | |
> | |
> @ @<Append tabskip glue and an empty box to list |u|...@>= | |
> s:=link(s); v:=glue_ptr(s); link(u):=new_glue(v); u:=link(u); | |
> subtype(u):=tab_skip_code+1; t:=t+width(v); | |
> if glue_sign(p)=stretching then | |
> begin if stretch_order(v)=glue_order(p) then | |
> t:=t+round(float(glue_set(p))*stretch(v)); | |
> @^real multiplication@> | |
> end | |
> else if glue_sign(p)=shrinking then | |
> begin if shrink_order(v)=glue_order(p) then | |
> t:=t-round(float(glue_set(p))*shrink(v)); | |
> end; | |
> s:=link(s); link(u):=new_null_box; u:=link(u); t:=t+width(s); | |
> if mode=-vmode then width(u):=width(s)@+else | |
> begin type(u):=vlist_node; height(u):=width(s); | |
> end | |
12888,12889c15828,15829 | |
< @ @<Make the unset node |r| into an |hlist_node| of width |t|@>= | |
< begin height(r)←height(q); depth(r)←depth(q); | |
--- | |
> @ @<Make the unset node |r| into an |hlist_node| of width |w|...@>= | |
> begin height(r):=height(q); depth(r):=depth(q); | |
12891,12893c15831,15833 | |
< begin glue_sign(r)←normal; glue_order(r)←normal; | |
< glue_set(r)←0.0; | |
< end | |
--- | |
> begin glue_sign(r):=normal; glue_order(r):=normal; | |
> set_glue_ratio_zero(glue_set(r)); | |
> end | |
12895,12903c15835,15846 | |
< begin glue_sign(r)←stretching; | |
< if glue_stretch(r)=0 then glue_set(r)←0.0 | |
< else glue_set(r)←(t-width(r))/glue_stretch(r); | |
< end | |
< else begin glue_order(r)←glue_sign(r); glue_sign(r)←shrinking; | |
< if glue_shrink(r)=0 then glue_set(r)←0.0 | |
< else glue_set(r)←(width(r)-t)/glue_shrink(r); | |
< end; | |
< width(r)←t; type(r)←hlist_node; | |
--- | |
> begin glue_sign(r):=stretching; | |
> if glue_stretch(r)=0 then set_glue_ratio_zero(glue_set(r)) | |
> else glue_set(r):=unfloat((t-width(r))/glue_stretch(r)); | |
> @^real division@> | |
> end | |
> else begin glue_order(r):=glue_sign(r); glue_sign(r):=shrinking; | |
> if glue_shrink(r)=0 then set_glue_ratio_zero(glue_set(r)) | |
> else if (glue_order(r)=normal)and(width(r)-t>glue_shrink(r)) then | |
> set_glue_ratio_one(glue_set(r)) | |
> else glue_set(r):=unfloat((width(r)-t)/glue_shrink(r)); | |
> end; | |
> width(r):=w; type(r):=hlist_node; | |
12906,12907c15849,15850 | |
< @ @<Make the unset node |r| into a |vlist_node| of height |t|@>= | |
< begin width(r)←width(q); | |
--- | |
> @ @<Make the unset node |r| into a |vlist_node| of height |w|...@>= | |
> begin width(r):=width(q); | |
12909,12911c15852,15854 | |
< begin glue_sign(r)←normal; glue_order(r)←normal; | |
< glue_set(r)←0.0; | |
< end | |
--- | |
> begin glue_sign(r):=normal; glue_order(r):=normal; | |
> set_glue_ratio_zero(glue_set(r)); | |
> end | |
12913,12921c15856,15867 | |
< begin glue_sign(r)←stretching; | |
< if glue_stretch(r)=0 then glue_set(r)←0.0 | |
< else glue_set(r)←(t-height(r))/glue_stretch(r); | |
< end | |
< else begin glue_order(r)←glue_sign(r); glue_sign(r)←shrinking; | |
< if glue_shrink(r)=0 then glue_set(r)←0.0 | |
< else glue_set(r)←(height(r)-t)/glue_shrink(r); | |
< end; | |
< height(r)←t; type(r)←vlist_node; | |
--- | |
> begin glue_sign(r):=stretching; | |
> if glue_stretch(r)=0 then set_glue_ratio_zero(glue_set(r)) | |
> else glue_set(r):=unfloat((t-height(r))/glue_stretch(r)); | |
> @^real division@> | |
> end | |
> else begin glue_order(r):=glue_sign(r); glue_sign(r):=shrinking; | |
> if glue_shrink(r)=0 then set_glue_ratio_zero(glue_set(r)) | |
> else if (glue_order(r)=normal)and(height(r)-t>glue_shrink(r)) then | |
> set_glue_ratio_one(glue_set(r)) | |
> else glue_set(r):=unfloat((height(r)-t)/glue_shrink(r)); | |
> end; | |
> height(r):=w; type(r):=vlist_node; | |
12927c15873,15878 | |
< another routine will take care of inserting glue before and after the display.) | |
--- | |
> we will need to insert glue before and after the display; that part of the | |
> program will be deferred until we're more familiar with such operations.) | |
> | |
> In restricted horizontal mode, the |clang| part of |aux| is undefined; | |
> an over-cautious \PASCAL\ runtime system may complain about this. | |
> @^dirty \PASCAL@> | |
12930c15881 | |
< t←aux; p←link(head); q←tail; pop_nest; | |
--- | |
> aux_save:=aux; p:=link(head); q:=tail; pop_nest; | |
12932,12936c15883,15888 | |
< else begin aux←t; link(tail)←p; | |
< if q≠null then tail←q; | |
< if mode=vmode then build_page; | |
< end | |
< @* \[37] Breaking paragraphs into lines. | |
--- | |
> else begin aux:=aux_save; link(tail):=p; | |
> if p<>null then tail:=q; | |
> if mode=vmode then build_page; | |
> end | |
> | |
> @* \[38] Breaking paragraphs into lines. | |
12957c15909 | |
< new ideas to the algorithm of 1980: memory space requirements are considerably | |
--- | |
> new ideas to the algorithm of 1980: Memory space requirements are considerably | |
12970c15922 | |
< starts at |link(head)|, and it is nonempty. The value of |already| in the | |
--- | |
> starts at |link(head)|, and it is nonempty. The value of |prev_graf| in the | |
12973c15925 | |
< are in use; |already| is zero unless this paragraph is being continued | |
--- | |
> is in use; |prev_graf| is zero unless this paragraph is being continued | |
12979c15931 | |
< value of |already|. Furthermore, the global variable |just_box| will | |
--- | |
> value of |prev_graf|. Furthermore, the global variable |just_box| will | |
12982c15934 | |
< |disp_skip| or |disp_a_skip| before a displayed formula. | |
--- | |
> |above_display_skip| or |above_display_short_skip| before a displayed formula. | |
12993,12996c15945,15948 | |
< procedure line_break(@!final_widow_penalty:integer); | |
< label done,done1,done2,done3,done4; | |
< var@?@<Local variables for line breaking@>@; | |
< begin par_begin_line←mode_line; {this is for over/underfull box messages} | |
--- | |
> procedure line_break(@!final_widow_penalty:integer); | |
> label done,done1,done2,done3,done4,done5,continue; | |
> var @<Local variables for line breaking@>@; | |
> begin pack_begin_line:=mode_line; {this is for over/underfull box messages} | |
13002c15954 | |
< par_begin_line←0; | |
--- | |
> pack_begin_line:=0; | |
13013c15965,15966 | |
< same number of words in |mem|. | |
--- | |
> same number of |mem|~words. | |
> @^data structure assumptions@> | |
13015,13016c15968,15969 | |
< @<Get ready...@>= | |
< link(temp_head)←link(head); | |
--- | |
> @<Get ready to start...@>= | |
> link(temp_head):=link(head); | |
13018,13023c15971,15978 | |
< else if (type(tail)≠glue_node)∨(subtype(tail)≥a_leaders) then | |
< tail_append(new_penalty(inf_penalty)) | |
< else begin type(tail)←penalty_node; delete_glue_ref(glue_ptr(tail)); | |
< penalty(tail)←inf_penalty; | |
< end; | |
< link(tail)←new_param_glue(par_fill_skip_code); | |
--- | |
> else if type(tail)<>glue_node then tail_append(new_penalty(inf_penalty)) | |
> else begin type(tail):=penalty_node; delete_glue_ref(glue_ptr(tail)); | |
> flush_node_list(leader_ptr(tail)); penalty(tail):=inf_penalty; | |
> end; | |
> link(tail):=new_param_glue(par_fill_skip_code); | |
> init_cur_lang:=prev_graf mod @'200000; | |
> init_l_hyf:=prev_graf div @'20000000; | |
> init_r_hyf:=(prev_graf div @'200000) mod @'100; | |
13035,13041c15990,15996 | |
< @d tight_fit=0 {fitness classification for lines shrinking 0.5 to 1.0 of their | |
< shrinkability} | |
< @d loose_fit=2 {fitness classification for lines stretching 0.5 to 1.0 of their | |
< stretchability} | |
< @d very_loose_fit=3 {fitness classification for lines stretching more than | |
< their stretchability} | |
< @d decent_fit=1 {fitness classification for all other lines} | |
--- | |
> @d tight_fit=3 {fitness classification for lines shrinking 0.5 to 1.0 of their | |
> shrinkability} | |
> @d loose_fit=1 {fitness classification for lines stretching 0.5 to 1.0 of their | |
> stretchability} | |
> @d very_loose_fit=0 {fitness classification for lines stretching more than | |
> their stretchability} | |
> @d decent_fit=2 {fitness classification for all other lines} | |
13073c16028 | |
< \yskip\hang|type| is either |hyphenated| or |unhyphenated|, de\-pending on | |
--- | |
> \yskip\hang|type| is either |hyphenated| or |unhyphenated|, depending on | |
13086c16041 | |
< @d fitness==subtype {|tight_fit..very_loose_fit| on final line for this break} | |
--- | |
> @d fitness==subtype {|very_loose_fit..tight_fit| on final line for this break} | |
13095,13096c16050,16051 | |
< type(last_active)←hyphenated; line_number(last_active)←max_halfword; | |
< subtype(last_active)←0; {the |subtype| is never examined by the algorithm} | |
--- | |
> type(last_active):=hyphenated; line_number(last_active):=max_halfword; | |
> subtype(last_active):=0; {the |subtype| is never examined by the algorithm} | |
13098c16053 | |
< @ The passive node for a given breakpoint contains only three fields: | |
--- | |
> @ The passive node for a given breakpoint contains only four fields: | |
13108a16064,16067 | |
> \yskip\hang|serial| is equal to |n| if this passive node is the |n|th | |
> one created during the current pass. (This field is used only when | |
> printing out detailed statistics about the line-breaking calculations.) | |
> | |
13111c16070,16072 | |
< recently created passive node. | |
--- | |
> recently created passive node. Another global variable, |printed_node|, | |
> is used to help print out the paragraph when detailed information about | |
> the line-breaking computation is being displayed. | |
13114,13115c16075,16077 | |
< @d cur_break==mark_ptr {in passive node, points to position of this breakpoint} | |
< @d prev_break==info {points to passive node that should precede this one} | |
--- | |
> @d cur_break==rlink {in passive node, points to position of this breakpoint} | |
> @d prev_break==llink {points to passive node that should precede this one} | |
> @d serial==info {serial number for symbolic identification} | |
13118a16081,16082 | |
> @!printed_node:pointer; {most recent node that has been printed} | |
> @!pass_number:halfword; {the number of passive nodes allocated on this pass} | |
13122c16086 | |
< active nodes, and they have |type=delta|. If |p| and |r| are active nodes | |
--- | |
> active nodes, and they have |type=delta_node|. If |p| and |r| are active nodes | |
13128c16092 | |
< starts after |r| is obtained by adding the amounts in node@@|q|. A delta node | |
--- | |
> starts after |r| is obtained by adding the amounts in node~|q|. A delta node | |
13146,13149c16110,16114 | |
< When we pass a delta node we want to do operations like `\!|for k←1 to 6 do | |
< cur_active_width[k]←cur_active_width[k]+mem[q+k].sc|', and we want to | |
< do this without the overhead of |for| loops. The |do_all_six| macro | |
< makes such six-tuples convenient. | |
--- | |
> When we pass a delta node we want to do operations like | |
> $$\hbox{\ignorespaces|for | |
> k:=1 to 6 do cur_active_width[k]:=cur_active_width[k]+mem[q+k].sc|};$$ and we | |
> want to do this without the overhead of |for| loops. The |do_all_six| | |
> macro makes such six-tuples convenient. | |
13153c16118 | |
< @<Glo...@>= | |
--- | |
> @<Glob...@>= | |
13155c16120 | |
< {distance from first active node to@@|cur_p|} | |
--- | |
> {distance from first active node to~|cur_p|} | |
13162,13164c16127,16129 | |
< breakpoint@@$p$ in the paragraph, we define two quantities $\alpha(p)$ and | |
< $\beta(p)$ such that the length of material in a line from breakpoint@@$p$ | |
< to breakpoint@@$q$ is $\gamma+\beta(q)-\alpha(p)$, for some fixed $\gamma$. | |
--- | |
> breakpoint~|p| in the paragraph, we define two quantities $\alpha(p)$ and | |
> $\beta(p)$ such that the length of material in a line from breakpoint~|p| | |
> to breakpoint~|q| is $\gamma+\beta(q)-\alpha(p)$, for some fixed $\gamma$. | |
13166,13167c16131,16132 | |
< the beginning of the paragraph to a point ``after'' a break at $p$ and to a | |
< point ``before'' a break at $q$; and $\gamma$ is the width of an empty line, | |
--- | |
> the beginning of the paragraph to a point ``after'' a break at |p| and to a | |
> point ``before'' a break at |q|; and $\gamma$ is the width of an empty line, | |
13171,13177c16136,16142 | |
< boxes and glue skips; let the boxes have widths $x↓1\ldotsm x↓n$ and | |
< let the skips have widths $y↓1\ldotsm y↓n$, so that the paragraph can be | |
< represented by $x↓1y↓1\ldotsm x↓ny↓n$. Let $p↓i$ be the legal breakpoint | |
< at $y↓i$; then $\alpha(p↓i)=x↓1+y↓1+\cdots+x↓i+y↓i$, and $\beta(p↓i)= | |
< x↓1+y↓1+\cdots+x↓i$. To check this, note that the length of material from | |
< $p↓2$ to $p↓5$, say, is $\gamma+x↓3+y↓3+x↓4+y↓4+x↓5=\gamma+\beta(p↓5) | |
< -\alpha(p↓2)$. | |
--- | |
> boxes and glue skips; let the boxes have widths $x_1\ldots x_n$ and | |
> let the skips have widths $y_1\ldots y_n$, so that the paragraph can be | |
> represented by $x_1y_1\ldots x_ny_n$. Let $p_i$ be the legal breakpoint | |
> at $y_i$; then $\alpha(p_i)=x_1+y_1+\cdots+x_i+y_i$, and $\beta(p_i)= | |
> x_1+y_1+\cdots+x_i$. To check this, note that the length of material from | |
> $p_2$ to $p_5$, say, is $\gamma+x_3+y_3+x_4+y_4+x_5=\gamma+\beta(p_5) | |
> -\alpha(p_2)$. | |
13181c16146 | |
< and $\beta(p)$ for each $p$, we would need multiple precision arithmetic, and | |
--- | |
> and $\beta(p)$ for each |p|, we would need multiple precision arithmetic, and | |
13185,13189c16150,16154 | |
< $a↓1\,\delta↓1\,a↓2\,\delta↓2\,a↓3$, where the $a$'s are active breakpoints | |
< and the $\delta$'s are delta nodes. Then $\delta↓1=\alpha(a↓1)-\alpha(a↓2)$ | |
< and $\delta↓2=\alpha(a↓2)-\alpha(a↓3)$. If the line breaking algorithm is | |
< currently positioned at some other breakpoint $p$, the |active_width| array | |
< contains the value $\gamma+\beta(p)-\alpha(a↓1)$. If we are scanning through | |
--- | |
> $a_1\,\delta_1\,a_2\,\delta_2\,a_3$, where the |a|'s are active breakpoints | |
> and the $\delta$'s are delta nodes. Then $\delta_1=\alpha(a_1)-\alpha(a_2)$ | |
> and $\delta_2=\alpha(a_2)-\alpha(a_3)$. If the line breaking algorithm is | |
> currently positioned at some other breakpoint |p|, the |active_width| array | |
> contains the value $\gamma+\beta(p)-\alpha(a_1)$. If we are scanning through | |
13191,13195c16156,16160 | |
< $a↓2$ to@@$p$, say, the |cur_active_width| array will contain the value | |
< $\gamma+\beta(p)-\alpha(a↓2)$. Thus, when we move from $a↓2$ to $a↓3$, | |
< we want to add $\alpha(a↓2)-\alpha(a↓3)$ to |cur_active_width|; and this | |
< is just $\delta↓2$, which appears in the active list between $a↓2$ and | |
< $a↓3$. The |background| array contains $\gamma$. The |break_width| array | |
--- | |
> $a_2$ to~|p|, say, the |cur_active_width| array will contain the value | |
> $\gamma+\beta(p)-\alpha(a_2)$. Thus, when we move from $a_2$ to $a_3$, | |
> we want to add $\alpha(a_2)-\alpha(a_3)$ to |cur_active_width|; and this | |
> is just $\delta_2$, which appears in the active list between $a_2$ and | |
> $a_3$. The |background| array contains $\gamma$. The |break_width| array | |
13206,13208c16171,16173 | |
< @d check_shrinkage(#)==if (shrink_order(#)≠normal)∧(shrink(#)≠0) then | |
< begin #←finite_shrink(#); | |
< end | |
--- | |
> @d check_shrinkage(#)==if (shrink_order(#)<>normal)and(shrink(#)<>0) then | |
> begin #:=finite_shrink(#); | |
> end | |
13217,13223c16182,16183 | |
< begin no_shrink_error_yet←false; | |
< help5("The paragraph just ended includes some glue that has")@/ | |
< ("infinite shrinkability, e.g., `\hskip 0pt minus 1fil'.")@/ | |
< ("Such glue doesn't belong there---it allows a paragraph")@/ | |
< ("of any length to fit on one line. But it's safe to proceed,")@/ | |
< ("since the offensive shrinkability has been made finite."); | |
< print_nl("! Infinite glue shrinkage found in a paragraph"); error; | |
--- | |
> begin no_shrink_error_yet:=false; | |
> print_err("Infinite glue shrinkage found in a paragraph"); | |
13225,13227c16185,16193 | |
< end; | |
< q←new_spec(p); shrink_order(q)←normal; | |
< delete_glue_ref(p); finite_shrink←q; | |
--- | |
> help5("The paragraph just ended includes some glue that has")@/ | |
> ("infinite shrinkability, e.g., `\hskip 0pt minus 1fil'.")@/ | |
> ("Such glue doesn't belong there---it allows a paragraph")@/ | |
> ("of any length to fit on one line. But it's safe to proceed,")@/ | |
> ("since the offensive shrinkability has been made finite."); | |
> error; | |
> end; | |
> q:=new_spec(p); shrink_order(q):=normal; | |
> delete_glue_ref(p); finite_shrink:=q; | |
13230,13231c16196,16197 | |
< @ @<Get ready...@>= | |
< no_shrink_error_yet←true;@/ | |
--- | |
> @ @<Get ready to start...@>= | |
> no_shrink_error_yet:=true;@/ | |
13233,13237c16199,16203 | |
< q←left_skip; r←right_skip; background[1]←width(q)+width(r);@/ | |
< background[2]←0; background[3]←0; background[4]←0; background[5]←0;@/ | |
< background[2+stretch_order(q)]←stretch(q);@/ | |
< background[2+stretch_order(r)]←@|background[2+stretch_order(r)]+stretch(r);@/ | |
< background[6]←shrink(q)+shrink(r); | |
--- | |
> q:=left_skip; r:=right_skip; background[1]:=width(q)+width(r);@/ | |
> background[2]:=0; background[3]:=0; background[4]:=0; background[5]:=0;@/ | |
> background[2+stretch_order(q)]:=stretch(q);@/ | |
> background[2+stretch_order(r)]:=@|background[2+stretch_order(r)]+stretch(r);@/ | |
> background[6]:=shrink(q)+shrink(r); | |
13244c16210 | |
< of individual lines: breakpoints are feasible if there is a way to reach | |
--- | |
> of individual lines: Breakpoints are feasible if there is a way to reach | |
13250c16216 | |
< |badness| function specified above never returns a value greater than@@10000. | |
--- | |
> |badness| function specified above never returns a value greater than~10000. | |
13252c16218 | |
< Two passes might be made through the paragraph in an attempt to find at | |
--- | |
> Up to three passes might be made through the paragraph in an attempt to find at | |
13254c16220,16221 | |
< |threshold=pretolerance| and |second_pass=false|. If this pass fails to find a | |
--- | |
> |threshold=pretolerance| and |second_pass=final_pass=false|. | |
> If this pass fails to find a | |
13256a16224,16225 | |
> If that fails too, we add |emergency_stretch| to the background | |
> stretchability and set |final_pass=true|. | |
13260a16230 | |
> @!final_pass:boolean; {is this our final attempt to break this paragraph?} | |
13266c16236 | |
< nodes to@@|cur_p|. If feasible breaks are possible, new break nodes are | |
--- | |
> nodes to~|cur_p|. If feasible breaks are possible, new break nodes are | |
13275,13276c16245,16246 | |
< de\-pending on whether or not the current break is at a |disc_node|. The | |
< end of a para\-graph is also regarded as `|hyphenated|'; this case is | |
--- | |
> depending on whether or not the current break is at a |disc_node|. The | |
> end of a paragraph is also regarded as `|hyphenated|'; this case is | |
13279c16249 | |
< @d copy_to_cur_active(#)==cur_active_width[#]←active_width[#] | |
--- | |
> @d copy_to_cur_active(#)==cur_active_width[#]:=active_width[#] | |
13284c16254 | |
< label exit,done,continue,deactivate; | |
--- | |
> label exit,done,done1,continue,deactivate; | |
13291c16261 | |
< no_break_yet←true; prev_r←active; old_l←0; | |
--- | |
> no_break_yet:=true; prev_r:=active; old_l:=0; | |
13293,13304c16263,16276 | |
< loop@+ begin continue: r←link(prev_r); | |
< @<If node |r| is of type |delta_node|, update |cur_active_width|, | |
< set |prev_r| and |prev_prev_r|, then |goto continue|@>; | |
< @<If a line number class has ended, create new active nodes for | |
< the best feasible breaks in that class; then |return| | |
< if |r=last_active|, otherwise compute the new |line_width|@>; | |
< @<Consider the demerits for a line from |r| to |cur_p|; | |
< deactivate node |r| if it should no longer be active; | |
< then |goto continue| if a line from |r| to |cur_p| is infeasible, | |
< otherwise record a new feasible break@>; | |
< end; | |
< exit:end; | |
--- | |
> loop@+ begin continue: r:=link(prev_r); | |
> @<If node |r| is of type |delta_node|, update |cur_active_width|, | |
> set |prev_r| and |prev_prev_r|, then |goto continue|@>; | |
> @<If a line number class has ended, create new active nodes for | |
> the best feasible breaks in that class; then |return| | |
> if |r=last_active|, otherwise compute the new |line_width|@>; | |
> @<Consider the demerits for a line from |r| to |cur_p|; | |
> deactivate node |r| if it should no longer be active; | |
> then |goto continue| if a line from |r| to |cur_p| is infeasible, | |
> otherwise record a new feasible break@>; | |
> end; | |
> exit: @!stat @<Update the value of |printed_node| for | |
> symbolic displays@>@+tats@; | |
> end; | |
13310,13311c16282,16283 | |
< @!v:pointer; {points to a glue specification} | |
< @!t:quarterword; {replacement count, if |cur_p| is a discretionary node} | |
--- | |
> @!v:pointer; {points to a glue specification or a node ahead of |cur_p|} | |
> @!t:integer; {node count, if |cur_p| is a discretionary node} | |
13316c16288 | |
< @!fit_class:tight_fit..very_loose_fit; {possible fitness class of test line} | |
--- | |
> @!fit_class:very_loose_fit..tight_fit; {possible fitness class of test line} | |
13318a16291,16293 | |
> @!artificial_demerits:boolean; {has |d| been forced to zero?} | |
> @!save_link:pointer; {temporarily holds value of |link(cur_p)|} | |
> @!shortfall:scaled; {used in badness calculations} | |
13321,13323c16296,16298 | |
< if abs(pi)≥inf_penalty then | |
< if pi>0 then return {this breakpoint is inhibited by infinite penalty} | |
< else pi←eject_penalty {this breakpoint will be forced} | |
--- | |
> if abs(pi)>=inf_penalty then | |
> if pi>0 then return {this breakpoint is inhibited by infinite penalty} | |
> else pi:=eject_penalty {this breakpoint will be forced} | |
13325c16300 | |
< @ The following code uses the fact that |type(last_active)≠delta_node|. | |
--- | |
> @ The following code uses the fact that |type(last_active)<>delta_node|. | |
13328c16303 | |
< cur_active_width[#]←cur_active_width[#]+mem[r+#].sc | |
--- | |
> cur_active_width[#]:=cur_active_width[#]+mem[r+#].sc | |
13330a16306 | |
> @^inner loop@> | |
13332,13334c16308,16310 | |
< begin do_all_six(update_width); | |
< prev_prev_r←prev_r; prev_r←r; goto continue; | |
< end | |
--- | |
> begin do_all_six(update_width); | |
> prev_prev_r:=prev_r; prev_r:=r; goto continue; | |
> end | |
13341c16317 | |
< points to the passive node for the break before@@|cur_p| that achieves such | |
--- | |
> points to the passive node for the break before~|cur_p| that achieves such | |
13351,13365c16327,16341 | |
< @!minimal_demerits:array[tight_fit..very_loose_fit] of scaled; {best total | |
< demerits known for current line class and position, given the fitness} | |
< @!minimum_demerits:scaled; {best total demerits known for current line class | |
< and position} | |
< @!best_place:array[tight_fit..very_loose_fit] of pointer; {how to achieve | |
< |minimal_demerits|} | |
< @!best_pl_line:array[tight_fit..very_loose_fit] of halfword; {corresponding | |
< line number} | |
< | |
< @ @<Get ready...@>= | |
< minimum_demerits←awful_bad; | |
< minimal_demerits[tight_fit]←awful_bad; | |
< minimal_demerits[decent_fit]←awful_bad; | |
< minimal_demerits[loose_fit]←awful_bad; | |
< minimal_demerits[very_loose_fit]←awful_bad; | |
--- | |
> @!minimal_demerits:array[very_loose_fit..tight_fit] of integer; {best total | |
> demerits known for current line class and position, given the fitness} | |
> @!minimum_demerits:integer; {best total demerits known for current line class | |
> and position} | |
> @!best_place:array[very_loose_fit..tight_fit] of pointer; {how to achieve | |
> |minimal_demerits|} | |
> @!best_pl_line:array[very_loose_fit..tight_fit] of halfword; {corresponding | |
> line number} | |
> | |
> @ @<Get ready to start...@>= | |
> minimum_demerits:=awful_bad; | |
> minimal_demerits[tight_fit]:=awful_bad; | |
> minimal_demerits[decent_fit]:=awful_bad; | |
> minimal_demerits[loose_fit]:=awful_bad; | |
> minimal_demerits[very_loose_fit]:=awful_bad; | |
13375c16351 | |
< begin l←line_number(r); | |
--- | |
> begin l:=line_number(r); | |
13377,13384c16353,16360 | |
< begin {now we are no longer in the inner loop} | |
< if (minimum_demerits<awful_bad)∧@| | |
< ((old_l≠easy_line)∨(r=last_active)) then | |
< @<Create new active nodes for the best feasible breaks | |
< just found@>; | |
< if r=last_active then return; | |
< @<Compute the new line width@>; | |
< end; | |
--- | |
> begin {now we are no longer in the inner loop} | |
> if (minimum_demerits<awful_bad)and@| | |
> ((old_l<>easy_line)or(r=last_active)) then | |
> @<Create new active nodes for the best feasible breaks | |
> just found@>; | |
> if r=last_active then return; | |
> @<Compute the new line width@>; | |
> end; | |
13387,13388c16363,16365 | |
< @ It is not necessary to create new active nodes having |minimal_demerits | |
< >minimum_demerits+abs(adj_demerits)|, since such active nodes will never | |
--- | |
> @ It is not necessary to create new active nodes having |minimal_demerits| | |
> greater than | |
> |minimum_demerits+abs(adj_demerits)|, since such active nodes will never | |
13395,13402c16372,16381 | |
< minimum_demerits←minimum_demerits+abs(adj_demerits); | |
< for fit_class←tight_fit to very_loose_fit do | |
< begin if minimal_demerits[fit_class]≤minimum_demerits then | |
< @<Insert a new active node | |
< from |best_place[fit_class]| to |cur_p|@>; | |
< minimal_demerits[fit_class]←awful_bad; | |
< end; | |
< minimum_demerits←awful_bad; | |
--- | |
> if abs(adj_demerits)>=awful_bad-minimum_demerits then | |
> minimum_demerits:=awful_bad-1 | |
> else minimum_demerits:=minimum_demerits+abs(adj_demerits); | |
> for fit_class:=very_loose_fit to tight_fit do | |
> begin if minimal_demerits[fit_class]<=minimum_demerits then | |
> @<Insert a new active node | |
> from |best_place[fit_class]| to |cur_p|@>; | |
> minimal_demerits[fit_class]:=awful_bad; | |
> end; | |
> minimum_demerits:=awful_bad; | |
13408c16387 | |
< want to insert `$\delta\,|cur_p|\,\delta^\prime$' before $a$, where | |
--- | |
> want to insert `$\delta\,|cur_p|\,\delta^\prime$' before |a|, where | |
13410c16389 | |
< in the notation explained above. The |cur_active_width| array now hold | |
--- | |
> in the notation explained above. The |cur_active_width| array now holds | |
13417c16396 | |
< (which is normally zero) minus the width of nodes following@@|cur_p| that are | |
--- | |
> (which is normally zero) minus the width of nodes following~|cur_p| that are | |
13423c16402,16404 | |
< @d set_break_width_to_background(#)==break_width[#]←background[#] | |
--- | |
> Kern nodes do not disappear at a line break unless they are |explicit|. | |
> | |
> @d set_break_width_to_background(#)==break_width[#]:=background[#] | |
13426,13440c16407,16422 | |
< begin no_break_yet←false; do_all_six(set_break_width_to_background); | |
< if (break_type=unhyphenated)∨(cur_p=null) then | |
< begin s←cur_p; | |
< while s≠null do | |
< begin if is_char_node(s) then goto done; | |
< case type(s) of | |
< glue_node:@<Subtract glue from |break_width|@>; | |
< penalty_node: do_nothing; | |
< math_node,kern_node: break_width[1]←break_width[1]-width(s); | |
< othercases goto done | |
< endcases;@/ | |
< s←link(s); | |
< end; | |
< end | |
< else @<Compute the discretionary |break_width| values@>; | |
--- | |
> begin no_break_yet:=false; do_all_six(set_break_width_to_background); | |
> s:=cur_p; | |
> if break_type>unhyphenated then if cur_p<>null then | |
> @<Compute the discretionary |break_width| values@>; | |
> while s<>null do | |
> begin if is_char_node(s) then goto done; | |
> case type(s) of | |
> glue_node:@<Subtract glue from |break_width|@>; | |
> penalty_node: do_nothing; | |
> math_node: break_width[1]:=break_width[1]-width(s); | |
> kern_node: if subtype(s)<>explicit then goto done | |
> else break_width[1]:=break_width[1]-width(s); | |
> othercases goto done | |
> endcases;@/ | |
> s:=link(s); | |
> end; | |
13444,13446c16426,16428 | |
< begin v←glue_ptr(s); break_width[1]←break_width[1]-width(v); | |
< break_width[2+stretch_order(v)]←break_width[2+stretch_order(v)]-stretch(v); | |
< break_width[6]←break_width[6]-shrink(v); | |
--- | |
> begin v:=glue_ptr(s); break_width[1]:=break_width[1]-width(v); | |
> break_width[2+stretch_order(v)]:=break_width[2+stretch_order(v)]-stretch(v); | |
> break_width[6]:=break_width[6]-shrink(v); | |
13451,13452c16433,16434 | |
< Suppose that the pre-break text at |cur_p| has length $l↓0$, the post-break | |
< text has length $l↓1$, and the replacement text has length $l$. Suppose | |
--- | |
> Suppose that the pre-break text at |cur_p| has length $l_0$, the post-break | |
> text has length $l_1$, and the replacement text has length |l|. Suppose | |
13455,13456c16437,16441 | |
< where $\beta(q)=\beta(|cur_p|)-l↓0+l$. The actual length will be the background | |
< plus $l↓1$, so the length from |cur_p| to |cur_p| should be $\gamma+l↓0+l↓1-l$. | |
--- | |
> where $\beta(q)=\beta(|cur_p|)-l_0+l$. The actual length will be the background | |
> plus $l_1$, so the length from |cur_p| to |cur_p| should be $\gamma+l_0+l_1-l$. | |
> If the post-break text of the discretionary is empty, a break may also | |
> discard~|q|; in that unusual case we subtract the length of~|q| and any | |
> other nodes that will be discarded after the discretionary break. | |
13458c16443 | |
< The value of $l↓0$ need not be computed, since |line_break| will put | |
--- | |
> The value of $l_0$ need not be computed, since |line_break| will put | |
13465c16450 | |
< begin t←replace_count(cur_p); s←cur_p; | |
--- | |
> begin t:=replace_count(cur_p); v:=cur_p; s:=post_break(cur_p); | |
13467,13475c16452,16461 | |
< begin decr(t); s←link(s); | |
< @<Subtract the width of node |s| from |break_width|@>; | |
< end; | |
< s←post_break(cur_p); | |
< while s≠null do | |
< begin @<Add the width of node |s| to |break_width|@>; | |
< s←link(s); | |
< end; | |
< break_width[1]←break_width[1]+disc_width; | |
--- | |
> begin decr(t); v:=link(v); | |
> @<Subtract the width of node |v| from |break_width|@>; | |
> end; | |
> while s<>null do | |
> begin @<Add the width of node |s| to |break_width|@>; | |
> s:=link(s); | |
> end; | |
> break_width[1]:=break_width[1]+disc_width; | |
> if post_break(cur_p)=null then s:=link(v); | |
> {nodes may be discardable after the break} | |
13479c16465 | |
< only character nodes, kern nodes, and ligature nodes. | |
--- | |
> only character nodes, kern nodes, ligature nodes, and box or rule nodes. | |
13481,13494c16467,16481 | |
< @<Subtract the width of node |s|...@>= | |
< if is_char_node(s) then | |
< begin f←font(s); | |
< break_width[1]←break_width[1]-char_width(f)(char_info(f)(character(s))); | |
< end | |
< else case type(s) of | |
< ligature_node: begin f←font(lig_char(s));@/ | |
< break_width[1]←@|break_width[1]- | |
< char_width(f)(char_info(f)(character(lig_char(s)))); | |
< end; | |
< kern_node: break_width[1]←break_width[1]-width(s); | |
< othercases confusion("disc1") | |
< @:confusion disc1}{\quad disc1@> | |
< endcases | |
--- | |
> @<Subtract the width of node |v|...@>= | |
> if is_char_node(v) then | |
> begin f:=font(v); | |
> break_width[1]:=break_width[1]-char_width(f)(char_info(f)(character(v))); | |
> end | |
> else case type(v) of | |
> ligature_node: begin f:=font(lig_char(v));@/ | |
> break_width[1]:=@|break_width[1]- | |
> char_width(f)(char_info(f)(character(lig_char(v)))); | |
> end; | |
> hlist_node,vlist_node,rule_node,kern_node: | |
> break_width[1]:=break_width[1]-width(v); | |
> othercases confusion("disc1") | |
> @:this can't happen disc1}{\quad disc1@> | |
> endcases | |
13498,13509c16485,16497 | |
< begin f←font(s); | |
< break_width[1]←@|break_width[1]+char_width(f)(char_info(f)(character(s))); | |
< end | |
< else case type(s) of | |
< ligature_node: begin f←font(lig_char(s)); | |
< break_width[1]←break_width[1]+ | |
< char_width(f)(char_info(f)(character(lig_char(s)))); | |
< end; | |
< kern_node: break_width[1]←break_width[1]+width(s); | |
< othercases confusion("disc2") | |
< @:confusion disc2}{\quad disc2@> | |
< endcases | |
--- | |
> begin f:=font(s); | |
> break_width[1]:=@|break_width[1]+char_width(f)(char_info(f)(character(s))); | |
> end | |
> else case type(s) of | |
> ligature_node: begin f:=font(lig_char(s)); | |
> break_width[1]:=break_width[1]+ | |
> char_width(f)(char_info(f)(character(lig_char(s)))); | |
> end; | |
> hlist_node,vlist_node,rule_node,kern_node: | |
> break_width[1]:=break_width[1]+width(s); | |
> othercases confusion("disc2") | |
> @:this can't happen disc2}{\quad disc2@> | |
> endcases | |
13511c16499 | |
< @ We use the fact that |type(active)≠delta_node|. | |
--- | |
> @ We use the fact that |type(active)<>delta_node|. | |
13514,13516c16502,16504 | |
< mem[prev_r+#].sc←@|@t\hskip10pt@>mem[prev_r+#].sc | |
< -cur_active_width[#]+break_width[#] | |
< @d store_break_width(#)==active_width[#]←break_width[#] | |
--- | |
> mem[prev_r+#].sc:=@|@t\hskip10pt@>mem[prev_r+#].sc | |
> -cur_active_width[#]+break_width[#] | |
> @d store_break_width(#)==active_width[#]:=break_width[#] | |
13518c16506 | |
< mem[q+#].sc←break_width[#]-cur_active_width[#] | |
--- | |
> mem[q+#].sc:=break_width[#]-cur_active_width[#] | |
13522,13523c16510,16511 | |
< begin εo_all_six(convert_to_break_width); | |
< end | |
--- | |
> begin do_all_six(convert_to_break_width); | |
> end | |
13525,13531c16513,16519 | |
< begin do_all_six(store_break_width); | |
< end | |
< else begin q←get_node(delta_node_size); link(q)←r; type(q)←delta_node; | |
< subtype(q)←0; {the |subtype| is not used} | |
< do_all_six(new_delta_to_break_width); | |
< link(prev_r)←q; prev_prev_r←prev_r; prev_r←q; | |
< end | |
--- | |
> begin do_all_six(store_break_width); | |
> end | |
> else begin q:=get_node(delta_node_size); link(q):=r; type(q):=delta_node;@/ | |
> subtype(q):=0; {the |subtype| is not used} | |
> do_all_six(new_delta_to_break_width); | |
> link(prev_r):=q; prev_prev_r:=prev_r; prev_r:=q; | |
> end | |
13534c16522 | |
< least one active node before |r|, so |type(prev_r)≠delta_node|. | |
--- | |
> least one active node before |r|, so |type(prev_r)<>delta_node|. | |
13536,13537c16524,16525 | |
< @d new_delta_from_break_width(#)==@|mem[q+#].sc← | |
< cur_active_width[#]-break_width[#] | |
--- | |
> @d new_delta_from_break_width(#)==@|mem[q+#].sc:= | |
> cur_active_width[#]-break_width[#] | |
13540,13545c16528,16533 | |
< if r≠last_active then | |
< begin q←get_node(delta_node_size); link(q)←r; type(q)←delta_node; | |
< subtype(q)←0; {the |subtype| is not used} | |
< do_all_six(new_delta_from_break_width); | |
< link(prev_r)←q; prev_prev_r←prev_r; prev_r←q; | |
< end | |
--- | |
> if r<>last_active then | |
> begin q:=get_node(delta_node_size); link(q):=r; type(q):=delta_node;@/ | |
> subtype(q):=0; {the |subtype| is not used} | |
> do_all_six(new_delta_from_break_width); | |
> link(prev_r):=q; prev_prev_r:=prev_r; prev_r:=q; | |
> end | |
13551,13558c16539,16562 | |
< begin q←get_node(passive_node_size); | |
< link(q)←passive; passive←q; cur_break(q)←cur_p; | |
< prev_break(q)←best_place[fit_class];@/ | |
< q←get_node(active_node_size); break_node(q)←passive; | |
< line_number(q)←best_pl_line[fit_class]+1; | |
< fitness(q)←fit_class; type(q)←break_type; | |
< total_demerits(q)←minimal_demerits[fit_class]; | |
< link(q)←r; link(prev_r)←q; prev_r←q; | |
--- | |
> begin q:=get_node(passive_node_size); | |
> link(q):=passive; passive:=q; cur_break(q):=cur_p; | |
> @!stat incr(pass_number); serial(q):=pass_number;@+tats@;@/ | |
> prev_break(q):=best_place[fit_class];@/ | |
> q:=get_node(active_node_size); break_node(q):=passive; | |
> line_number(q):=best_pl_line[fit_class]+1; | |
> fitness(q):=fit_class; type(q):=break_type; | |
> total_demerits(q):=minimal_demerits[fit_class]; | |
> link(q):=r; link(prev_r):=q; prev_r:=q; | |
> @!stat if tracing_paragraphs>0 then | |
> @<Print a symbolic description of the new break node@>; | |
> tats@;@/ | |
> end | |
> | |
> @ @<Print a symbolic description of the new break node@>= | |
> begin print_nl("@@@@"); print_int(serial(passive)); | |
> @.\AT!\AT!@> | |
> print(": line "); print_int(line_number(q)-1); | |
> print_char("."); print_int(fit_class); | |
> if break_type=hyphenated then print_char("-"); | |
> print(" t="); print_int(total_demerits(q)); | |
> print(" -> @@@@"); | |
> if prev_break(passive)=null then print_char("0") | |
> else print_int(serial(prev_break(passive))); | |
13568,13574c16572,16578 | |
< |n=hang_after|; if |n≥0|, hanging indentation takes place on lines |n+1|, | |
< |n+2|, $\ldotss$, otherwise it takes place on lines 1, $\ldotss$, $\leftv | |
< n\rightv$. When hanging indentation is active, the left margin is | |
< |hanging_indent|, if |hanging_indent≥0|, else it is 0; the line length is | |
< $|hsize|-\leftv|hanging_indent|\rightv$. The normal setting is | |
< |par_shape_ptr=null|, |hang_after=0|, and |hanging_indent=0|. | |
< Note that if |hanging_indent=0|, the value of |hang_after| is irrelevant. | |
--- | |
> |n=hang_after|; if |n>=0|, hanging indentation takes place on lines |n+1|, | |
> |n+2|, \dots, otherwise it takes place on lines 1, \dots, $\vert | |
> n\vert$. When hanging indentation is active, the left margin is | |
> |hang_indent|, if |hang_indent>=0|, else it is 0; the line length is | |
> $|hsize|-\vert|hang_indent|\vert$. The normal setting is | |
> |par_shape_ptr=null|, |hang_after=1|, and |hang_indent=0|. | |
> Note that if |hang_indent=0|, the value of |hang_after| is irrelevant. | |
13580,13582c16584,16586 | |
< the same width} | |
< @!first_width:scaled; {the width of all lines |≤last_special_line|, if | |
< no \.{\\parshape} has been specified} | |
--- | |
> the same width} | |
> @!first_width:scaled; {the width of all lines |<=last_special_line|, if | |
> no \.{\\parshape} has been specified} | |
13590c16594 | |
< @<Get ready...@>= | |
--- | |
> @<Get ready to start...@>= | |
13592,13602c16596,16606 | |
< if hanging_indent=0 then | |
< begin last_special_line←0; first_width←hsize; | |
< second_width←first_width; | |
< end | |
< else @<Set line length parameters in preparation for hanging indentation@> | |
< else begin last_special_line←info(par_shape_ptr)-1; | |
< second_width←mem[par_shape_ptr+2*(last_special_line+1)].sc; | |
< second_indent←mem[par_shape_ptr+2*last_special_line+1].sc; | |
< end; | |
< if looseness=0 then easy_line←last_special_line | |
< else easy_line←max_halfword | |
--- | |
> if hang_indent=0 then | |
> begin last_special_line:=0; second_width:=hsize; | |
> second_indent:=0; | |
> end | |
> else @<Set line length parameters in preparation for hanging indentation@> | |
> else begin last_special_line:=info(par_shape_ptr)-1; | |
> second_width:=mem[par_shape_ptr+2*(last_special_line+1)].sc; | |
> second_indent:=mem[par_shape_ptr+2*last_special_line+1].sc; | |
> end; | |
> if looseness=0 then easy_line:=last_special_line | |
> else easy_line:=max_halfword | |
13605c16609 | |
< begin last_special_line←abs(hang_after); | |
--- | |
> begin last_special_line:=abs(hang_after); | |
13607,13616c16611,16620 | |
< begin first_width←hsize-abs(hanging_indent); | |
< if hanging_indent≥0 then first_indent←hanging_indent | |
< else first_indent←0; | |
< second_width←hsize; second_indent←0; | |
< end | |
< else begin first_width←hsize; first_indent←0; | |
< second_width←hsize-abs(hanging_indent); | |
< if hanging_indent≥0 then second_indent←hanging_indent | |
< else second_indent←0; | |
< end; | |
--- | |
> begin first_width:=hsize-abs(hang_indent); | |
> if hang_indent>=0 then first_indent:=hang_indent | |
> else first_indent:=0; | |
> second_width:=hsize; second_indent:=0; | |
> end | |
> else begin first_width:=hsize; first_indent:=0; | |
> second_width:=hsize-abs(hang_indent); | |
> if hang_indent>=0 then second_indent:=hang_indent | |
> else second_indent:=0; | |
> end; | |
13620,13621c16624,16625 | |
< active node@@|r| whose |line_number| field contains |l|. Thus we want to | |
< compute the length of the $l\,$th line of the current paragraph. Furthermore | |
--- | |
> active node~|r| whose |line_number| field contains |l|. Thus we want to | |
> compute the length of the $l\mskip1mu$th line of the current paragraph. Furthermore, | |
13623c16627 | |
< equivalent to@@|l|. | |
--- | |
> equivalent to~|l|. | |
13627,13633c16631,16637 | |
< begin line_width←second_width; old_l←max_halfword-1; | |
< end | |
< else begin old_l←l; | |
< if l>last_special_line then line_width←second_width | |
< else if par_shape_ptr=null then line_width←first_width | |
< else line_width←mem[par_shape_ptr+2*l@,].sc; | |
< end | |
--- | |
> begin line_width:=second_width; old_l:=max_halfword-1; | |
> end | |
> else begin old_l:=l; | |
> if l>last_special_line then line_width:=second_width | |
> else if par_shape_ptr=null then line_width:=first_width | |
> else line_width:=mem[par_shape_ptr+2*l@,].sc; | |
> end | |
13642c16646 | |
< We also deactivate node@@|r| when a break at@@|cur_p| is forced, since future | |
--- | |
> We also deactivate node~|r| when a break at~|cur_p| is forced, since future | |
13646,13648c16650,16655 | |
< begin if cur_active_width[1]<line_width then | |
< @<Set the value of |b| to the badness for stretching the line, | |
< and compute the corresponding |fit_class|@> | |
--- | |
> begin artificial_demerits:=false;@/ | |
> @^inner loop@> | |
> shortfall:=line_width-cur_active_width[1]; {we're this much too short} | |
> if shortfall>0 then | |
> @<Set the value of |b| to the badness for stretching the line, | |
> and compute the corresponding |fit_class|@> | |
13650,13657c16657,16664 | |
< and compute the corresponding |fit_class|@>; | |
< if (b>inf_bad)∨(pi=eject_penalty) then | |
< @<Prepare to deactivate node@@|r|, and |goto deactivate| unless | |
< there is a reason to consider lines of text from |r| to |cur_p|@> | |
< else begin prev_r←r; | |
< if b>threshold then goto continue; | |
< node_r_stays_active←true; | |
< end; | |
--- | |
> and compute the corresponding |fit_class|@>; | |
> if (b>inf_bad)or(pi=eject_penalty) then | |
> @<Prepare to deactivate node~|r|, and |goto deactivate| unless | |
> there is a reason to consider lines of text from |r| to |cur_p|@> | |
> else begin prev_r:=r; | |
> if b>threshold then goto continue; | |
> node_r_stays_active:=true; | |
> end; | |
13663c16670 | |
< @ When a line must stretch, the available stretchability appears in the | |
--- | |
> @ When a line must stretch, the available stretchability can be found in the | |
13665a16673,16678 | |
> The present section is part of \TeX's inner loop, and it is most often performed | |
> when the badness is infinite; therefore it is worth while to make a quick | |
> test for large width excess and small stretchability, before calling the | |
> |badness| subroutine. | |
> @^inner loop@> | |
> | |
13667,13676c16680,16693 | |
< if (cur_active_width[3]≠0)∨(cur_active_width[4]≠0)∨@| | |
< (cur_active_width[5]≠0) then | |
< begin b←0; fit_class←decent_fit; {infinite stretch} | |
< end | |
< else begin b←badness(line_width-cur_active_width[1],cur_active_width[2]); | |
< if b>12 then | |
< if b>99 then fit_class←very_loose_fit | |
< else fit_class←loose_fit | |
< else fit_class←decent_fit; | |
< end | |
--- | |
> if (cur_active_width[3]<>0)or(cur_active_width[4]<>0)or@| | |
> (cur_active_width[5]<>0) then | |
> begin b:=0; fit_class:=decent_fit; {infinite stretch} | |
> end | |
> else begin if shortfall>7230584 then if cur_active_width[2]<1663497 then | |
> begin b:=inf_bad; fit_class:=very_loose_fit; goto done1; | |
> end; | |
> b:=badness(shortfall,cur_active_width[2]); | |
> if b>12 then | |
> if b>99 then fit_class:=very_loose_fit | |
> else fit_class:=loose_fit | |
> else fit_class:=decent_fit; | |
> done1: | |
> end | |
13682,13685c16699,16701 | |
< begin if cur_active_width[1]-line_width>cur_active_width[6] then | |
< b←inf_bad+1 | |
< else b←badness(cur_active_width[1]-line_width,cur_active_width[6]); | |
< if b>12 then fit_class←tight_fit@+else fit_class←decent_fit; | |
--- | |
> begin if -shortfall>cur_active_width[6] then b:=inf_bad+1 | |
> else b:=badness(-shortfall,cur_active_width[6]); | |
> if b>12 then fit_class:=tight_fit@+else fit_class:=decent_fit; | |
13688c16704 | |
< @ During the second pass, we dare not lose all active nodes, lest we lose | |
--- | |
> @ During the final pass, we dare not lose all active nodes, lest we lose | |
13697,13700c16713,16717 | |
< @<Prepare to deactivate node@@|r|, and |goto deactivate| unless...@>= | |
< begin if second_pass ∧ (minimum_demerits=awful_bad) ∧@| | |
< (link(r)=last_active) ∧ | |
< (prev_r=active) then b←0 {set badness zero, this break is forced} | |
--- | |
> @<Prepare to deactivate node~|r|, and |goto deactivate| unless...@>= | |
> begin if final_pass and (minimum_demerits=awful_bad) and@| | |
> (link(r)=last_active) and | |
> (prev_r=active) then | |
> artificial_demerits:=true {set demerits zero, this break is forced} | |
13702c16719 | |
< node_r_stays_active←false; | |
--- | |
> node_r_stays_active:=false; | |
13706c16723 | |
< feasible, its badness is@@|b|, and its fitness classification is |fit_class|. | |
--- | |
> feasible, its badness is~|b|, and its fitness classification is |fit_class|. | |
13713,13732c16730,16799 | |
< @<Compute the fewest total demerits, |d|, | |
< from the beginning to |cur_p| via@@|r|@>; | |
< if d≤minimal_demerits[fit_class] then | |
< begin minimal_demerits[fit_class]←d; | |
< best_place[fit_class]←break_node(r); best_pl_line[fit_class]←l; | |
< if d<minimum_demerits then minimum_demerits←d; | |
< end | |
< | |
< @ @<Compute the fewest total demerits...@>= | |
< if pi≥0 then | |
< begin d←(line_penalty+b+pi); d←d*d; | |
< end | |
< else begin d←line_penalty+b; d←d*d; | |
< if pi>eject_penalty then d←d-pi*pi; | |
< end; | |
< d←d+total_demerits(r); | |
< if (break_type=hyphenated)∧(type(r)=hyphenated) then | |
< if cur_p≠null then d←d+double_hyphen_demerits | |
< else d←d+final_hyphen_demerits; | |
< if abs(fit_class-fitness(r))>1 then d←d+adj_demerits | |
--- | |
> if artificial_demerits then d:=0 | |
> else @<Compute the demerits, |d|, from |r| to |cur_p|@>; | |
> @!stat if tracing_paragraphs>0 then | |
> @<Print a symbolic description of this feasible break@>; | |
> tats@;@/ | |
> d:=d+total_demerits(r); {this is the minimum total demerits | |
> from the beginning to |cur_p| via |r|} | |
> if d<=minimal_demerits[fit_class] then | |
> begin minimal_demerits[fit_class]:=d; | |
> best_place[fit_class]:=break_node(r); best_pl_line[fit_class]:=l; | |
> if d<minimum_demerits then minimum_demerits:=d; | |
> end | |
> | |
> @ @<Print a symbolic description of this feasible break@>= | |
> begin if printed_node<>cur_p then | |
> @<Print the list between |printed_node| and |cur_p|, | |
> then set |printed_node:=cur_p|@>; | |
> print_nl("@@"); | |
> @.\AT!@> | |
> if cur_p=null then print_esc("par") | |
> else if type(cur_p)<>glue_node then | |
> begin if type(cur_p)=penalty_node then print_esc("penalty") | |
> else if type(cur_p)=disc_node then print_esc("discretionary") | |
> else if type(cur_p)=kern_node then print_esc("kern") | |
> else print_esc("math"); | |
> end; | |
> print(" via @@@@"); | |
> if break_node(r)=null then print_char("0") | |
> else print_int(serial(break_node(r))); | |
> print(" b="); | |
> if b>inf_bad then print_char("*")@+else print_int(b); | |
> @.*\relax@> | |
> print(" p="); print_int(pi); print(" d="); | |
> if artificial_demerits then print_char("*")@+else print_int(d); | |
> end | |
> | |
> @ @<Print the list between |printed_node| and |cur_p|...@>= | |
> begin print_nl(""); | |
> if cur_p=null then short_display(link(printed_node)) | |
> else begin save_link:=link(cur_p); | |
> link(cur_p):=null; print_nl(""); short_display(link(printed_node)); | |
> link(cur_p):=save_link; | |
> end; | |
> printed_node:=cur_p; | |
> end | |
> | |
> @ When the data for a discretionary break is being displayed, we will have | |
> printed the |pre_break| and |post_break| lists; we want to skip over the | |
> third list, so that the discretionary data will not appear twice. The | |
> following code is performed at the very end of |try_break|. | |
> | |
> @<Update the value of |printed_node|...@>= | |
> if cur_p=printed_node then if cur_p<>null then if type(cur_p)=disc_node then | |
> begin t:=replace_count(cur_p); | |
> while t>0 do | |
> begin decr(t); printed_node:=link(printed_node); | |
> end; | |
> end | |
> | |
> @ @<Compute the demerits, |d|, from |r| to |cur_p|@>= | |
> begin d:=line_penalty+b; | |
> if abs(d)>=10000 then d:=100000000@+else d:=d*d; | |
> if pi<>0 then | |
> if pi>0 then d:=d+pi*pi | |
> else if pi>eject_penalty then d:=d-pi*pi; | |
> if (break_type=hyphenated)and(type(r)=hyphenated) then | |
> if cur_p<>null then d:=d+double_hyphen_demerits | |
> else d:=d+final_hyphen_demerits; | |
> if abs(fit_class-fitness(r))>1 then d:=d+adj_demerits; | |
> end | |
13738c16805 | |
< to@@|cur_p|. | |
--- | |
> to~|cur_p|. | |
13740,13742c16807,16809 | |
< @d combine_two_deltas(#)==@|mem[prev_r+#].sc←mem[prev_r+#].sc+mem[r+#].sc | |
< @d downdate_width(#)==@|cur_active_width[#]←cur_active_width[#]- | |
< mem[prev_r+#].sc | |
--- | |
> @d combine_two_deltas(#)==@|mem[prev_r+#].sc:=mem[prev_r+#].sc+mem[r+#].sc | |
> @d downdate_width(#)==@|cur_active_width[#]:=cur_active_width[#]- | |
> mem[prev_r+#].sc | |
13745c16812 | |
< link(prev_r)←link(r); free_node(r,active_node_size); | |
--- | |
> link(prev_r):=link(r); free_node(r,active_node_size); | |
13747c16814 | |
< node has been deleted@> | |
--- | |
> node has been deleted@> | |
13749,13760c16816,16827 | |
< begin r←link(prev_r); | |
< if r=last_active then | |
< begin do_all_six(downdate_width); | |
< link(prev_prev_r)←last_active; | |
< free_node(prev_r,delta_node_size); prev_r←prev_prev_r; | |
< end | |
< else if type(r)=delta_node then | |
< begin do_all_six(update_width); | |
< do_all_six(combine_two_deltas); | |
< link(prev_r)←link(r); free_node(r,delta_node_size); | |
< end; | |
< end | |
--- | |
> begin r:=link(prev_r); | |
> if r=last_active then | |
> begin do_all_six(downdate_width); | |
> link(prev_prev_r):=last_active; | |
> free_node(prev_r,delta_node_size); prev_r:=prev_prev_r; | |
> end | |
> else if type(r)=delta_node then | |
> begin do_all_six(update_width); | |
> do_all_six(combine_two_deltas); | |
> link(prev_r):=link(r); free_node(r,delta_node_size); | |
> end; | |
> end | |
13762c16829 | |
< @ The following code uses the fact that |type(last_active)≠delta_node|. If the | |
--- | |
> @ The following code uses the fact that |type(last_active)<>delta_node|. If the | |
13767c16834 | |
< @d update_active(#)==active_width[#]←active_width[#]+mem[r+#].sc | |
--- | |
> @d update_active(#)==active_width[#]:=active_width[#]+mem[r+#].sc | |
13770c16837 | |
< begin r←link(active); | |
--- | |
> begin r:=link(active); | |
13772,13775c16839,16842 | |
< begin do_all_six(update_active); | |
< do_all_six(copy_to_cur_active); | |
< link(active)←link(r); free_node(r,delta_node_size); | |
< end; | |
--- | |
> begin do_all_six(update_active); | |
> do_all_six(copy_to_cur_active); | |
> link(active):=link(r); free_node(r,delta_node_size); | |
> end; | |
13777c16844,16845 | |
< @* \[38] Breaking paragraphs into lines, continued. | |
--- | |
> | |
> @* \[39] Breaking paragraphs into lines, continued. | |
13782c16850 | |
< The main loop of |line_break| traverses the hlist of the given paragraph, | |
--- | |
> The main loop of |line_break| traverses the given hlist, | |
13789c16857 | |
< local variable, |prev_p|, is usually one step behind |cur_p|, but the real | |
--- | |
> variable, |prev_p|, is usually one step behind |cur_p|, but the real | |
13792c16860 | |
< point to a glue node, penalty node, kern node, or math node. | |
--- | |
> point to a glue node, penalty node, explicit kern node, or math node. | |
13800c16868 | |
< @!q,@!r,@!s:pointer; {miscellaneous nodes of temporary interest} | |
--- | |
> @!q,@!r,@!s,@!prev_s:pointer; {miscellaneous nodes of temporary interest} | |
13803,13804c16871,16872 | |
< @ The `\!|loop|\unskip' in the following code is performed at most | |
< twice per call of |line_break|, since it is actually a pass over the | |
--- | |
> @ The `\ignorespaces|loop|\unskip' in the following code is performed at most | |
> thrice per call of |line_break|, since it is actually a pass over the | |
13808,13826c16876,16912 | |
< threshold←pretolerance; second_pass←false; | |
< loop@+ begin @<Create an active breakpoint representing the beginning of | |
< the paragraph@>; | |
< cur_p←link(temp_head); auto_breaking←true;@/ | |
< prev_p←cur_p; {glue at beginning is not a legal breakpoint} | |
< while (cur_p≠null)∧(link(active)≠last_active) do | |
< @<Call |try_break| if |cur_p| is a legal breakpoint; | |
< on the second pass, also try to hyphenate the next | |
< word, if |cur_p| is a glue node; | |
< then advance |cur_p| to the next node of the paragraph | |
< that could possibly be a legal breakpoint@>; | |
< if cur_p=null then | |
< @<Try the final line break at the end of the paragraph, | |
< and |goto done| if the desired breakpoints have been found@>; | |
< @<Clean up the memory by removing the break nodes@>; | |
< threshold←tolerance; second_pass←true; {if at first you don't | |
< succeed, $\ldotss$} | |
< end; | |
< done: | |
--- | |
> threshold:=pretolerance; | |
> if threshold>=0 then | |
> begin @!stat if tracing_paragraphs>0 then | |
> begin begin_diagnostic; print_nl("@@firstpass");@+end;@;@+tats@;@/ | |
> second_pass:=false; final_pass:=false; | |
> end | |
> else begin threshold:=tolerance; second_pass:=true; | |
> final_pass:=(emergency_stretch<=0); | |
> @!stat if tracing_paragraphs>0 then begin_diagnostic;@+tats@; | |
> end; | |
> loop@+ begin if threshold>inf_bad then threshold:=inf_bad; | |
> if second_pass then @<Initialize for hyphenating a paragraph@>; | |
> @<Create an active breakpoint representing the beginning of the paragraph@>; | |
> cur_p:=link(temp_head); auto_breaking:=true;@/ | |
> prev_p:=cur_p; {glue at beginning is not a legal breakpoint} | |
> while (cur_p<>null)and(link(active)<>last_active) do | |
> @<Call |try_break| if |cur_p| is a legal breakpoint; | |
> on the second pass, also try to hyphenate the next | |
> word, if |cur_p| is a glue node; | |
> then advance |cur_p| to the next node of the paragraph | |
> that could possibly be a legal breakpoint@>; | |
> if cur_p=null then | |
> @<Try the final line break at the end of the paragraph, | |
> and |goto done| if the desired breakpoints have been found@>; | |
> @<Clean up the memory by removing the break nodes@>; | |
> if not second_pass then | |
> begin@!stat if tracing_paragraphs>0 then print_nl("@@secondpass");@;@+tats@/ | |
> threshold:=tolerance; second_pass:=true; final_pass:=(emergency_stretch<=0); | |
> end {if at first you don't succeed, \dots} | |
> else begin @!stat if tracing_paragraphs>0 then | |
> print_nl("@@emergencypass");@;@+tats@/ | |
> background[2]:=background[2]+emergency_stretch; final_pass:=true; | |
> end; | |
> end; | |
> done: @!stat if tracing_paragraphs>0 then | |
> begin end_diagnostic(true); normalize_selector; | |
> end;@+tats@/ | |
13829c16915 | |
< corresponding passive node. | |
--- | |
> corresponding passive node. | |
13831c16917 | |
< @d store_background(#)==active_width[#]←background[#] | |
--- | |
> @d store_background(#)==active_width[#]:=background[#] | |
13834,13837c16920,16923 | |
< q←get_node(active_node_size); | |
< type(q)←unhyphenated; fitness(q)←decent_fit; | |
< link(q)←last_active; break_node(q)←null; | |
< line_number(q)←already+1; total_demerits(q)←0; link(active)←q; | |
--- | |
> q:=get_node(active_node_size); | |
> type(q):=unhyphenated; fitness(q):=decent_fit; | |
> link(q):=last_active; break_node(q):=null; | |
> line_number(q):=prev_graf+1; total_demerits(q):=0; link(active):=q; | |
13839c16925,16926 | |
< passive←null | |
--- | |
> passive:=null; printed_node:=temp_head; pass_number:=0; | |
> font_in_short_display:=null_font | |
13842,13854c16929,16941 | |
< q←link(active); | |
< while q≠last_active do | |
< begin cur_p←link(q); | |
< if type(q)=delta_node then free_node(q,delta_node_size) | |
< else free_node(q,active_node_size); | |
< q←cur_p; | |
< end; | |
< q←passive; | |
< while q≠null do | |
< begin cur_p←link(q); | |
< free_node(q,passive_node_size); | |
< q←cur_p; | |
< end | |
--- | |
> q:=link(active); | |
> while q<>last_active do | |
> begin cur_p:=link(q); | |
> if type(q)=delta_node then free_node(q,delta_node_size) | |
> else free_node(q,active_node_size); | |
> q:=cur_p; | |
> end; | |
> q:=passive; | |
> while q<>null do | |
> begin cur_p:=link(q); | |
> free_node(q,passive_node_size); | |
> q:=cur_p; | |
> end | |
13863,13867c16950,16953 | |
< @d kern_break==begin@t@>@;@/ | |
< if not is_char_node(link(cur_p)) ∧ auto_breaking then | |
< if type(link(cur_p))=glue_node then try_break(0,unhyphenated); | |
< act_width←act_width+width(cur_p); | |
< end | |
--- | |
> @d kern_break==begin if not is_char_node(link(cur_p)) and auto_breaking then | |
> if type(link(cur_p))=glue_node then try_break(0,unhyphenated); | |
> act_width:=act_width+width(cur_p); | |
> end | |
13870,13871c16956,16958 | |
< begin while is_char_node(cur_p) do | |
< @<Advance \(c)|cur_p| to the node following the present character@>; | |
--- | |
> begin if is_char_node(cur_p) then | |
> @<Advance \(c)|cur_p| to the node following the present | |
> string of characters@>; | |
13873,13886c16960,16974 | |
< hlist_node,vlist_node,rule_node: act_width←act_width+width(cur_p); | |
< whatsit_node: @<Advance \(p)past a whatsit node in the |line_break| loop@>; | |
< glue_node: begin @<If node |cur_p| is a legal breakpoint, call |try_break|@>; | |
< @<Update the active widths by including the glue in |glue_ptr(cur_p)|@>; | |
< if second_pass ∧ auto_breaking then | |
< @<Try to hyphenate the following word@>; | |
< end; | |
< kern_node: kern_break; | |
< ligature_node: begin f←font(lig_char(cur_p)); | |
< act_width←act_width+char_width(f)(char_info(f)(character(lig_char(cur_p)))); | |
< end; | |
< disc_node: @<Try to break after a discretionary fragment@>; | |
< math_node: begin auto_breaking←(subtype(cur_p)=after); kern_break; | |
< end; | |
--- | |
> hlist_node,vlist_node,rule_node: act_width:=act_width+width(cur_p); | |
> whatsit_node: @<Advance \(p)past a whatsit node in the \(l)|line_break| loop@>; | |
> glue_node: begin @<If node |cur_p| is a legal breakpoint, call |try_break|; | |
> then update the active widths by including the glue in |glue_ptr(cur_p)|@>; | |
> if second_pass and auto_breaking then | |
> @<Try to hyphenate the following word@>; | |
> end; | |
> kern_node: if subtype(cur_p)=explicit then kern_break | |
> else act_width:=act_width+width(cur_p); | |
> ligature_node: begin f:=font(lig_char(cur_p)); | |
> act_width:=act_width+char_width(f)(char_info(f)(character(lig_char(cur_p)))); | |
> end; | |
> disc_node: @<Try to break after a discretionary fragment, then |goto done5|@>; | |
> math_node: begin auto_breaking:=(subtype(cur_p)=after); kern_break; | |
> end; | |
13890c16978 | |
< @:confusion paragraph}{\quad paragraph@> | |
--- | |
> @:this can't happen paragraph}{\quad paragraph@> | |
13892,13893c16980,16981 | |
< prev_p←cur_p; cur_p←link(cur_p); | |
< end | |
--- | |
> prev_p:=cur_p; cur_p:=link(cur_p); | |
> done5:end | |
13899a16988 | |
> @^inner loop@> | |
13901,13904c16990,16995 | |
< @<Advance \(c)|cur_p| to the node following the present character@>= | |
< begin f←font(cur_p); | |
< act_width←act_width+char_width(f)(char_info(f)(character(cur_p))); | |
< cur_p←link(cur_p); | |
--- | |
> @<Advance \(c)|cur_p| to the node following the present string...@>= | |
> begin prev_p:=cur_p; | |
> repeat f:=font(cur_p); | |
> act_width:=act_width+char_width(f)(char_info(f)(character(cur_p))); | |
> cur_p:=link(cur_p); | |
> until not is_char_node(cur_p); | |
13912,13922c17003,17012 | |
< begin if is_char_node(prev_p) then try_break(0,unhyphenated) | |
< else if precedes_break(prev_p) then try_break(0,unhyphenated); | |
< end | |
< | |
< @ @<Update the active widths by including the glue in |glue_ptr(cur_p)|@>= | |
< begin check_shrinkage(glue_ptr(cur_p)); q←glue_ptr(cur_p); | |
< act_width←act_width+width(q);@| | |
< active_width[2+stretch_order(q)]←@| | |
< active_width[2+stretch_order(q)]+stretch(q);@/ | |
< active_width[6]←active_width[6]+shrink(q); | |
< end | |
--- | |
> begin if is_char_node(prev_p) then try_break(0,unhyphenated) | |
> else if precedes_break(prev_p) then try_break(0,unhyphenated) | |
> else if (type(prev_p)=kern_node)and(subtype(prev_p)<>explicit) then | |
> try_break(0,unhyphenated); | |
> end; | |
> check_shrinkage(glue_ptr(cur_p)); q:=glue_ptr(cur_p); | |
> act_width:=act_width+width(q);@| | |
> active_width[2+stretch_order(q)]:=@| | |
> active_width[2+stretch_order(q)]+stretch(q);@/ | |
> active_width[6]:=active_width[6]+shrink(q) | |
13925c17015 | |
< only character nodes, kern nodes, and ligature nodes. | |
--- | |
> only character nodes, kern nodes, box nodes, rule nodes, and ligature nodes. | |
13927,13928c17017,17018 | |
< @<Try to break after a discretionary fragment@>= | |
< begin s←pre_break(cur_p); | |
--- | |
> @<Try to break after a discretionary fragment...@>= | |
> begin s:=pre_break(cur_p); disc_width:=0; | |
13930,13937c17020,17032 | |
< else begin disc_width←0; | |
< repeat @<Add the width of node |s| to |disc_width|@>; | |
< s←link(s); | |
< until s=null; | |
< act_width←act_width+disc_width; | |
< try_break(hyphen_penalty,hyphenated); | |
< act_width←act_width-disc_width; | |
< end; | |
--- | |
> else begin repeat @<Add the width of node |s| to |disc_width|@>; | |
> s:=link(s); | |
> until s=null; | |
> act_width:=act_width+disc_width; | |
> try_break(hyphen_penalty,hyphenated); | |
> act_width:=act_width-disc_width; | |
> end; | |
> r:=replace_count(cur_p); s:=link(cur_p); | |
> while r>0 do | |
> begin @<Add the width of node |s| to |act_width|@>; | |
> decr(r); s:=link(s); | |
> end; | |
> prev_p:=cur_p; cur_p:=s; goto done5; | |
13942,13953c17037,17065 | |
< begin f←font(s); | |
< disc_width←disc_width+char_width(f)(char_info(f)(character(s))); | |
< end | |
< else case type(s) of | |
< ligature_node: begin f←font(lig_char(s)); | |
< disc_width←disc_width+ | |
< char_width(f)(char_info(f)(character(lig_char(s)))); | |
< end; | |
< kern_node: disc_width←disc_width+width(s); | |
< othercases confusion("disc3") | |
< @:confusion disc3}{\quad disc3@> | |
< endcases | |
--- | |
> begin f:=font(s); | |
> disc_width:=disc_width+char_width(f)(char_info(f)(character(s))); | |
> end | |
> else case type(s) of | |
> ligature_node: begin f:=font(lig_char(s)); | |
> disc_width:=disc_width+ | |
> char_width(f)(char_info(f)(character(lig_char(s)))); | |
> end; | |
> hlist_node,vlist_node,rule_node,kern_node: | |
> disc_width:=disc_width+width(s); | |
> othercases confusion("disc3") | |
> @:this can't happen disc3}{\quad disc3@> | |
> endcases | |
> | |
> @ @<Add the width of node |s| to |act_width|@>= | |
> if is_char_node(s) then | |
> begin f:=font(s); | |
> act_width:=act_width+char_width(f)(char_info(f)(character(s))); | |
> end | |
> else case type(s) of | |
> ligature_node: begin f:=font(lig_char(s)); | |
> act_width:=act_width+ | |
> char_width(f)(char_info(f)(character(lig_char(s)))); | |
> end; | |
> hlist_node,vlist_node,rule_node,kern_node: | |
> act_width:=act_width+width(s); | |
> othercases confusion("disc4") | |
> @:this can't happen disc4}{\quad disc4@> | |
> endcases | |
13958c17070 | |
< correct ``looseness.'' On the second pass, there will be at least one active | |
--- | |
> correct ``looseness.'' On the final pass, there will be at least one active | |
13970c17082 | |
< and the optimum |best_line|} | |
--- | |
> and the optimum |best_line|} | |
13972c17084 | |
< the optimum |best_line|} | |
--- | |
> the optimum |best_line|} | |
13976,13981c17088,17093 | |
< if link(active)≠last_active then | |
< begin @<Find an active node with fewest demerits@>; | |
< if looseness=0 then goto done; | |
< @<Find the best active node for the desired looseness@>; | |
< if (actual_looseness=looseness)∨ second_pass then goto done; | |
< end; | |
--- | |
> if link(active)<>last_active then | |
> begin @<Find an active node with fewest demerits@>; | |
> if looseness=0 then goto done; | |
> @<Find the best active node for the desired looseness@>; | |
> if (actual_looseness=looseness)or final_pass then goto done; | |
> end; | |
13985,13989c17097,17101 | |
< r←link(active); fewest_demerits←awful_bad; | |
< repeat if type(r)≠delta_node then if total_demerits(r)<fewest_demerits then | |
< begin fewest_demerits←total_demerits(r); best_bet←r; | |
< end; | |
< r←link(r); | |
--- | |
> r:=link(active); fewest_demerits:=awful_bad; | |
> repeat if type(r)<>delta_node then if total_demerits(r)<fewest_demerits then | |
> begin fewest_demerits:=total_demerits(r); best_bet:=r; | |
> end; | |
> r:=link(r); | |
13991c17103 | |
< best_line←line_number(best_bet) | |
--- | |
> best_line:=line_number(best_bet) | |
13999,14012c17111,17124 | |
< begin r←link(active); actual_looseness←0; | |
< repeat if type(r)≠delta_node then | |
< begin line_diff←line_number(cur_p)-best_line; | |
< if ((line_diff<actual_looseness)∧(looseness≤line_diff))∨@| | |
< ((line_diff>actual_looseness)∧(looseness≥line_diff)) then | |
< begin best_bet←cur_p; actual_looseness←line_diff; | |
< fewest_demerits←total_demerits(r); | |
< end | |
< else if (line_diff=actual_looseness)∧@| | |
< (total_demerits(r)<fewest_demerits) then | |
< begin best_bet←cur_p; fewest_demerits←total_demerits(r); | |
< end; | |
< end; | |
< r←link(r); | |
--- | |
> begin r:=link(active); actual_looseness:=0; | |
> repeat if type(r)<>delta_node then | |
> begin line_diff:=line_number(r)-best_line; | |
> if ((line_diff<actual_looseness)and(looseness<=line_diff))or@| | |
> ((line_diff>actual_looseness)and(looseness>=line_diff)) then | |
> begin best_bet:=r; actual_looseness:=line_diff; | |
> fewest_demerits:=total_demerits(r); | |
> end | |
> else if (line_diff=actual_looseness)and@| | |
> (total_demerits(r)<fewest_demerits) then | |
> begin best_bet:=r; fewest_demerits:=total_demerits(r); | |
> end; | |
> end; | |
> r:=link(r); | |
14014c17126 | |
< best_line←line_number(best_bet); | |
--- | |
> best_line:=line_number(best_bet); | |
14017c17129 | |
< @ Once the best sequence of breakpoints has been found, we call on the | |
--- | |
> @ Once the best sequence of breakpoints has been found (hurray), we call on the | |
14026c17138 | |
< is |best_line-already-1|. The last breakpoint is specified by | |
--- | |
> is |best_line-prev_graf-1|. The last breakpoint is specified by | |
14040a17153 | |
> @!post_disc_break:boolean; {and did it have a nonempty post-break part?} | |
14047,14048c17160,17161 | |
< first breakpoint@>; | |
< cur_line←already+1; | |
--- | |
> first breakpoint@>; | |
> cur_line:=prev_graf+1; | |
14050,14053c17163,17167 | |
< current vertical list, together with associated penalties and other | |
< insertions@>; | |
< incr(cur_line); cur_p←next_break(cur_p); | |
< if cur_p≠null then @<Prune unwanted nodes at the beginning of the next line@>; | |
--- | |
> current vertical list, together with associated penalties and other | |
> insertions@>; | |
> incr(cur_line); cur_p:=next_break(cur_p); | |
> if cur_p<>null then if not post_disc_break then | |
> @<Prune unwanted nodes at the beginning of the next line@>; | |
14055,14058c17169,17172 | |
< if (cur_line≠best_line)∨(link(temp_head)≠null) then | |
< confusion("line breaking"); | |
< @:confusion line breaking}{\quad line breaking@> | |
< already←best_line-1; | |
--- | |
> if (cur_line<>best_line)or(link(temp_head)<>null) then | |
> confusion("line breaking"); | |
> @:this can't happen line breaking}{\quad line breaking@> | |
> prev_graf:=best_line-1; | |
14068,14069c17182,17183 | |
< q←break_node(best_bet); cur_p←null; | |
< repeat r←q; q←prev_break(q); next_break(r)←cur_p; cur_p←r; | |
--- | |
> q:=break_node(best_bet); cur_p:=null; | |
> repeat r:=q; q:=prev_break(q); next_break(r):=cur_p; cur_p:=r; | |
14073,14074c17187,17189 | |
< a line, except in the unusual case that the node to be deleted is actually | |
< one of the chosen breakpoints. The pruning done here is designed to match | |
--- | |
> a line, except in the anomalous case that the node to be deleted is actually | |
> one of the chosen breakpoints. Otherwise | |
> the pruning done here is designed to match | |
14079,14091c17194,17207 | |
< begin r←temp_head; | |
< loop@+ begin q←link(r); | |
< if q=cur_break(cur_p) then goto done1; | |
< {|cur_break(cur_p)| is the next breakpoint} | |
< {now |q| cannot be |null|} | |
< if is_char_node(q) then goto done1; | |
< if non_discardable(q) then goto done1; | |
< r←q; {now |type(q)=glue_node|, |kern_node|, |math_node| or |penalty_node|} | |
< end; | |
< done1: if r≠temp_head then | |
< begin link(r)←null; flush_node_list(link(temp_head)); | |
< link(temp_head)←q; | |
< end; | |
--- | |
> begin r:=temp_head; | |
> loop@+ begin q:=link(r); | |
> if q=cur_break(cur_p) then goto done1; | |
> {|cur_break(cur_p)| is the next breakpoint} | |
> {now |q| cannot be |null|} | |
> if is_char_node(q) then goto done1; | |
> if non_discardable(q) then goto done1; | |
> if type(q)=kern_node then if subtype(q)<>explicit then goto done1; | |
> r:=q; {now |type(q)=glue_node|, |kern_node|, |math_node| or |penalty_node|} | |
> end; | |
> done1: if r<>temp_head then | |
> begin link(r):=null; flush_node_list(link(temp_head)); | |
> link(temp_head):=q; | |
> end; | |
14104c17220 | |
< \.{\\rightskip}; also set the proper value of |disc_break|@>; | |
--- | |
> \.{\\rightskip}; also set the proper value of |disc_break|@>; | |
14108c17224 | |
< special nodes taken out of the box by the packager@>; | |
--- | |
> special nodes taken out of the box by the packager@>; | |
14115,14130c17231,17246 | |
< q←cur_break(cur_p); disc_break←false; | |
< if q≠null then {|q| cannot be a |char_node|} | |
< if type(q)=glue_node then | |
< begin delete_glue_ref(glue_ptr(q)); | |
< glue_ptr(q)←right_skip; | |
< subtype(q)←right_skip_code+1; add_glue_ref(right_skip); | |
< goto done; | |
< end | |
< else begin if type(q)=disc_node then | |
< @<Change discretionary to compulsory and set | |
< |disc_break←true|@>; | |
< if (type(q)=math_node)∨(type(q)=kern_node) then width(q)←0; | |
< end | |
< else begin q←temp_head; | |
< while link(q)≠null do q←link(q); | |
< end; | |
--- | |
> q:=cur_break(cur_p); disc_break:=false; post_disc_break:=false; | |
> if q<>null then {|q| cannot be a |char_node|} | |
> if type(q)=glue_node then | |
> begin delete_glue_ref(glue_ptr(q)); | |
> glue_ptr(q):=right_skip; | |
> subtype(q):=right_skip_code+1; add_glue_ref(right_skip); | |
> goto done; | |
> end | |
> else begin if type(q)=disc_node then | |
> @<Change discretionary to compulsory and set | |
> |disc_break:=true|@> | |
> else if (type(q)=math_node)or(type(q)=kern_node) then width(q):=0; | |
> end | |
> else begin q:=temp_head; | |
> while link(q)<>null do q:=link(q); | |
> end; | |
14135,14157c17251,17268 | |
< begin t←replace_count(q); | |
< @<Destroy the |t| nodes following |q|, but save the last one if it is | |
< a necessary kern; make |r| point to the following node@>; | |
< if post_break(q)≠null then @<Transplant the post-break list@>; | |
< if pre_break(q)≠null then @<Transplant the pre-break list@>; | |
< link(q)←r; disc_break←true; | |
< end | |
< | |
< @ A subtle bug that would perhaps never have been detected is avoided here | |
< by preserving a kern node that just might equal |cur_break(next_break(cur_p))|. | |
< | |
< @<Destroy the |t| nodes following |q|...@>= | |
< if t=0 then r←link(q) | |
< else begin r←q; | |
< while t>1 do | |
< begin r←link(r); decr(t); | |
< end; | |
< s←link(r); | |
< if ¬is_char_node(s) then if next_break(cur_p)≠null then | |
< if cur_break(next_break(cur_p))=s then s←r; | |
< r←link(s); link(s)←null; | |
< flush_node_list(link(q)); replace_count(q)←0; | |
< end | |
--- | |
> begin t:=replace_count(q); | |
> @<Destroy the |t| nodes following |q|, and | |
> make |r| point to the following node@>; | |
> if post_break(q)<>null then @<Transplant the post-break list@>; | |
> if pre_break(q)<>null then @<Transplant the pre-break list@>; | |
> link(q):=r; disc_break:=true; | |
> end | |
> | |
> @ @<Destroy the |t| nodes following |q|...@>= | |
> if t=0 then r:=link(q) | |
> else begin r:=q; | |
> while t>1 do | |
> begin r:=link(r); decr(t); | |
> end; | |
> s:=link(r); | |
> r:=link(s); link(s):=null; | |
> flush_node_list(link(q)); replace_count(q):=0; | |
> end | |
14163,14165c17274,17276 | |
< begin s←post_break(q); | |
< while link(s)≠null do s←link(s); | |
< link(s)←r; r←post_break(q); post_break(q)←null; | |
--- | |
> begin s:=post_break(q); | |
> while link(s)<>null do s:=link(s); | |
> link(s):=r; r:=post_break(q); post_break(q):=null; post_disc_break:=true; | |
14172,14174c17283,17285 | |
< begin s←pre_break(q); link(q)←s; | |
< while link(s)≠null do s←link(s); | |
< pre_break(q)←null; q←s; | |
--- | |
> begin s:=pre_break(q); link(q):=s; | |
> while link(s)<>null do s:=link(s); | |
> pre_break(q):=null; q:=s; | |
14178c17289 | |
< r←new_param_glue(right_skip_code); link(r)←link(q); link(q)←r; q←r | |
--- | |
> r:=new_param_glue(right_skip_code); link(r):=link(q); link(q):=r; q:=r | |
14185,14189c17296,17307 | |
< r←link(q); link(q)←null; q←link(temp_head); link(temp_head)←r; | |
< if left_skip≠zero_glue then | |
< begin r←new_param_glue(left_skip_code); | |
< link(r)←q; q←r; | |
< end | |
--- | |
> r:=link(q); link(q):=null; q:=link(temp_head); link(temp_head):=r; | |
> if left_skip<>zero_glue then | |
> begin r:=new_param_glue(left_skip_code); | |
> link(r):=q; q:=r; | |
> end | |
> | |
> @ @<Append the new box to the current vertical list...@>= | |
> append_to_vlist(just_box); | |
> if adjust_head<>adjust_tail then | |
> begin link(tail):=link(adjust_head); tail:=adjust_tail; | |
> end; | |
> adjust_tail:=null | |
14198,14199c17316,17317 | |
< begin cur_width←second_width; cur_indent←second_indent; | |
< end | |
--- | |
> begin cur_width:=second_width; cur_indent:=second_indent; | |
> end | |
14201,14215c17319,17325 | |
< begin cur_width←first_width; cur_indent←first_indent; | |
< end | |
< else begin cur_width←mem[par_shape_ptr+2*cur_line].sc; | |
< cur_indent←mem[par_shape_ptr+2*cur_line-1].sc; | |
< end; | |
< just_box←hpack(q,cur_width,exactly); | |
< shift_amount(just_box)←cur_indent | |
< | |
< @ @<Append the new box to the current vertical list...@>= | |
< append_to_vlist(just_box); | |
< if adjustments≠null then | |
< begin link(tail)←adjustments; | |
< repeat tail←link(tail); | |
< until link(tail)=null; | |
< end | |
--- | |
> begin cur_width:=first_width; cur_indent:=first_indent; | |
> end | |
> else begin cur_width:=mem[par_shape_ptr+2*cur_line].sc; | |
> cur_indent:=mem[par_shape_ptr+2*cur_line-1].sc; | |
> end; | |
> adjust_tail:=adjust_head; just_box:=hpack(q,cur_width,exactly); | |
> shift_amount(just_box):=cur_indent | |
14217,14218c17327,17328 | |
< @ Penalties between the lines of a paragraph come from widow lines, from | |
< the |inter_line_penalty| parameter, and from lines that end at | |
--- | |
> @ Penalties between the lines of a paragraph come from club and widow lines, | |
> from the |inter_line_penalty| parameter, and from lines that end at | |
14220,14221c17330,17332 | |
< two contributions of widow-line penalties. The local variable |pen| will | |
< be set to the sum of all relevant penalties for the current line. | |
--- | |
> both club-line and widow-line penalties. The local variable |pen| will | |
> be set to the sum of all relevant penalties for the current line, except | |
> that the final line is never penalized. | |
14224,14232c17335,17346 | |
< if cur_line+1=best_line then pen←0@+else pen←inter_line_penalty; | |
< if (cur_line=already+1)∧(best_line≠already+2) then pen←pen+widow_penalty; | |
< if cur_line+2=best_line then pen←pen+final_widow_penalty; | |
< if disc_break then pen←pen+broken_penalty; | |
< if pen≠0 then | |
< begin r←new_penalty(pen); | |
< link(tail)←r; tail←r; | |
< end | |
< @* \[39] Pre-hyphenation. | |
--- | |
> if cur_line+1<>best_line then | |
> begin pen:=inter_line_penalty; | |
> if cur_line=prev_graf+1 then pen:=pen+club_penalty; | |
> if cur_line+2=best_line then pen:=pen+final_widow_penalty; | |
> if disc_break then pen:=pen+broken_penalty; | |
> if pen<>0 then | |
> begin r:=new_penalty(pen); | |
> link(tail):=r; tail:=r; | |
> end; | |
> end | |
> | |
> @* \[40] Pre-hyphenation. | |
14248,14268c17362,17385 | |
< This is a sequence of nodes $p↓0p↓1\ldotsm p↓m$ where $p↓0$ is a glue | |
< node, $p↓1\ldotsm p↓{m-1}$ are either character or ligature or kern nodes, | |
< and $p↓m$ is a glue or penalty or insertion or adjust or mark node. | |
< (Therefore hyphenation is disabled by boxes, math formulas, whatsit nodes, and | |
< discretionary nodes already inserted by the user.) The ligature nodes among | |
< $p↓1\ldotsm p↓{m-1}$ are effectively expanded into the original non-ligature | |
< characters, and the kern nodes are ignored. Each character $c$ is now | |
< classified as either a nonletter (if |c≥128| or |lc_code(c)=0|), a lower | |
< case letter (if |lc_code(c)=c|), or an upper case letter (otherwise); an | |
< upper case letter is treated as if it were |lc_code(c)| for purposes of | |
< hyphenation. The characters generated by $p↓1\ldotsm p↓{m-1}$ may begin with | |
< nonletters; let $c↓1$ be the first letter that is not in the middle | |
< of a ligature. All characters that do not have | |
< the same font as $c↓1$ will be treated as nonletters. \TeX\ looks ahead | |
< for as many consecutive letters $c↓1\ldotsm c↓n$ as possible; however, | |
< |n| must be less than 64, so a character that would otherwise be $c↓{64}$ | |
< is effectively not a letter. Furthermore $c↓n$ must not be in the middle | |
< of a ligature. In this way we obtain a string of letters | |
< $c↓1\ldotsm c↓n$ that are generated by nodes $p↓a\ldotsm p↓b$, where | |
< |1≤a≤b+1≤m|. If |n≥5|, this string qualifies for hyphenation; however, | |
< |uc_hyph| must be nonzero, if $c↓1$ is upper case. | |
--- | |
> This is a sequence of nodes $p_0p_1\ldots p_m$ where $p_0$ is a glue node, | |
> $p_1\ldots p_{m-1}$ are either character or ligature or whatsit or | |
> implicit kern nodes, and $p_m$ is a glue or penalty or insertion or adjust | |
> or mark or whatsit or explicit kern node. (Therefore hyphenation is | |
> disabled by boxes, math formulas, and discretionary nodes already inserted | |
> by the user.) The ligature nodes among $p_1\ldots p_{m-1}$ are effectively | |
> expanded into the original non-ligature characters; the kern nodes and | |
> whatsits are ignored. Each character |c| is now classified as either a | |
> nonletter (if |lc_code(c)=0|), a lowercase letter (if | |
> |lc_code(c)=c|), or an uppercase letter (otherwise); an uppercase letter | |
> is treated as if it were |lc_code(c)| for purposes of hyphenation. The | |
> characters generated by $p_1\ldots p_{m-1}$ may begin with nonletters; let | |
> $c_1$ be the first letter that is not in the middle of a ligature. Whatsit | |
> nodes preceding $c_1$ are ignored; a whatsit found after $c_1$ will be the | |
> terminating node $p_m$. All characters that do not have the same font as | |
> $c_1$ will be treated as nonletters. The |hyphen_char| for that font | |
> must be between 0 and 255, otherwise hyphenation will not be attempted. | |
> \TeX\ looks ahead for as many consecutive letters $c_1\ldots c_n$ as | |
> possible; however, |n| must be less than 64, so a character that would | |
> otherwise be $c_{64}$ is effectively not a letter. Furthermore $c_n$ must | |
> not be in the middle of a ligature. In this way we obtain a string of | |
> letters $c_1\ldots c_n$ that are generated by nodes $p_a\ldots p_b$, where | |
> |1<=a<=b+1<=m|. If |n>=l_hyf+r_hyf|, this string qualifies for hyphenation; | |
> however, |uc_hyph| must be positive, if $c_1$ is uppercase. | |
14271c17388 | |
< sequence $c↓1\ldotsm c↓n$ is found; then potential positions for hyphens | |
--- | |
> sequence $c_1\ldots c_n$ is found; then potential positions for hyphens | |
14273c17390 | |
< $p↓a\ldotsm p↓b$ are replaced by a new sequence of nodes that includes the | |
--- | |
> $p_a\ldots p_b$ are replaced by a new sequence of nodes that includes the | |
14284c17401,17406 | |
< @ The letters $c↓1\ldotsm c↓n$ that are candidates for hyphenation are placed | |
--- | |
> @<Initialize for hyphenating...@>= | |
> begin @!init if trie_not_ready then init_trie;@+tini@;@/ | |
> cur_lang:=init_cur_lang; l_hyf:=init_l_hyf; r_hyf:=init_r_hyf; | |
> end | |
> | |
> @ The letters $c_1\ldots c_n$ that are candidates for hyphenation are placed | |
14286c17408 | |
< nodes $p↓a$ and@@$p↓b$ in the description above are placed into variables | |
--- | |
> nodes $p_{a-1}$ and~$p_b$ in the description above are placed into variables | |
14290c17412 | |
< @!hc:array[0..65] of ascii_code; {word to be hyphenated} | |
--- | |
> @!hc:array[0..65] of 0..256; {word to be hyphenated} | |
14294c17416,17420 | |
< @!hu:array[1..63] of ascii_code; {like |hc|, before conversion to lower case} | |
--- | |
> @!hu:array[0..63] of 0..256; {like |hc|, before conversion to lowercase} | |
> @!hyf_char:integer; {hyphen character of the relevant font} | |
> @!cur_lang,@!init_cur_lang:ASCII_code; {current hyphenation table of interest} | |
> @!l_hyf,@!r_hyf,@!init_l_hyf,@!init_r_hyf:integer; {limits on fragment sizes} | |
> @!hyf_bchar:halfword; {boundary character after $c_n$} | |
14299c17425 | |
< @!i,@!j,@!l:small_number; {indices into |hc| or |hu|} | |
--- | |
> @!j:small_number; {an index into |hc| or |hu|} | |
14306,14315c17432,17441 | |
< begin s←link(cur_p); | |
< if s≠null then | |
< begin @<Skip to node |ha|, or |goto done1| if no hyphenation | |
< should be attempted@>; | |
< @<Skip to node |hb|, putting letters into |hu| and |hc|, | |
< or |goto done1| if no hyphenation should be attempted@>; | |
< @<Check that the nodes following |hb| permit hyphenation and that | |
< at least five letters have been found, otherwise |goto done1|@>; | |
< hyphenate; | |
< end; | |
--- | |
> begin prev_s:=cur_p; s:=link(prev_s); | |
> if s<>null then | |
> begin @<Skip to node |ha|, or |goto done1| if no hyphenation | |
> should be attempted@>; | |
> if l_hyf+r_hyf>63 then goto done1; | |
> @<Skip to node |hb|, putting letters into |hu| and |hc|@>; | |
> @<Check that the nodes following |hb| permit hyphenation and that at least | |
> |l_hyf+r_hyf| letters have been found, otherwise |goto done1|@>; | |
> hyphenate; | |
> end; | |
14321,14323c17447,17449 | |
< label done,found,not_found,found1,exit; | |
< var@?@<Local variables for hyphenation@>@; | |
< begin @<Find hyphen locations for the word in |hc|@>; | |
--- | |
> label common_ending,done,found,found1,found2,not_found,exit; | |
> var @<Local variables for hyphenation@>@; | |
> begin @<Find hyphen locations for the word in |hc|, or |return|@>; | |
14326c17452 | |
< the discretionary hyphens@>; | |
--- | |
> the discretionary hyphens@>; | |
14329c17455 | |
< @ The first thing we need to do is find the node |ha| that contains the | |
--- | |
> @ The first thing we need to do is find the node |ha| just before the | |
14333,14346c17459,17480 | |
< loop@+ begin if is_char_node(s) then | |
< begin c←qo(character(s)); hf←font(s); | |
< end | |
< else if type(s)=ligature_node then | |
< begin q←lig_ptr(s); c←qo(character(q)); hf←font(q); | |
< end | |
< else if type(s)≠kern_node then goto done1 | |
< else c←128; | |
< if c<128 then if lc_code(c)≠0 then | |
< if (lc_code(c)=c)∨(uc_hyph≠0) then goto done2 | |
< else goto done1; | |
< s←link(s); | |
< end; | |
< done2: ha←s | |
--- | |
> loop@+ begin if is_char_node(s) then | |
> begin c:=qo(character(s)); hf:=font(s); | |
> end | |
> else if type(s)=ligature_node then | |
> if lig_ptr(s)=null then goto continue | |
> else begin q:=lig_ptr(s); c:=qo(character(q)); hf:=font(q); | |
> end | |
> else if (type(s)=kern_node)and(subtype(s)=normal) then goto continue | |
> else if type(s)=whatsit_node then | |
> begin @<Advance \(p)past a whatsit node in the \(p)pre-hyphenation loop@>; | |
> goto continue; | |
> end | |
> else goto done1; | |
> if lc_code(c)<>0 then | |
> if (lc_code(c)=c)or(uc_hyph>0) then goto done2 | |
> else goto done1; | |
> continue: prev_s:=s; s:=link(prev_s); | |
> end; | |
> done2: hyf_char:=hyphen_char[hf]; | |
> if hyf_char<0 then goto done1; | |
> if hyf_char>255 then goto done1; | |
> ha:=prev_s | |
14351,14364c17485,17502 | |
< hn←0; | |
< loop@+ begin if is_char_node(s) then | |
< begin if font(s)≠hf then goto done3; | |
< c←qo(character(s)); | |
< if c≥128 then goto done3; | |
< if (lc_code(c)=0)∨(hn=63) then goto done3; | |
< hb←s; incr(hn); hu[hn]←c; hc[hn]←lc_code(c); | |
< end | |
< else if type(s)=ligature_node then | |
< @<Move the characters of a ligature node to |hu| and |hc|; | |
< but |goto done3| if they are not all letters@> | |
< else if type(s)≠kern_node then goto done3; | |
< s←link(s); | |
< end; | |
--- | |
> hn:=0; | |
> loop@+ begin if is_char_node(s) then | |
> begin if font(s)<>hf then goto done3; | |
> hyf_bchar:=character(s); c:=qo(hyf_bchar); | |
> if lc_code(c)=0 then goto done3; | |
> if hn=63 then goto done3; | |
> hb:=s; incr(hn); hu[hn]:=c; hc[hn]:=lc_code(c); hyf_bchar:=non_char; | |
> end | |
> else if type(s)=ligature_node then | |
> @<Move the characters of a ligature node to |hu| and |hc|; | |
> but |goto done3| if they are not all letters@> | |
> else if (type(s)=kern_node)and(subtype(s)=normal) then | |
> begin hb:=s; | |
> hyf_bchar:=font_bchar[hf]; | |
> end | |
> else goto done3; | |
> s:=link(s); | |
> end; | |
14373,14381c17511,17521 | |
< begin j←hn; q←lig_ptr(s); | |
< if font(q)≠hf then goto done3; | |
< repeat c←qo(character(q)); | |
< if c≥128 then goto done3; | |
< if (lc_code(c)=0)∨(j=63) then goto done3; | |
< incr(j); hu[j]←c; hc[j]←lc_code(c);@/ | |
< q←link(q); | |
< until q=null; | |
< hb←s; hn←j; | |
--- | |
> begin if font(lig_char(s))<>hf then goto done3; | |
> j:=hn; q:=lig_ptr(s);@+if q>null then hyf_bchar:=character(q); | |
> while q>null do | |
> begin c:=qo(character(q)); | |
> if lc_code(c)=0 then goto done3; | |
> if j=63 then goto done3; | |
> incr(j); hu[j]:=c; hc[j]:=lc_code(c);@/ | |
> q:=link(q); | |
> end; | |
> hb:=s; hn:=j; | |
> if odd(subtype(s)) then hyf_bchar:=font_bchar[hf]@+else hyf_bchar:=non_char; | |
14385,14394c17525,17535 | |
< if hn<5 then goto done1; | |
< loop@+ begin if ¬(is_char_node(s)) then | |
< case type(s) of | |
< ligature_node,kern_node: do_nothing; | |
< glue_node,penalty_node,ins_node,adjust_node,mark_node: | |
< goto done4; | |
< othercases goto done1 | |
< endcases; | |
< s←link(s); | |
< end; | |
--- | |
> if hn<l_hyf+r_hyf then goto done1; {|l_hyf| and |r_hyf| are |>=1|} | |
> loop@+ begin if not(is_char_node(s)) then | |
> case type(s) of | |
> ligature_node: do_nothing; | |
> kern_node: if subtype(s)<>normal then goto done4; | |
> whatsit_node,glue_node,penalty_node,ins_node,adjust_node,mark_node: | |
> goto done4; | |
> othercases goto done1 | |
> endcases; | |
> s:=link(s); | |
> end; | |
14396c17537,17538 | |
< @* \[40] Post-hyphenation. | |
--- | |
> | |
> @* \[41] Post-hyphenation. | |
14405a17548,17550 | |
> @!init_list:pointer; {list of punctuation characters preceding the word} | |
> @!init_lig:boolean; {does |init_list| represent a ligature?} | |
> @!init_lft:boolean; {if so, did the ligature involve a left boundary?} | |
14408c17553 | |
< @!i,@!j,@!l:small_number; {indices into |hc| or |hu|} | |
--- | |
> @!i,@!j,@!l:0..65; {indices into |hc| or |hu|} | |
14409a17555 | |
> @!bchar:halfword; {right boundary character of hyphenated word, or |non_char|} | |
14411,14414c17557,17562 | |
< @ \TeX\ will never insert a hyphen that has fewer than two letters before | |
< it or fewer than three after it; hence, a five-letter word has comparatively | |
< little chance of being hyphenated. If no hyphens have been found, | |
< we can save time by not having to make any changes to the paragraph. | |
--- | |
> @ \TeX\ will never insert a hyphen that has fewer than | |
> \.{\\lefthyphenmin} letters before it or fewer than | |
> \.{\\righthyphenmin} after it; hence, a short word has | |
> comparatively little chance of being hyphenated. If no hyphens have | |
> been found, we can save time by not having to make any changes to the | |
> paragraph. | |
14417c17565 | |
< for j←2 to hn-3 do if odd(hyf[j]) then goto found1; | |
--- | |
> for j:=l_hyf to hn-r_hyf do if odd(hyf[j]) then goto found1; | |
14422,14423c17570,17577 | |
< subsequence of nodes |ha..hb|. The variable |s| will point to the node | |
< preceding |ha|, and |q| will point to the node following |hb|, so that | |
--- | |
> subsequence of nodes between |ha| and~|hb|. An attempt is made to | |
> preserve the effect that implicit boundary characters and punctuation marks | |
> had on ligatures inside the hyphenated word, by storing a left boundary or | |
> preceding character in |hu[0]| and by storing a possible right boundary | |
> in |bchar|. We set |j:=0| if |hu[0]| is to be part of the reconstruction; | |
> otherwise |j:=1|. | |
> The variable |s| will point to the tail of the current hlist, and | |
> |q| will point to the node following |hb|, so that | |
14427,14430c17581,17606 | |
< q←link(hb); link(hb)←null; s←cur_p; | |
< while link(s)≠ha do s←link(s); | |
< link(s)←null; flush_node_list(ha); | |
< @<Reconstitute nodes for the hyphenated word, inserting discretionary hyphens@> | |
--- | |
> q:=link(hb); link(hb):=null; r:=link(ha); link(ha):=null; bchar:=hyf_bchar; | |
> if is_char_node(ha) then | |
> if font(ha)<>hf then goto found2 | |
> else begin init_list:=ha; init_lig:=false; hu[0]:=qo(character(ha)); | |
> end | |
> else if type(ha)=ligature_node then | |
> if font(lig_char(ha))<>hf then goto found2 | |
> else begin init_list:=lig_ptr(ha); init_lig:=true; init_lft:=(subtype(ha)>1); | |
> hu[0]:=qo(character(lig_char(ha))); | |
> if init_list=null then if init_lft then | |
> begin hu[0]:=256; init_lig:=false; | |
> end; {in this case a ligature will be reconstructed from scratch} | |
> free_node(ha,small_node_size); | |
> end | |
> else begin {no punctuation found; look for left boundary} | |
> if not is_char_node(r) then if type(r)=ligature_node then | |
> if subtype(r)>1 then goto found2; | |
> j:=1; s:=ha; init_list:=null; goto common_ending; | |
> end; | |
> s:=cur_p; {we have |cur_p<>ha| because |type(cur_p)=glue_node|} | |
> while link(s)<>ha do s:=link(s); | |
> j:=0; goto common_ending; | |
> found2: s:=ha; j:=0; hu[0]:=256; init_lig:=false; init_list:=null; | |
> common_ending: flush_node_list(r); | |
> @<Reconstitute nodes for the hyphenated word, inserting discretionary hyphens@>; | |
> flush_list(init_list) | |
14433c17609 | |
< {\def\!{\kern-1pt} | |
--- | |
> {\def\!{\kern-1pt}% | |
14435,14447c17611,17633 | |
< because ligatures might change when a hyphen is present. The manual discusses | |
< the difficulties of the word ``difficult'', but since fonts can include | |
< highly general ligatures, the discretionary material surrounding a hyphen can | |
< be even more complex than that. For example, suppose that \.{abcdef} is a | |
< word in a font for which the only ligatures are \.{b\!c}, \.{c\!d}, \.{d\!e}, | |
< and \.{e\!f}. If this word is to permit hyphenation between \.b and \.c, the | |
< two patterns with and without hyphenation are $\.a\,\.{b\!c}\,\.{d\!e}\,\.f$ | |
< and $\.a\,\.b\,\.-\,\.{c\!d}\,\.{e\!f}$. Thus the insertion of a hyphen might | |
< cause effects to ripple arbitrarily far into the rest of the word. A | |
< further complication arises if additional hyphens appear together with | |
< such rippling, e.g., if the word in the example just given could also be | |
< hyphenated between \.c and \.d; \TeX\ avoids this by simply ignoring the | |
< additional hyphens in such weird cases.} | |
--- | |
> because ligatures might change when a hyphen is present. {\sl The \TeX book\/} | |
> discusses the difficulties of the word ``difficult'', and | |
> the discretionary material surrounding a | |
> hyphen can be considerably more complex than that. Suppose | |
> \.{abcdef} is a word in a font for which the only ligatures are \.{b\!c}, | |
> \.{c\!d}, \.{d\!e}, and \.{e\!f}. If this word permits hyphenation | |
> between \.b and \.c, the two patterns with and without hyphenation are | |
> $\.a\,\.b\,\.-\,\.{c\!d}\,\.{e\!f}$ and $\.a\,\.{b\!c}\,\.{d\!e}\,\.f$. | |
> Thus the insertion of a hyphen might cause effects to ripple arbitrarily | |
> far into the rest of the word. A further complication arises if additional | |
> hyphens appear together with such rippling, e.g., if the word in the | |
> example just given could also be hyphenated between \.c and \.d; \TeX\ | |
> avoids this by simply ignoring the additional hyphens in such weird cases.} | |
> | |
> Still further complications arise in the presence of ligatures that do not | |
> delete the original characters. When punctuation precedes the word being | |
> hyphenated, \TeX's method is not perfect under all possible scenarios, | |
> because punctuation marks and letters can propagate information back and forth. | |
> For example, suppose the original pre-hyphenation pair | |
> \.{*a} changes to \.{*y} via a \.{\?=:} ligature, which changes to \.{xy} | |
> via a \.{=:\?} ligature; if $p_{a-1}=\.x$ and $p_a=\.y$, the reconstitution | |
> procedure isn't smart enough to obtain \.{xy} again. In such cases the | |
> font designer should include a ligature that goes from \.{xa} to \.{xy}. | |
14450,14472c17636,17668 | |
< an index@@|j|, this function creates a node for the next character or ligature | |
< found in the |hu| array starting at |hu[j]|, using font |hf|. For example, | |
< if |hu[j..j+2]| contains the three letters `f', `i', and `x', and if | |
< font |hf| contains an `fi' ligature but no `fix' ligature, then |reconstitute| | |
< will create a ligature node for `fi'. The index of the last character | |
< consumed, in this case |j+1|, will be returned. Furthermore, a kern node | |
< is created and appended, if kerning is called for between the consumed | |
< character or ligature and the next (unconsumed) character. | |
< | |
< A second parameter, |n|, gives the limit beyond which this procedure does not | |
< advance. In other words, |hu[n]| might be consumed, but |hu[n+1]| is never | |
< accessed. | |
< | |
< The global variable |hyphen_passed| is set to@@|k| if this procedure | |
< consumes two characters |hu[k]| and |hu[k+1]| such that |hyf[k]| is odd, | |
< i.e., if the ligature might have to be broken by a hyphen, or if a kern is | |
< inserted between |hu[k]| and |hu[k+1]|. If this condition holds for more | |
< than one value of |k|, the smallest value is used; and if the condition | |
< holds for no values of |k|, |hyphen_passed| is set to zero. | |
< | |
< After |reconstitute| has acted, |link(hold_head)| points to the character | |
< or ligature node that was created, and |link(link(hold_head))| will either | |
< be |null| or a pointer to the kern node that was appended. | |
--- | |
> a string of characters $x_j\ldots x_n$, there is a smallest index $m\ge j$ | |
> such that the ``translation'' of $x_j\ldots x_n$ by ligatures and kerning | |
> has the form $y_1\ldots y_t$ followed by the translation of $x_{m+1}\ldots x_n$, | |
> where $y_1\ldots y_t$ is some nonempty sequence of character, ligature, and | |
> kern nodes. We call $x_j\ldots x_m$ a ``cut prefix'' of $x_j\ldots x_n$. | |
> For example, if $x_1x_2x_3=\.{fly}$, and if the font contains `fl' as a | |
> ligature and a kern between `fl' and `y', then $m=2$, $t=2$, and $y_1$ will | |
> be a ligature node for `fl' followed by an appropriate kern node~$y_2$. | |
> In the most common case, $x_j$~forms no ligature with $x_{j+1}$ and we | |
> simply have $m=j$, $y_1=x_j$. If $m<n$ we can repeat the procedure on | |
> $x_{m+1}\ldots x_n$ until the entire translation has been found. | |
> | |
> The |reconstitute| function returns the integer $m$ and puts the nodes | |
> $y_1\ldots y_t$ into a linked list starting at |link(hold_head)|, | |
> getting the input $x_j\ldots x_n$ from the |hu| array. If $x_j=256$, | |
> we consider $x_j$ to be an implicit left boundary character; in this | |
> case |j| must be strictly less than~|n|. There is a | |
> parameter |bchar|, which is either 256 or an implicit right boundary character | |
> assumed to be present just following~$x_n$. (The value |hu[n+1]| is never | |
> explicitly examined, but the algorithm imagines that |bchar| is there.) | |
> | |
> If there exists an index |k| in the range $j\le k\le m$ such that |hyf[k]| | |
> is odd and such that the result of |reconstitute| would have been different | |
> if $x_{k+1}$ had been |hchar|, then |reconstitute| sets |hyphen_passed| | |
> to the smallest such~|k|. Otherwise it sets |hyphen_passed| to zero. | |
> | |
> A special convention is used in the case |j=0|: Then we assume that the | |
> translation of |hu[0]| appears in a special list of charnodes starting at | |
> |init_list|; moreover, if |init_lig| is |true|, then |hu[0]| will be | |
> a ligature character, involving a left boundary if |init_lft| is |true|. | |
> This facility is provided for cases when a hyphenated | |
> word is preceded by punctuation (like single or double quotes) that might | |
> affect the translation of the beginning of the word. | |
14478,14479c17674,17675 | |
< function reconstitute(@!j,@!n:small_number): | |
< small_number; | |
--- | |
> function reconstitute(@!j,@!n:small_number;@!bchar,@!hchar:halfword): | |
> small_number; | |
14481,14482c17677,17678 | |
< var p:pointer; {a node being created} | |
< @!s:pointer; {a node being appended to} | |
--- | |
> var @!p:pointer; {temporary register for list manipulation} | |
> @!t:pointer; {a node being appended to} | |
14484,14485c17680,17681 | |
< @!c:quarterword; {current character} | |
< @!d:quarterword; {current character or ligature} | |
--- | |
> @!cur_rh:halfword; {hyphen character for ligature testing} | |
> @!test_char:halfword; {hyphen or other character for ligature testing} | |
14487,14503c17683,17709 | |
< @!r:0..font_mem_size; {position of current lig/kern instruction} | |
< begin @<Build a list of characters in a maximal ligature, and set |w| | |
< to the amount of kerning that should follow@>; | |
< @<If the list has more than one element, create a ligature node@>; | |
< @<Attach kerning, if |w≠0|@>; | |
< reconstitute←j; | |
< end; | |
< | |
< @ @<Build a list of characters in a maximal ligature...@>= | |
< hyphen_passed←0; s←hold_head; w←0; d←qi(hu[j]); c←d; | |
< loop@+ begin continue: p←get_avail; font(p)←hf; | |
< character(p)←c; link(s)←p;@/ | |
< @<Look for a ligature or kern between |d| and the following | |
< character; update the data structure and |goto continue| | |
< if a ligature is found, otherwise update@@|w| and |goto done|@>; | |
< end; | |
< done: | |
--- | |
> @!k:font_index; {position of current lig/kern instruction} | |
> begin hyphen_passed:=0; t:=hold_head; w:=0; link(hold_head):=null; | |
> {at this point |ligature_present=lft_hit=rt_hit=false|} | |
> @<Set up data structures with the cursor following position |j|@>; | |
> continue:@<If there's a ligature or kern at the cursor position, update the data | |
> structures, possibly advancing~|j|; continue until the cursor moves@>; | |
> @<Append a ligature and/or kern to the translation; | |
> |goto continue| if the stack of inserted ligatures is nonempty@>; | |
> reconstitute:=j; | |
> end; | |
> | |
> @ The reconstitution procedure shares many of the global data structures | |
> by which \TeX\ has processed the words before they were hyphenated. | |
> There is an implied ``cursor'' between characters |cur_l| and |cur_r|; | |
> these characters will be tested for possible ligature activity. If | |
> |ligature_present| then |cur_l| is a ligature character formed from the | |
> original characters following |cur_q| in the current translation list. | |
> There is a ``ligature stack'' between the cursor and character |j+1|, | |
> consisting of pseudo-ligature nodes linked together by their |link| fields. | |
> This stack is normally empty unless a ligature command has created a new | |
> character that will need to be processed later. A pseudo-ligature is | |
> a special node having a |character| field that represents a potential | |
> ligature and a |lig_ptr| field that points to a |char_node| or is |null|. | |
> We have | |
> $$|cur_r|=\cases{|character(lig_stack)|,&if |lig_stack>null|;\cr | |
> |qi(hu[j+1])|,&if |lig_stack=null| and |j<n|;\cr | |
> bchar,&if |lig_stack=null| and |j=n|.\cr}$$ | |
14505,14534c17711,17774 | |
< @ @<Look for a ligature or kern between |d| and...@>= | |
< if j=n then goto done; | |
< q←char_info(hf)(d); | |
< if char_tag(q)≠lig_tag then goto done; | |
< r←lig_kern_start(hf)(q); c←qi(hu[j+1]); | |
< loop@+ begin q←font_info[r].qqqq; | |
< if next_char(q)=c then | |
< begin if odd(hyf[j])∧(hyphen_passed=0) then hyphen_passed←j; | |
< if op_bit(q)<kern_flag then | |
< @<Append to the ligature and |goto continue|@> | |
< else begin w←char_kern(hf)(q); | |
< goto done; | |
< end; | |
< end | |
< else if stop_bit(q)<stop_flag then incr(r) | |
< else goto done; | |
< end | |
< | |
< @ @<Append to the ligature...@>= | |
< begin d←rem_byte(q); | |
< incr(j); s←p; goto continue; | |
< end | |
< | |
< @ After the list has been built, |link(s)| points to the final list element. | |
< | |
< @<If the list has more than one element, create a ligature node@>= | |
< if s≠hold_head then | |
< begin p←new_ligature(hf,d,link(hold_head)); | |
< link(hold_head)←p; | |
< end | |
--- | |
> @<Glob...@>= | |
> @!cur_l,@!cur_r:halfword; {characters before and after the cursor} | |
> @!cur_q:pointer; {where a ligature should be detached} | |
> @!lig_stack:pointer; {unfinished business to the right of the cursor} | |
> @!ligature_present:boolean; {should a ligature node be made for |cur_l|?} | |
> @!lft_hit,@!rt_hit:boolean; {did we hit a ligature with a boundary character?} | |
> | |
> @ @d append_charnode_to_t(#)== begin link(t):=get_avail; t:=link(t); | |
> font(t):=hf; character(t):=#; | |
> end | |
> @d set_cur_r==begin if j<n then cur_r:=qi(hu[j+1])@+else cur_r:=bchar; | |
> if odd(hyf[j]) then cur_rh:=hchar@+else cur_rh:=non_char; | |
> end | |
> | |
> @<Set up data structures with the cursor following position |j|@>= | |
> cur_l:=qi(hu[j]); cur_q:=t; | |
> if j=0 then | |
> begin ligature_present:=init_lig; p:=init_list; | |
> if ligature_present then lft_hit:=init_lft; | |
> while p>null do | |
> begin append_charnode_to_t(character(p)); p:=link(p); | |
> end; | |
> end | |
> else if cur_l<non_char then append_charnode_to_t(cur_l); | |
> lig_stack:=null; set_cur_r | |
> | |
> @ We may want to look at the lig/kern program twice, once for a hyphen | |
> and once for a normal letter. (The hyphen might appear after the letter | |
> in the program, so we'd better not try to look for both at once.) | |
> | |
> @<If there's a ligature or kern at the cursor position, update...@>= | |
> if cur_l=non_char then | |
> begin k:=bchar_label[hf]; | |
> if k=non_address then goto done@+else q:=font_info[k].qqqq; | |
> end | |
> else begin q:=char_info(hf)(cur_l); | |
> if char_tag(q)<>lig_tag then goto done; | |
> k:=lig_kern_start(hf)(q); q:=font_info[k].qqqq; | |
> if skip_byte(q)>stop_flag then | |
> begin k:=lig_kern_restart(hf)(q); q:=font_info[k].qqqq; | |
> end; | |
> end; {now |k| is the starting address of the lig/kern program} | |
> if cur_rh<non_char then test_char:=cur_rh@+else test_char:=cur_r; | |
> loop@+begin if next_char(q)=test_char then if skip_byte(q)<=stop_flag then | |
> if cur_rh<non_char then | |
> begin hyphen_passed:=j; hchar:=non_char; cur_rh:=non_char; | |
> goto continue; | |
> end | |
> else begin if hchar<non_char then if odd(hyf[j]) then | |
> begin hyphen_passed:=j; hchar:=non_char; | |
> end; | |
> if op_byte(q)<kern_flag then | |
> @<Carry out a ligature replacement, updating the cursor structure | |
> and possibly advancing~|j|; |goto continue| if the cursor doesn't | |
> advance, otherwise |goto done|@>; | |
> w:=char_kern(hf)(q); goto done; {this kern will be inserted below} | |
> end; | |
> if skip_byte(q)>=stop_flag then | |
> if cur_rh=non_char then goto done | |
> else begin cur_rh:=non_char; goto continue; | |
> end; | |
> k:=k+qo(skip_byte(q))+1; q:=font_info[k].qqqq; | |
> end; | |
> done: | |
14536,14537c17776,17836 | |
< @ @<Attach kerning, if |w≠0|@>= | |
< if w≠0 then link(link(hold_head))←new_kern(w) | |
--- | |
> @ @d wrap_lig(#)==if ligature_present then | |
> begin p:=new_ligature(hf,cur_l,link(cur_q)); | |
> if lft_hit then | |
> begin subtype(p):=2; lft_hit:=false; | |
> end; | |
> if # then if lig_stack=null then | |
> begin incr(subtype(p)); rt_hit:=false; | |
> end; | |
> link(cur_q):=p; t:=p; ligature_present:=false; | |
> end | |
> @d pop_lig_stack==begin if lig_ptr(lig_stack)>null then | |
> begin link(t):=lig_ptr(lig_stack); {this is a charnode for |hu[j+1]|} | |
> t:=link(t); incr(j); | |
> end; | |
> p:=lig_stack; lig_stack:=link(p); free_node(p,small_node_size); | |
> if lig_stack=null then set_cur_r@+else cur_r:=character(lig_stack); | |
> end {if |lig_stack| isn't |null| we have |cur_rh=non_char|} | |
> | |
> @<Append a ligature and/or kern to the translation...@>= | |
> wrap_lig(rt_hit); | |
> if w<>0 then | |
> begin link(t):=new_kern(w); t:=link(t); w:=0; | |
> end; | |
> if lig_stack>null then | |
> begin cur_q:=t; cur_l:=character(lig_stack); ligature_present:=true; | |
> pop_lig_stack; goto continue; | |
> end | |
> | |
> @ @<Carry out a ligature replacement, updating the cursor structure...@>= | |
> begin if cur_l=non_char then lft_hit:=true; | |
> if j=n then if lig_stack=null then rt_hit:=true; | |
> check_interrupt; {allow a way out in case there's an infinite ligature loop} | |
> case op_byte(q) of | |
> qi(1),qi(5):begin cur_l:=rem_byte(q); {\.{=:\?}, \.{=:\?>}} | |
> ligature_present:=true; | |
> end; | |
> qi(2),qi(6):begin cur_r:=rem_byte(q); {\.{\?=:}, \.{\?=:>}} | |
> if lig_stack>null then character(lig_stack):=cur_r | |
> else begin lig_stack:=new_lig_item(cur_r); | |
> if j=n then bchar:=non_char | |
> else begin p:=get_avail; lig_ptr(lig_stack):=p; | |
> character(p):=qi(hu[j+1]); font(p):=hf; | |
> end; | |
> end; | |
> end; | |
> qi(3):begin cur_r:=rem_byte(q); {\.{\?=:\?}} | |
> p:=lig_stack; lig_stack:=new_lig_item(cur_r); link(lig_stack):=p; | |
> end; | |
> qi(7),qi(11):begin wrap_lig(false); {\.{\?=:\?>}, \.{\?=:\?>>}} | |
> cur_q:=t; cur_l:=rem_byte(q); ligature_present:=true; | |
> end; | |
> othercases begin cur_l:=rem_byte(q); ligature_present:=true; {\.{=:}} | |
> if lig_stack>null then pop_lig_stack | |
> else if j=n then goto done | |
> else begin append_charnode_to_t(cur_r); incr(j); set_cur_r; | |
> end; | |
> end | |
> endcases; | |
> if op_byte(q)>qi(4) then if op_byte(q)<>qi(7) then goto done; | |
> goto continue; | |
> end | |
14541,14542c17840,17841 | |
< |hu[1..hn]| after node |s|, and node |q| should be appended to the result. | |
< During this process, the variable |i| will be a temporary counter or an | |
--- | |
> |hu[1..hn]| after node |ha|, and node |q| should be appended to the result. | |
> During this process, the variable |i| will be a temporary | |
14546c17845 | |
< we need two new local variables: | |
--- | |
> we need a few new local variables: | |
14550c17849,17853 | |
< discretionary branches being reconstructed} | |
--- | |
> discretionary branches being reconstructed} | |
> @!c:ASCII_code; {character temporarily replaced by a hyphen} | |
> @!c_loc:0..63; {where that character came from} | |
> @!r_count:integer; {replacement count for discretionary} | |
> @!hyf_node:pointer; {the hyphen, if it exists} | |
14552,14553c17855 | |
< @ When the following code is performed, |hyf[j]| will be zero for |j=1| | |
< and for |j≥hn-2|. | |
--- | |
> @ When the following code is performed, |hyf[0]| and |hyf[hn]| will be zero. | |
14556,14575c17858,17889 | |
< j←0; | |
< repeat l←j; j←reconstitute(j+1,hn); | |
< if hyphen_passed≠0 then | |
< @<Create and append a discretionary node as an alternative to the | |
< ligature, and continue to develop both branches until they | |
< become equivalent@> | |
< else begin link(s)←link(hold_head); s←link(s); | |
< if link(s)≠null then s←link(s); | |
< end; | |
< if odd(hyf[j]) then @<Insert a discretionary hyphen after |s|@>; | |
< until j=hn; | |
< link(s)←q | |
< | |
< @ @<Create and append a discretionary node as an alternative...@>= | |
< begin r←get_node(small_node_size); | |
< link(s)←r; link(r)←link(hold_head); type(r)←disc_node; | |
< major_tail←link(hold_head); | |
< if link(major_tail)≠null then major_tail←link(major_tail); | |
< i←hyphen_passed; | |
< @<Put the \(c)characters |hu[l+1..i]| and a hyphen into |pre_break(r)|@>; | |
--- | |
> repeat l:=j; j:=reconstitute(j,hn,bchar,qi(hyf_char))+1; | |
> if hyphen_passed=0 then | |
> begin link(s):=link(hold_head); | |
> while link(s)>null do s:=link(s); | |
> if odd(hyf[j-1]) then | |
> begin l:=j; hyphen_passed:=j-1; link(hold_head):=null; | |
> end; | |
> end; | |
> if hyphen_passed>0 then | |
> @<Create and append a discretionary node as an alternative to the | |
> unhyphenated word, and continue to develop both branches until they | |
> become equivalent@>; | |
> until j>hn; | |
> link(s):=q | |
> | |
> @ In this repeat loop we will insert another discretionary if |hyf[j-1]| is | |
> odd, when both branches of the previous discretionary end at position |j-1|. | |
> Strictly speaking, we aren't justified in doing this, because we don't know | |
> that a hyphen after |j-1| is truly independent of those branches. But in almost | |
> all applications we would rather not lose a potentially valuable hyphenation | |
> point. (Consider the word `difficult', where the letter `c' is in position |j|.) | |
> | |
> @d advance_major_tail==begin major_tail:=link(major_tail); incr(r_count); | |
> end | |
> | |
> @<Create and append a discretionary node as an alternative...@>= | |
> repeat r:=get_node(small_node_size); | |
> link(r):=link(hold_head); type(r):=disc_node; | |
> major_tail:=r; r_count:=0; | |
> while link(major_tail)>null do advance_major_tail; | |
> i:=hyphen_passed; hyf[i]:=0; | |
> @<Put the \(c)characters |hu[l..i]| and a hyphen into |pre_break(r)|@>; | |
14577c17891 | |
< list and to |major_tail| until synchronization has been achieved@>; | |
--- | |
> list and to |major_tail| until synchronization has been achieved@>; | |
14579,14580c17893,17895 | |
< appropriately@>; | |
< end | |
--- | |
> appropriately@>; | |
> hyphen_passed:=j-1; link(hold_head):=null; | |
> until not odd(hyf[j-1]) | |
14583c17898 | |
< or kern. At this point we have |i≤j|. | |
--- | |
> or kern. At this point we have |l-1<=i<j| and |i<hn|. | |
14585,14594c17900,17917 | |
< @<Put the \(c)characters |hu[l+1..i]| and a hyphen into |pre_break(r)|@>= | |
< minor_tail←null; c←hu[i+1]; hu[i+1]←"-"; | |
< repeat l←reconstitute(l+1,i+1); | |
< if minor_tail=null then pre_break(r)←link(hold_head) | |
< else link(minor_tail)←link(hold_head); | |
< minor_tail←link(hold_head); | |
< if link(minor_tail)≠null then minor_tail←link(minor_tail); | |
< until l>i; | |
< hu[i+1]←c; {restore the character in the hyphen position} | |
< decr(l); hyf[l]←0 | |
--- | |
> @<Put the \(c)characters |hu[l..i]| and a hyphen into |pre_break(r)|@>= | |
> minor_tail:=null; pre_break(r):=null; hyf_node:=new_character(hf,hyf_char); | |
> if hyf_node<>null then | |
> begin incr(i); c:=hu[i]; hu[i]:=hyf_char; free_avail(hyf_node); | |
> end; | |
> while l<=i do | |
> begin l:=reconstitute(l,i,font_bchar[hf],non_char)+1; | |
> if link(hold_head)>null then | |
> begin if minor_tail=null then pre_break(r):=link(hold_head) | |
> else link(minor_tail):=link(hold_head); | |
> minor_tail:=link(hold_head); | |
> while link(minor_tail)>null do minor_tail:=link(minor_tail); | |
> end; | |
> end; | |
> if hyf_node<>null then | |
> begin hu[i]:=c; {restore the character in the hyphen position} | |
> l:=i; decr(i); | |
> end | |
14596c17919 | |
< @ The synchronization algorithm begins with |l≤j|. | |
--- | |
> @ The synchronization algorithm begins with |l=i+1<=j|. | |
14599c17922,17925 | |
< minor_tail←null; post_break(r)←null; | |
--- | |
> minor_tail:=null; post_break(r):=null; c_loc:=0; | |
> if bchar_label[hf]<>non_address then {put left boundary at beginning of new line} | |
> begin decr(l); c:=hu[l]; c_loc:=l; hu[l]:=256; | |
> end; | |
14601,14632c17927,17960 | |
< begin repeat l←reconstitute(l+1,hn); | |
< if minor_tail=null then post_break(r)←link(hold_head) | |
< else link(minor_tail)←link(hold_head); | |
< minor_tail←link(hold_head); | |
< if link(minor_tail)≠null then | |
< begin hyf[l]←0; minor_tail←link(minor_tail); {kern present} | |
< end; | |
< until l≥j; | |
< while l>j do | |
< begin j←reconstitute(j+1,hn); | |
< link(major_tail)←link(hold_head); | |
< major_tail←link(hold_head); | |
< if link(major_tail)≠null then | |
< begin hyf[j]←0; major_tail←link(major_tail); {kern present} | |
< end; | |
< end; | |
< end | |
< | |
< @ @<Move pointer |s| to the end of the current list...@>= | |
< i←0; s←r; | |
< while link(s)≠null do | |
< begin incr(i); s←link(s); | |
< end; | |
< replace_count(r)←i | |
< | |
< @ At this point |link(s)| is |null|. | |
< | |
< @<Insert a discretionary hyphen after |s|@>= | |
< begin r←new_disc; pre_break(r)←new_character(hf,"-"); | |
< link(s)←r; s←r; | |
< end | |
< @* \[41] Hyphenation. | |
--- | |
> begin repeat l:=reconstitute(l,hn,bchar,non_char)+1; | |
> if c_loc>0 then | |
> begin hu[c_loc]:=c; c_loc:=0; | |
> end; | |
> if link(hold_head)>null then | |
> begin if minor_tail=null then post_break(r):=link(hold_head) | |
> else link(minor_tail):=link(hold_head); | |
> minor_tail:=link(hold_head); | |
> while link(minor_tail)>null do minor_tail:=link(minor_tail); | |
> end; | |
> until l>=j; | |
> while l>j do | |
> @<Append characters of |hu[j..@,]| to |major_tail|, advancing~|j|@>; | |
> end | |
> | |
> @ @<Append characters of |hu[j..@,]|...@>= | |
> begin j:=reconstitute(j,hn,bchar,non_char)+1; | |
> link(major_tail):=link(hold_head); | |
> while link(major_tail)>null do advance_major_tail; | |
> end | |
> | |
> @ Ligature insertion can cause a word to grow exponentially in size. Therefore | |
> we must test the size of |r_count| here, even though the hyphenated text | |
> was at most 63 characters long. | |
> | |
> @<Move pointer |s| to the end of the current list...@>= | |
> if r_count>127 then {we have to forget the discretionary hyphen} | |
> begin link(s):=link(r); link(r):=null; flush_node_list(r); | |
> end | |
> else begin link(s):=r; replace_count(r):=r_count; | |
> end; | |
> s:=major_tail | |
> | |
> @* \[42] Hyphenation. | |
14636c17964 | |
< using an algorithm due to Frank M. Liang. | |
--- | |
> using an algorithm due to Frank~M. Liang. | |
14641c17969 | |
< for all |j|, and invalid `\.{\^\^?}' characters are inserted into |hc[0]| | |
--- | |
> for all |j|, and invalid characters are inserted into |hc[0]| | |
14644,14647c17972,17975 | |
< |hc[0..(hn+1)]|. Each pattern $p↓1\ldotsm p↓k$ of length |k| has an associated | |
< sequence of |k+1| numbers $n↓0\ldotsm n↓k$; and if the pattern occurs in | |
< |hc[(j+1)..(j+k)]|, \TeX\ will set |hyf[j+i]←@tmax@>(hyf[j+i],@t$n↓i$@>)| for | |
< |0≤i≤k|. After this has been done for each pattern that occurs, a | |
--- | |
> |hc[0..(hn+1)]|. Each pattern $p_1\ldots p_k$ of length |k| has an associated | |
> sequence of |k+1| numbers $n_0\ldots n_k$; and if the pattern occurs in | |
> |hc[(j+1)..(j+k)]|, \TeX\ will set |hyf[j+i]:=@tmax@>(hyf[j+i],@t$n_i$@>)| for | |
> |0<=i<=k|. After this has been done for each pattern that occurs, a | |
14651c17979 | |
< The set of patterns $p↓1\ldotsm p↓k$ and associated numbers $n↓0\ldotsm n↓k$ | |
--- | |
> The set of patterns $p_1\ldots p_k$ and associated numbers $n_0\ldots n_k$ | |
14656c17984 | |
< 1982); \TeX\ simply starts with the patterns and works from there. | |
--- | |
> 1983); \TeX\ simply starts with the patterns and works from there. | |
14660,14663c17988,17992 | |
< Computer Program\-ming \bf3} (1973), 481--505]. We can find each pattern | |
< $p↓1\ldotsm p↓k$ by setting |@t$z↓1$@>←@t$p↓1$@>| and then, for |1<i≤k|, | |
< setting |@t$z↓i$@>←trie_link@t$(z↓{i-1})+p↓i$@>|; the pattern will be | |
< identified by the number $z↓k$. Since all the pattern information is | |
--- | |
> Computer Programming \bf3} (1973), 481--505]. We can find each pattern | |
> $p_1\ldots p_k$ by letting $z_0$ be one greater than the relevant language | |
> index and then, for |1<=i<=k|, | |
> setting |@t$z_i$@>:=trie_link@t$(z_{i-1})+p_i$@>|; the pattern will be | |
> identified by the number $z_k$. Since all the pattern information is | |
14666,14668c17995,17997 | |
< table is provided such that |trie_char@t$(z↓i)=p↓i$@>| for all |i|. There | |
< is also a table |trie_op|$(z↓k)$ to identify the numbers $n↓0\ldotsm n↓k$ | |
< associated with $p↓1\ldotsm p↓k$. | |
--- | |
> table is provided such that |trie_char@t$(z_i)=p_i$@>| for all |i|. There | |
> is also a table |trie_op|$(z_k)$ to identify the numbers $n_0\ldots n_k$ | |
> associated with $p_1\ldots p_k$. | |
14670c17999 | |
< Comparatively few different number sequences $n↓0\ldotsm n↓k$ actually occur, | |
--- | |
> Comparatively few different number sequences $n_0\ldots n_k$ actually occur, | |
14672,14674c18001,18004 | |
< are encoded in such a way that |trie_op|$(z↓k)$ is only one byte long. | |
< If |trie_op(@t$z↓k$@>)≠min_quarterword|, when $p↓1\ldotsm p↓k$ has matched | |
< the letters in |hc[(l-k+1)..l@,]|, we perform all of the required operations | |
--- | |
> are encoded in such a way that |trie_op|$(z_k)$ is only one byte long. | |
> If |trie_op(@t$z_k$@>)<>min_quarterword|, when $p_1\ldots p_k$ has matched | |
> the letters in |hc[(l-k+1)..l@,]| of language |t|, | |
> we perform all of the required operations | |
14676,14678c18006,18008 | |
< |v←trie_op(@t$z↓k$@>)|. Then set |hyf[l-hyf_distance[v]]←@tmax@>( | |
< hyf[l-hyf_distance[v]], hyf_num[v])|, and |v←hyf_next[v]|; repeat, if | |
< necessary, until |v=min_quarterword|. | |
--- | |
> |v:=trie_op(@t$z_k$@>)|. Then set |v:=v+op_start[t]|, | |
> |hyf[l-hyf_distance[v]]:=@tmax@>(hyf[l-hyf_distance[v]], hyf_num[v])|, | |
> and |v:=hyf_next[v]|; repeat, if necessary, until |v=min_quarterword|. | |
14689,14691c18019,18022 | |
< @!hyf_distance:array[quarterword] of small_number; {position |k-j| of $n↓j$} | |
< @!hyf_num:array[quarterword] of small_number; {value of $n↓j$} | |
< @!hyf_next:array[quarterword] of quarterword; {continuation of this |trie_op|} | |
--- | |
> @!hyf_distance:array[1..trie_op_size] of small_number; {position |k-j| of $n_j$} | |
> @!hyf_num:array[1..trie_op_size] of small_number; {value of $n_j$} | |
> @!hyf_next:array[1..trie_op_size] of quarterword; {continuation code} | |
> @!op_start:array[ASCII_code] of 0..trie_op_size; {offset for current language} | |
14695c18026 | |
< @!v:quarterword; {an index into |hyf_distance|, etc.} | |
--- | |
> @!v:integer; {an index into |hyf_distance|, etc.} | |
14697,14700c18028,18031 | |
< @ Assuming that these auxiliary tables have been set properly, the | |
< hyphenation algorithm is quite short. In the following code we use the | |
< fact that no pattern contains $p↓i=0$; setting |hc[hn+2]| to zero therefore | |
< guarantees that |hc[hn+3]| will never be fetched. | |
--- | |
> @ Assuming that these auxiliary tables have been set up properly, the | |
> hyphenation algorithm is quite short. In the following code we set |hc[hn+2]| | |
> to the impossible value 256, in order to guarantee that |hc[hn+3]| will | |
> never be fetched. | |
14702,14703c18033,18034 | |
< @<Find hyphen locations for the word in |hc|@>= | |
< for j←0 to hn do hyf[j]←0; | |
--- | |
> @<Find hyphen locations for the word in |hc|...@>= | |
> for j:=0 to hn do hyf[j]:=0; | |
14705,14715c18036,18048 | |
< |hyf| containing the hyphens) if an entry is found@>; | |
< hc[0]←127; hc[hn+1]←127; hc[hn+2]←0; {insert delimiters} | |
< for j←0 to hn-2 do | |
< begin z←hc[j]; l←j; | |
< while hc[l]=trie_char(z) do | |
< begin if trie_op(z)≠min_quarterword then | |
< @<Store \(m)maximum values in the |hyf| table@>; | |
< incr(l); z←trie_link(z)+hc[l]; | |
< end; | |
< end; | |
< found: hyf[1]←0; hyf[hn-2]←0; hyf[hn-1]←0; hyf[hn]←0 | |
--- | |
> |hyf| containing the hyphens) if an entry is found@>; | |
> if trie_char(cur_lang+1)<>qi(cur_lang) then return; {no patterns for |cur_lang|} | |
> hc[0]:=0; hc[hn+1]:=0; hc[hn+2]:=256; {insert delimiters} | |
> for j:=0 to hn-r_hyf+1 do | |
> begin z:=trie_link(cur_lang+1)+hc[j]; l:=j; | |
> while hc[l]=qo(trie_char(z)) do | |
> begin if trie_op(z)<>min_quarterword then | |
> @<Store \(m)maximum values in the |hyf| table@>; | |
> incr(l); z:=trie_link(z)+hc[l]; | |
> end; | |
> end; | |
> found: for j:=0 to l_hyf-1 do hyf[j]:=0; | |
> for j:=0 to r_hyf-1 do hyf[hn-j]:=0 | |
14718,14721c18051,18054 | |
< begin v←trie_op(z); | |
< repeat i←l-hyf_distance[v]; | |
< if hyf_num[v]>hyf[i] then hyf[i]←hyf_num[v]; | |
< v←hyf_next[v]; | |
--- | |
> begin v:=trie_op(z); | |
> repeat v:=v+op_start[cur_lang]; i:=l-hyf_distance[v]; | |
> if hyf_num[v]>hyf[i] then hyf[i]:=hyf_num[v]; | |
> v:=hyf_next[v]; | |
14728,14732c18061,18065 | |
< Journal\/\ \bf17} (1974), 135--142] using linear probing. If $\alpha$ and | |
< $\beta$ are words, we will say that $\alpha<\beta$ if $\leftv\alpha\rightv< | |
< \leftv\beta\rightv$ or if $\leftv\alpha\rightv=\leftv\beta\rightv$ and | |
< $\alpha$ is lexicographically smaller than $\beta$. (The notation $\leftv | |
< \alpha\rightv$ stands for the length of $\alpha$.) The idea of ordered hashing | |
--- | |
> Journal\/ \bf17} (1974), 135--142] using linear probing. If $\alpha$ and | |
> $\beta$ are words, we will say that $\alpha<\beta$ if $\vert\alpha\vert< | |
> \vert\beta\vert$ or if $\vert\alpha\vert=\vert\beta\vert$ and | |
> $\alpha$ is lexicographically smaller than $\beta$. (The notation $\vert | |
> \alpha\vert$ stands for the length of $\alpha$.) The idea of ordered hashing | |
14734,14735c18067,18068 | |
< a hash address $h=h(\alpha)$ and then looking in table positions $h$, $h-1$, | |
< $\ldotss$, until encountering the first word $\L\alpha$. If this word is | |
--- | |
> a hash address $h=h(\alpha)$ and then looking in table positions |h|, |h-1|, | |
> \dots, until encountering the first word $\L\alpha$. If this word is | |
14739,14741c18072,18074 | |
< in their |info| fields. The list for $c↓1\ldotsm c↓n$ contains $k$ if | |
< the word $c↓1\ldotsm c↓n$ has a discretionary hyphen between $c↓k$ and | |
< $c↓{k+1}$. | |
--- | |
> in their |info| fields. The list for $c_1\ldots c_n$ contains the number |k| if | |
> the word $c_1\ldots c_n$ has a discretionary hyphen between $c_k$ and | |
> $c_{k+1}$. | |
14748c18081 | |
< @!hyph_list:array[hyph_pointer] of pointer; {list of hyphen positions} | |
--- | |
> @!hyph_list:array[hyph_pointer] of pointer; {lists of hyphen positions} | |
14755,14756c18088,18091 | |
< for z←0 to hyph_size do hyph_word[z]←0; | |
< hyph_count←0; | |
--- | |
> for z:=0 to hyph_size do | |
> begin hyph_word[z]:=0; hyph_list[z]:=null; | |
> end; | |
> hyph_count:=0; | |
14767c18102,18103 | |
< find the word or we don't. | |
--- | |
> find the word or we don't. Words from different languages are kept | |
> separate by appending the language code to the string. | |
14770,14777c18106,18113 | |
< h←hc[1]; | |
< for j←2 to hn do h←(h+h+hc[j]) mod hyph_size; | |
< loop@+ begin @<If the string |hyph_word[h]| is less than \(hc)|hc[1..hn]|, | |
< |goto not_found|; but if the two strings are equal, | |
< set |hyf| to the hyphen positions and |goto found|@>; | |
< if h>0 then decr(h)@+else h←hyph_size; | |
< end; | |
< not_found: | |
--- | |
> h:=hc[1]; incr(hn); hc[hn]:=cur_lang; | |
> for j:=2 to hn do h:=(h+h+hc[j]) mod hyph_size; | |
> loop@+ begin @<If the string |hyph_word[h]| is less than \(hc)|hc[1..hn]|, | |
> |goto not_found|; but if the two strings are equal, | |
> set |hyf| to the hyphen positions and |goto found|@>; | |
> if h>0 then decr(h)@+else h:=hyph_size; | |
> end; | |
> not_found: decr(hn) | |
14780c18116 | |
< k←hyph_word[h]; if k=0 then goto not_found; | |
--- | |
> k:=hyph_word[h]; if k=0 then goto not_found; | |
14783,14790c18119,18126 | |
< begin j←1; u←str_start[k]; | |
< repeat if str_pool[u]<hc[j] then goto not_found; | |
< if str_pool[u]>hc[j] then goto done; | |
< incr(j); incr(u); | |
< until j>hn; | |
< @<Insert hyphens as specified in |hyph_list[h]|@>; | |
< goto found; | |
< end; | |
--- | |
> begin j:=1; u:=str_start[k]; | |
> repeat if so(str_pool[u])<hc[j] then goto not_found; | |
> if so(str_pool[u])>hc[j] then goto done; | |
> incr(j); incr(u); | |
> until j>hn; | |
> @<Insert hyphens as specified in |hyph_list[h]|@>; | |
> decr(hn); goto found; | |
> end; | |
14794,14797c18130,18140 | |
< s←hyph_list[h]; | |
< while s≠null do | |
< begin hyf[info(s)]←1; s←link(s); | |
< end | |
--- | |
> s:=hyph_list[h]; | |
> while s<>null do | |
> begin hyf[info(s)]:=1; s:=link(s); | |
> end | |
> | |
> @ @<Search |hyph_list| for pointers to |p|@>= | |
> for q:=0 to hyph_size do | |
> begin if hyph_list[q]=p then | |
> begin print_nl("HYPH("); print_int(q); print_char(")"); | |
> end; | |
> end | |
14803,14804c18146,18151 | |
< When \TeX\ has scanned the `\.{\\hyphenation}' control sequence, it calls | |
< on a procedure named |new_hyph_exceptions| to do the right thing. | |
--- | |
> When \TeX\ has scanned `\.{\\hyphenation}', it calls on a procedure named | |
> |new_hyph_exceptions| to do the right thing. | |
> | |
> @d set_cur_lang==if language<=0 then cur_lang:=0 | |
> else if language>255 then cur_lang:=0 | |
> else cur_lang:=language | |
14807,14809c18154,18156 | |
< label exit, found, not_found; | |
< var n:small_number; {length of current word} | |
< @!j:small_number; {an index into |hc|} | |
--- | |
> label reswitch, exit, found, not_found; | |
> var n:0..64; {length of current word; not always a |small_number|} | |
> @!j:0..64; {an index into |hc|} | |
14816a18164 | |
> set_cur_lang; | |
14818c18166 | |
< until coming to a right brace; then skip an optional space and |return|@>; | |
--- | |
> until coming to a right brace; then |return|@>; | |
14822,14834c18170,18183 | |
< n←0; p←null; | |
< loop@+ begin get_nc_token; | |
< case cur_cmd of | |
< letter,other_char:@<Append a new letter or hyphen@>; | |
< spacer,right_brace: begin if n>4 then @<Enter a hyphenation exception@>; | |
< if cur_cmd=right_brace then | |
< begin @<Scan an optional space@>; return; | |
< end; | |
< n←0; p←null; | |
< end; | |
< othercases @<Give improper \.{\\hyphenation} error@> | |
< endcases; | |
< end | |
--- | |
> n:=0; p:=null; | |
> loop@+ begin get_x_token; | |
> reswitch: case cur_cmd of | |
> letter,other_char,char_given:@<Append a new letter or hyphen@>; | |
> char_num: begin scan_char_num; cur_chr:=cur_val; cur_cmd:=char_given; | |
> goto reswitch; | |
> end; | |
> spacer,right_brace: begin if n>1 then @<Enter a hyphenation exception@>; | |
> if cur_cmd=right_brace then return; | |
> n:=0; p:=null; | |
> end; | |
> othercases @<Give improper \.{\\hyphenation} error@> | |
> endcases; | |
> end | |
14837,14839c18186 | |
< begin help2("Hyphenation exceptions must contain only letters")@/ | |
< ("and hyphens. But continue; I'll forgive and forget."); | |
< print_nl("! Improper \hyphenation will be flushed"); error; | |
--- | |
> begin print_err("Improper "); print_esc("hyphenation"); | |
14840a18188,18191 | |
> print(" will be flushed"); | |
> help2("Hyphenation exceptions must contain only letters")@/ | |
> ("and hyphens. But continue; I'll forgive and forget."); | |
> error; | |
14845,14846c18196,18197 | |
< else begin if lc_code(cur_chr)=0 then | |
< begin print_nl("! Not a letter"); | |
--- | |
> else begin if lc_code(cur_chr)=0 then | |
> begin print_err("Not a letter"); | |
14848,14855c18199,18206 | |
< help2("Letters in \hyphenation words must have \lccode>0.")@/ | |
< ("Proceed; I'll ignore the character I just read."); | |
< error; | |
< end | |
< else if n<63 then | |
< begin incr(n); hc[n]←lc_code(cur_chr); | |
< end; | |
< end | |
--- | |
> help2("Letters in \hyphenation words must have \lccode>0.")@/ | |
> ("Proceed; I'll ignore the character I just read."); | |
> error; | |
> end | |
> else if n<63 then | |
> begin incr(n); hc[n]:=lc_code(cur_chr); | |
> end; | |
> end | |
14858,14860c18209,18211 | |
< begin if n>1 then | |
< begin q←get_avail; link(q)←p; info(q)←n; p←q; | |
< end; | |
--- | |
> begin if n<63 then | |
> begin q:=get_avail; link(q):=p; info(q):=n; p:=q; | |
> end; | |
14864,14872c18215,18220 | |
< begin str_room(n); h←0; | |
< for j←1 to n do | |
< begin h←(h+h+hc[j]) mod hyph_size; | |
< append_char(hc[j]); | |
< end; | |
< s←make_string; | |
< while info(p)>n-3 do {eliminate hyphens \TeX\ doesn't like} | |
< begin q←link(p); free_avail(p); p←q; | |
< end; | |
--- | |
> begin incr(n); hc[n]:=cur_lang; str_room(n); h:=0; | |
> for j:=1 to n do | |
> begin h:=(h+h+hc[j]) mod hyph_size; | |
> append_char(hc[j]); | |
> end; | |
> s:=make_string; | |
14877a18226 | |
> @:TeX capacity exceeded exception dictionary}{\quad exception dictionary@> | |
14879,14884c18228,18233 | |
< while hyph_word[h]≠0 do | |
< begin @<If the string |hyph_word[h]| is less than \(or)or equal to | |
< |s|, interchange |(hyph_word[h],hyph_list[h])| with |(s,p)|@>; | |
< if h>0 then decr(h)@+else h←hyph_size; | |
< end; | |
< hyph_word[h]←s; hyph_list[h]←p | |
--- | |
> while hyph_word[h]<>0 do | |
> begin @<If the string |hyph_word[h]| is less than \(or)or equal to | |
> |s|, interchange |(hyph_word[h],hyph_list[h])| with |(s,p)|@>; | |
> if h>0 then decr(h)@+else h:=hyph_size; | |
> end; | |
> hyph_word[h]:=s; hyph_list[h]:=p | |
14887c18236 | |
< k←hyph_word[h]; | |
--- | |
> k:=hyph_word[h]; | |
14890c18239 | |
< u←str_start[k]; v←str_start[s]; | |
--- | |
> u:=str_start[k]; v:=str_start[s]; | |
14895,14896c18244,18245 | |
< found:q←hyph_list[h]; hyph_list[h]←p; p←q;@/ | |
< t←hyph_word[h]; hyph_word[h]←s; s←t; | |
--- | |
> found:q:=hyph_list[h]; hyph_list[h]:=p; p:=q;@/ | |
> t:=hyph_word[h]; hyph_word[h]:=s; s:=t; | |
14898c18247,18248 | |
< @* \[42] Initializing the hyphenation tables. | |
--- | |
> | |
> @* \[43] Initializing the hyphenation tables. | |
14900c18250 | |
< patterns following a \.{\\patterns} speci\-fi\-ca\-tion. Such a specification | |
--- | |
> patterns following a \.{\\patterns} specification. Such a specification | |
14905,14907c18255,18258 | |
< The initialization first builds a trie that is linked instead of packed | |
< into sequential storage, so that insertions are readily made. Then it | |
< compresses the linked trie by identifying common subtries, and finally the | |
--- | |
> The first step is to build a trie that is linked, instead of packed | |
> into sequential storage, so that insertions are readily made. | |
> After all patterns have been processed, \.{INITEX} | |
> compresses the linked trie by identifying common subtries. Finally the | |
14911c18262,18263 | |
< @p init @<Declare procedures for preprocessing hyphenation patterns@>@; | |
--- | |
> @<Declare subprocedures for |line_break|@>= | |
> @!init @<Declare procedures for preprocessing hyphenation patterns@>@; | |
14918c18270 | |
< a pattern of length 5, with $n↓0\ldotsm n↓5=0\,0\,2\,0\,0\,1$ in the | |
--- | |
> a pattern of length 5, with $n_0\ldots n_5=0\,0\,2\,0\,0\,1$ in the | |
14927,14928c18279,18280 | |
< $$\hbox{|@t$v^\prime$@>←new_trie_op(0,1,min_quarterword)|,\qquad | |
< |v←new_trie_op(3,2,@t$v^\prime$@>)|.}$$ | |
--- | |
> $$\hbox{|@t$v^\prime$@>:=new_trie_op(0,1,min_quarterword)|,\qquad | |
> |v:=new_trie_op(3,2,@t$v^\prime$@>)|.}$$ | |
14931c18283 | |
< three have not appeared before. | |
--- | |
> three have not appeared before for the current language. | |
14934,14938c18286 | |
< is |trie_op_ptr|. If the table overflows, the excess ops are ignored, | |
< and |trie_op_ptr=max_quarterword|. | |
< | |
< @d quarterword_diff=max_quarterword-min_quarterword | |
< @d trie_op_hash_size=quarterword_diff+quarterword_diff {double} | |
--- | |
> is |trie_op_ptr|. | |
14941,14943c18289,18297 | |
< init@! trie_op_hash:array[0..trie_op_hash_size] of quarterword; | |
< {trie op codes for triples} | |
< @t\hskip1em@>@!trie_op_ptr:quarterword; {highest |trie_op| assigned} | |
--- | |
> @!init@! trie_op_hash:array[-trie_op_size..trie_op_size] of 0..trie_op_size; | |
> {trie op codes for quadruples} | |
> @!trie_used:array[ASCII_code] of quarterword; | |
> {largest opcode used so far for this language} | |
> @!trie_op_lang:array[1..trie_op_size] of ASCII_code; | |
> {language part of a hashed quadruple} | |
> @!trie_op_val:array[1..trie_op_size] of quarterword; | |
> {opcode corresponding to a hashed quadruple} | |
> @!trie_op_ptr:0..trie_op_size; {number of stored ops so far} | |
14946,14949c18300,18305 | |
< @ The hash function used by |new_trie_op| is based on the idea that | |
< 313/510 is an approximation to the golden ratio [cf.\ {\sl The Art of | |
< Computer Programming \bf3} (1973), 510--512]; but the choice is | |
< comparatively unimportant in this particular application. | |
--- | |
> @ It's tempting to remove the |overflow| stops in the following procedure; | |
> |new_trie_op| could return |min_quarterword| (thereby simply ignoring | |
> part of a hyphenation pattern) instead of aborting the job. However, that would | |
> lead to different hyphenation results on different installations of \TeX\ | |
> using the same patterns. The |overflow| stops are necessary for portability | |
> of patterns. | |
14954c18310 | |
< var h:0..trie_op_hash_size; {trial hash location} | |
--- | |
> var h:-trie_op_size..trie_op_size; {trial hash location} | |
14956,14972c18312,18334 | |
< begin h←(n+313*d+361*v) mod trie_op_hash_size; | |
< loop@+ begin u←trie_op_hash[h]; | |
< if u=min_quarterword then {empty position found} | |
< begin if trie_op_ptr≥max_quarterword-1 then {overflow} | |
< begin trie_op_ptr←max_quarterword; | |
< new_trie_op←min_quarterword; return; | |
< end; | |
< incr(trie_op_ptr); hyf_distance[trie_op_ptr]←d; | |
< hyf_num[trie_op_ptr]←n; hyf_next[trie_op_ptr]←v; | |
< trie_op_hash[h]←trie_op_ptr; | |
< new_trie_op←trie_op_ptr; return; | |
< end; | |
< if (hyf_distance[u]=d)∧(hyf_num[u]=n)∧(hyf_next[u]=v) then | |
< begin new_trie_op←u; return; | |
< end; | |
< if h>min_quarterword then decr(h)@+else h←max_quarterword; | |
< end; | |
--- | |
> @!l:0..trie_op_size; {pointer to stored data} | |
> begin h:=abs(n+313*d+361*v+1009*cur_lang) mod (trie_op_size+trie_op_size) | |
> - trie_op_size; | |
> loop@+ begin l:=trie_op_hash[h]; | |
> if l=0 then {empty position found for a new op} | |
> begin if trie_op_ptr=trie_op_size then | |
> overflow("pattern memory ops",trie_op_size); | |
> u:=trie_used[cur_lang]; | |
> if u=max_quarterword then | |
> overflow("pattern memory ops per language", | |
> max_quarterword-min_quarterword); | |
> incr(trie_op_ptr); incr(u); trie_used[cur_lang]:=u; | |
> hyf_distance[trie_op_ptr]:=d; | |
> hyf_num[trie_op_ptr]:=n; hyf_next[trie_op_ptr]:=v; | |
> trie_op_lang[trie_op_ptr]:=cur_lang; trie_op_hash[h]:=trie_op_ptr; | |
> trie_op_val[trie_op_ptr]:=u; new_trie_op:=u; return; | |
> end; | |
> if (hyf_distance[l]=d)and(hyf_num[l]=n)and(hyf_next[l]=v) | |
> and(trie_op_lang[l]=cur_lang) then | |
> begin new_trie_op:=trie_op_val[l]; return; | |
> end; | |
> if h>-trie_op_size then decr(h)@+else h:=trie_op_size; | |
> end; | |
14974a18337,18361 | |
> @ After |new_trie_op| has compressed the necessary opcode information, | |
> plenty of information is available to unscramble the data into the | |
> final form needed by our hyphenation algorithm. | |
> | |
> @<Sort \(t)the hyphenation op tables into proper order@>= | |
> op_start[0]:=-min_quarterword; | |
> for j:=1 to 255 do op_start[j]:=op_start[j-1]+qo(trie_used[j-1]); | |
> for j:=1 to trie_op_ptr do | |
> trie_op_hash[j]:=op_start[trie_op_lang[j]]+trie_op_val[j]; {destination} | |
> for j:=1 to trie_op_ptr do while trie_op_hash[j]>j do | |
> begin k:=trie_op_hash[j];@/ | |
> t:=hyf_distance[k]; hyf_distance[k]:=hyf_distance[j]; hyf_distance[j]:=t;@/ | |
> t:=hyf_num[k]; hyf_num[k]:=hyf_num[j]; hyf_num[j]:=t;@/ | |
> t:=hyf_next[k]; hyf_next[k]:=hyf_next[j]; hyf_next[j]:=t;@/ | |
> trie_op_hash[j]:=trie_op_hash[k]; trie_op_hash[k]:=k; | |
> end | |
> | |
> @ Before we forget how to initialize the data structures that have been | |
> mentioned so far, let's write down the code that gets them started. | |
> | |
> @<Initialize table entries...@>= | |
> for k:=-trie_op_size to trie_op_size do trie_op_hash[k]:=0; | |
> for k:=0 to 255 do trie_used[k]:=min_quarterword; | |
> trie_op_ptr:=0; | |
> | |
14986,14987c18373,18375 | |
< The algorithms maintain the condition |trie_c[trie_r[z]]>trie_c[z]| | |
< whenever |z≠0| and |trie_r[z]≠0|; in other words, sibling nodes are | |
--- | |
> The algorithms maintain the condition | |
> $$\hbox{|trie_c[trie_r[z]]>trie_c[z]|\qquad | |
> whenever |z<>0| and |trie_r[z]<>0|};$$ in other words, sibling nodes are | |
14992,14998c18380,18391 | |
< @<Globals...@>= | |
< init @!trie_c:array[trie_pointer] of ascii_code; {characters to match} | |
< @t\hskip1em@>@!trie_o:array[trie_pointer] of quarterword; | |
< {operations to perform} | |
< @t\hskip1em@>@!trie_l:array[trie_pointer] of trie_pointer; {left subtrie links} | |
< @t\hskip1em@>@!trie_r:array[trie_pointer] of trie_pointer; {right subtrie links} | |
< @t\hskip1em@>@!trie_ptr:trie_pointer; {the number of nodes in the trie} | |
--- | |
> @<Glob...@>= | |
> @!init @!trie_c:packed array[trie_pointer] of packed_ASCII_code; | |
> {characters to match} | |
> @t\hskip10pt@>@!trie_o:packed array[trie_pointer] of quarterword; | |
> {operations to perform} | |
> @t\hskip10pt@>@!trie_l:packed array[trie_pointer] of trie_pointer; | |
> {left subtrie links} | |
> @t\hskip10pt@>@!trie_r:packed array[trie_pointer] of trie_pointer; | |
> {right subtrie links} | |
> @t\hskip10pt@>@!trie_ptr:trie_pointer; {the number of nodes in the trie} | |
> @t\hskip10pt@>@!trie_hash:packed array[trie_pointer] of trie_pointer; | |
> {used to identify equivalent subtries} | |
15002c18395 | |
< Experi\-ence shows that we can often reduce its size by recognizing common | |
--- | |
> Experience shows that we can often reduce its size by recognizing common | |
15007,15011c18400 | |
< @<Glob...@>= | |
< init @!trie_hash:array[trie_pointer] of trie_pointer; | |
< tini {to identify equivalent subtries} | |
< | |
< @ The function |trie_node(p)| returns |p| if |p| is distinct from other nodes | |
--- | |
> The function |trie_node(p)| returns |p| if |p| is distinct from other nodes | |
15014a18404,18407 | |
> Notice that we might make subtries equivalent even if they correspond to | |
> patterns for different languages, in which the trie ops might mean quite | |
> different things. That's perfectly all right. | |
> | |
15017c18410 | |
< to a canonical form} | |
--- | |
> to a canonical form} | |
15021,15032c18414,18425 | |
< begin h←(trie_c[p]+1009*trie_o[p]+@| | |
< 2718*trie_l[p]+3142*trie_r[p]) mod trie_size; | |
< loop@+ begin q←trie_hash[h]; | |
< if q=0 then | |
< begin trie_hash[h]←p; trie_node←p; return; | |
< end; | |
< if (trie_c[q]=trie_c[p])∧(trie_o[q]=trie_o[p])∧@| | |
< (trie_l[q]=trie_l[p])∧(trie_r[q]=trie_r[p]) then | |
< begin trie_node←q; return; | |
< end; | |
< if h>0 then decr(h)@+else h←trie_size; | |
< end; | |
--- | |
> begin h:=abs(trie_c[p]+1009*trie_o[p]+@| | |
> 2718*trie_l[p]+3142*trie_r[p]) mod trie_size; | |
> loop@+ begin q:=trie_hash[h]; | |
> if q=0 then | |
> begin trie_hash[h]:=p; trie_node:=p; return; | |
> end; | |
> if (trie_c[q]=trie_c[p])and(trie_o[q]=trie_o[p])and@| | |
> (trie_l[q]=trie_l[p])and(trie_r[q]=trie_r[p]) then | |
> begin trie_node:=q; return; | |
> end; | |
> if h>0 then decr(h)@+else h:=trie_size; | |
> end; | |
15038c18431 | |
< zero and then saying `|trie_root←compress_trie(trie_root)|'. | |
--- | |
> zero and then saying `|trie_root:=compress_trie(trie_root)|'. | |
15043,15059c18436,18440 | |
< begin if p=0 then compress_trie←0 | |
< else begin trie_l[p]←compress_trie(trie_l[p]); | |
< trie_r[p]←compress_trie(trie_r[p]); | |
< compress_trie←trie_node(p); | |
< end; | |
< end; | |
< | |
< @ Before we forget how to initialize the data structures that have been | |
< mentioned so far, let's write a procedure that does the initialization. | |
< | |
< @<Declare procedures for preprocessing hyph...@>= | |
< procedure init_pattern_memory; {gets ready to build a linked trie} | |
< var h:0..trie_op_hash_size; {an index into |trie_op_hash|} | |
< @!p:trie_pointer; {an index into |trie_hash|} | |
< begin for h←0 to trie_op_hash_size do trie_op_hash[h]←min_quarterword; | |
< trie_op_ptr←min_quarterword; trie_root←0; trie_c[0]←0; trie_ptr←0; | |
< for p←0 to trie_size do trie_hash[p]←0; | |
--- | |
> begin if p=0 then compress_trie:=0 | |
> else begin trie_l[p]:=compress_trie(trie_l[p]); | |
> trie_r[p]:=compress_trie(trie_r[p]); | |
> compress_trie:=trie_node(p); | |
> end; | |
15066c18447,18448 | |
< |trie_ref[p]| will be nonzero if the linked trie node |p| is the oldest sibling | |
--- | |
> |trie_ref[p]| will be nonzero only if the linked trie node |p| is the | |
> smallest character | |
15073a18456,18457 | |
> To save time at the low end of the trie, we maintain array entries | |
> |trie_min[c]| pointing to the smallest hole that is greater than~|c|. | |
15083,15086c18467,18472 | |
< init@!trie_taken:array[trie_pointer] of boolean; {does a family start here?} | |
< @t\hskip1em@>@!trie_max:trie_pointer; {largest location used in |trie|} | |
< @t\hskip1em@>@!trie_min:trie_pointer; | |
< {all locations |≤trie_min| are vacant in |trie|} | |
--- | |
> @!init@!trie_taken:packed array[1..trie_size] of boolean; | |
> {does a family start here?} | |
> @t\hskip10pt@>@!trie_min:array[ASCII_code] of trie_pointer; | |
> {the first possible slot for each character} | |
> @t\hskip10pt@>@!trie_max:trie_pointer; {largest location used in |trie|} | |
> @t\hskip10pt@>@!trie_not_ready:boolean; {is the trie still in linked form?} | |
15089,15105c18475,18479 | |
< @ Here is how these data structures are initialized. | |
< | |
< @<Declare procedures for preprocessing hyph...@>= | |
< procedure init_trie_memory; {gets ready to pack into |trie|} | |
< var p:trie_pointer; {index into |trie_ref|, |trie|, |trie_taken|} | |
< begin for p←0 to trie_ptr do trie_ref[p]←0; | |
< trie_max←128; trie_min←128; trie_link(0)←1; trie_taken[0]←false; | |
< for p←1 to 128 do | |
< begin trie_back(p)←p-1; trie_link(p)←p+1; trie_taken[p]←false; | |
< end; | |
< end; | |
< | |
< @ Each time \.{\\patterns} appears, it overrides any patterns that were | |
< entered earlier, so the arrays are not initialized until \TeX\ sees | |
< \.{\\patterns}. However, some of the global variables must be | |
< initialized when \.{INITEX} is loaded, in case the user never mentions | |
< any \.{\\patterns}. | |
--- | |
> @ Each time \.{\\patterns} appears, it contributes further patterns to | |
> the future trie, which will be built only when hyphenation is attempted or | |
> when a format file is dumped. The boolean variable |trie_not_ready| | |
> will change to |false| when the trie is compressed; this will disable | |
> further patterns. | |
15108,15111c18482,18495 | |
< trie_op_ptr←min_quarterword;@/ | |
< trie_link(0)←0; trie_char(0)←0; trie_op(0)←0; | |
< for k←1 to 127 do trie[k]←trie[0]; | |
< trie_max←127; | |
--- | |
> trie_not_ready:=true; trie_root:=0; trie_c[0]:=si(0); trie_ptr:=0; | |
> | |
> @ Here is how the trie-compression data structures are initialized. | |
> If storage is tight, it would be possible to overlap |trie_op_hash|, | |
> |trie_op_lang|, and |trie_op_val| with |trie|, |trie_hash|, and |trie_taken|, | |
> because we finish with the former just before we need the latter. | |
> | |
> @<Get ready to compress the trie@>= | |
> @<Sort \(t)the hyphenation...@>; | |
> for p:=0 to trie_size do trie_hash[p]:=0; | |
> trie_root:=compress_trie(trie_root); {identify equivalent subtries} | |
> for p:=0 to trie_ptr do trie_ref[p]:=0; | |
> for p:=0 to 255 do trie_min[p]:=p+1; | |
> trie_link(0):=1; trie_max:=0 | |
15126,15137c18510,18521 | |
< @!c:ascii_code; {smallest character in the family} | |
< begin c←trie_c[p]; {we have |c≠0|} | |
< if c<trie_min then trie_min←c; | |
< z←trie_link(trie_min-1); {get the first conceivably good hole} | |
< loop@+ begin if z<c then goto not_found; | |
< h←z-c;@/ | |
< @<Ensure that |trie_max≥h+128|@>; | |
< if trie_taken[h] then goto not_found; | |
< @<If all characters of the family fit relative to |h|, then | |
< |goto found|,\30\ otherwise |goto not_found|@>; | |
< not_found: z←trie_link(z); {move to the next hole} | |
< end; | |
--- | |
> @!c:ASCII_code; {smallest character in the family} | |
> @!l,@!r:trie_pointer; {left and right neighbors} | |
> @!ll:1..256; {upper limit of |trie_min| updating} | |
> begin c:=so(trie_c[p]); | |
> z:=trie_min[c]; {get the first conceivably good hole} | |
> loop@+ begin h:=z-c;@/ | |
> @<Ensure that |trie_max>=h+256|@>; | |
> if trie_taken[h] then goto not_found; | |
> @<If all characters of the family fit relative to |h|, then | |
> |goto found|,\30\ otherwise |goto not_found|@>; | |
> not_found: z:=trie_link(z); {move to the next hole} | |
> end; | |
15141,15151c18525,18536 | |
< @ By making sure that |trie_max| is at least |h+128|, we can be sure that | |
< |trie_max>z|, since |h=z+c|. It follows that location |trie_max| will | |
< never be occupied in |trie|, and we will have |trie_max≥trie_link(z)|. | |
< | |
< @<Ensure that |trie_max≥h+128|@>= | |
< if trie_max<h+128 then | |
< begin if trie_size≤h+128 then overflow("pattern memory",trie_size); | |
< repeat incr(trie_max); trie_taken[trie_max]←false; | |
< trie_link(trie_max)←trie_max+1; trie_back(trie_max)←trie_max-1; | |
< until trie_max=h+128; | |
< end | |
--- | |
> @ By making sure that |trie_max| is at least |h+256|, we can be sure that | |
> |trie_max>z|, since |h=z-c|. It follows that location |trie_max| will | |
> never be occupied in |trie|, and we will have |trie_max>=trie_link(z)|. | |
> | |
> @<Ensure that |trie_max>=h+256|@>= | |
> if trie_max<h+256 then | |
> begin if trie_size<=h+256 then overflow("pattern memory",trie_size); | |
> @:TeX capacity exceeded pattern memory}{\quad pattern memory@> | |
> repeat incr(trie_max); trie_taken[trie_max]:=false; | |
> trie_link(trie_max):=trie_max+1; trie_back(trie_max):=trie_max-1; | |
> until trie_max=h+256; | |
> end | |
15154c18539 | |
< q←trie_r[p]; | |
--- | |
> q:=trie_r[p]; | |
15156,15158c18541,18543 | |
< begin if trie_link(h+trie_c[q])=0 then goto not_found; | |
< q←trie_r[q]; | |
< end; | |
--- | |
> begin if trie_link(h+so(trie_c[q]))=0 then goto not_found; | |
> q:=trie_r[q]; | |
> end; | |
15162,15164c18547,18555 | |
< trie_taken[h]←true; trie_ref[p]←h; q←p; | |
< repeat z←h+trie_c[q]; trie_back(trie_link(z))←trie_back(z); | |
< trie_link(trie_back(z))←trie_link(z); trie_link(z)←0; q←trie_r[q]; | |
--- | |
> trie_taken[h]:=true; trie_ref[p]:=h; q:=p; | |
> repeat z:=h+so(trie_c[q]); l:=trie_back(z); r:=trie_link(z); | |
> trie_back(r):=l; trie_link(l):=r; trie_link(z):=0; | |
> if l<256 then | |
> begin if z<256 then ll:=z @+else ll:=256; | |
> repeat trie_min[l]:=r; incr(l); | |
> until l=ll; | |
> end; | |
> q:=trie_r[q]; | |
15173,15177c18564,18568 | |
< begin repeat q←trie_l[p]; | |
< if (q>0)∧(trie_ref[q]=0) then | |
< begin first_fit(q); trie_pack(q); | |
< end; | |
< p←trie_r[p]; | |
--- | |
> begin repeat q:=trie_l[p]; | |
> if (q>0)and(trie_ref[q]=0) then | |
> begin first_fit(q); trie_pack(q); | |
> end; | |
> p:=trie_r[p]; | |
15183,15188c18574,18575 | |
< information. Null pointers in the linked trie will be replaced by the | |
< first untaken position |r| in |trie|, since this properly implements an | |
< ``empty'' family. The value of |r| is stored in |trie_ref[0]| just before | |
< the fixup process starts. Note that |trie_max| will always be at least as | |
< large as |r+127|, since it is always at least 128 more than each location | |
< that is taken. | |
--- | |
> information. Null pointers in the linked trie will be represented by the | |
> value~0, which properly implements an ``empty'' family. | |
15191,15194c18578,18589 | |
< r←0; | |
< while trie_taken[r] do incr(r); | |
< trie_ref[0]←r; {|r| will be used for null pointers} | |
< trie_fix(trie_root) {this fixes the non-holes in |trie|} | |
--- | |
> h.rh:=0; h.b0:=min_quarterword; h.b1:=min_quarterword; {|trie_link:=0|, | |
> |trie_op:=min_quarterword|, |trie_char:=qi(0)|} | |
> if trie_root=0 then {no patterns were given} | |
> begin for r:=0 to 256 do trie[r]:=h; | |
> trie_max:=256; | |
> end | |
> else begin trie_fix(trie_root); {this fixes the non-holes in |trie|} | |
> r:=0; {now we will zero out all the holes} | |
> repeat s:=trie_link(r); trie[r]:=h; r:=s; | |
> until r>trie_max; | |
> end; | |
> trie_char(0):=qi("?"); {make |trie_char(c)<>c| for all |c|} | |
15205c18600 | |
< @!c:ascii_code; {another one that need not be saved} | |
--- | |
> @!c:ASCII_code; {another one that need not be saved} | |
15207,15213c18602,18607 | |
< begin z←trie_ref[p]; | |
< while p≠0 do | |
< begin q←trie_l[p]; c←trie_c[p]; | |
< trie_link(z+c)←trie_ref[q]; trie_char(z+c)←c; trie_op(z+c)←trie_o[p]; | |
< if q>0 then trie_fix(q); | |
< p←trie_r[p]; | |
< end; | |
--- | |
> begin z:=trie_ref[p]; | |
> repeat q:=trie_l[p]; c:=so(trie_c[p]); | |
> trie_link(z+c):=trie_ref[q]; trie_char(z+c):=qi(c); trie_op(z+c):=trie_o[p]; | |
> if q>0 then trie_fix(q); | |
> p:=trie_r[p]; | |
> until p=0; | |
15216,15221c18610,18612 | |
< @ Now let's put all these routines together. When \.{INITEX} has scanned | |
< the `\.{\\patterns}' control sequence, it calls on |new_patterns| to do | |
< the right thing. After |new_patterns| has acted, the compacted pattern data | |
< will appear in the array |trie[1..trie_max]|, and the associated numeric | |
< hyphenation data will appear in locations |[(min_quarterword+1)..trie_op_ptr]| | |
< of the arrays |hyf_distance|, |hyf_num|, |hyf_next|. | |
--- | |
> @ Now let's go back to the easier problem, of building the linked | |
> trie. When \.{INITEX} has scanned the `\.{\\patterns}' control | |
> sequence, it calls on |new_patterns| to do the right thing. | |
15226c18617,18618 | |
< var k,@!l:small_number; {indices into |hc| and |hyf|} | |
--- | |
> var k,@!l:0..64; {indices into |hc| and |hyf|; | |
> not always in |small_number| range} | |
15231,15239c18623,18632 | |
< @!c:ascii_code; {character being inserted} | |
< @!r,@!s:trie_pointer; {used to clean up the packed |trie|} | |
< @!h:two_halves; {template used to zero out |trie|'s holes} | |
< begin scan_left_brace; {a left brace must follow \.{\\patterns}} | |
< init_pattern_memory;@/ | |
< @<Enter all of the patterns into a linked trie, until coming to a right | |
< brace; then skip an optional space@>; | |
< trie_root←compress_trie(trie_root); {compress the trie} | |
< @<Pack the trie@>; | |
--- | |
> @!c:ASCII_code; {character being inserted} | |
> begin if trie_not_ready then | |
> begin set_cur_lang; scan_left_brace; {a left brace must follow \.{\\patterns}} | |
> @<Enter all of the patterns into a linked trie, until coming to a right | |
> brace@>; | |
> end | |
> else begin print_err("Too late for "); print_esc("patterns"); | |
> help1("All patterns must be given before typesetting begins."); | |
> error; link(garbage):=scan_toks(false,false); flush_list(def_ref); | |
> end; | |
15247,15258c18640,18649 | |
< k←0; hyf[0]←0; digit_sensed←false; | |
< loop@+ begin get_nc_token; | |
< case cur_cmd of | |
< letter,other_char:@<Append a new letter or a hyphen level@>; | |
< spacer,right_brace: begin if k>0 then | |
< @<Insert a new pattern into the linked trie@>; | |
< if cur_cmd=right_brace then | |
< begin @<Scan an optional space@>; goto done; | |
< end; | |
< k←0; hyf[0]←0; digit_sensed←false; | |
< end; | |
< othercases begin print_nl("! Bad \patterns"); | |
--- | |
> k:=0; hyf[0]:=0; digit_sensed:=false; | |
> loop@+ begin get_x_token; | |
> case cur_cmd of | |
> letter,other_char:@<Append a new letter or a hyphen level@>; | |
> spacer,right_brace: begin if k>0 then | |
> @<Insert a new pattern into the linked trie@>; | |
> if cur_cmd=right_brace then goto done; | |
> k:=0; hyf[0]:=0; digit_sensed:=false; | |
> end; | |
> othercases begin print_err("Bad "); print_esc("patterns"); | |
15260,15263c18651,18654 | |
< help1("(See Appendix H.)"); error; pass_block(1); goto done; | |
< end | |
< endcases; | |
< end; | |
--- | |
> help1("(See Appendix H.)"); error; | |
> end | |
> endcases; | |
> end; | |
15267,15272c18658,18662 | |
< if digit_sensed ∨(cur_chr<"0")∨(cur_chr>"9") then | |
< begin if cur_chr="." then cur_chr←127 {change edge-of-word delimiter | |
< to |@'177|} | |
< else begin cur_chr←lc_code(cur_chr); | |
< if cur_chr=0 then | |
< begin print_nl("! Nonletter"); | |
--- | |
> if digit_sensed or(cur_chr<"0")or(cur_chr>"9") then | |
> begin if cur_chr="." then cur_chr:=0 {edge-of-word delimiter} | |
> else begin cur_chr:=lc_code(cur_chr); | |
> if cur_chr=0 then | |
> begin print_err("Nonletter"); | |
15274,15286c18664,18677 | |
< help1("(See Appendix H.)"); error; cur_chr←127; | |
< end; | |
< end; | |
< if k<63 then | |
< begin incr(k); hc[k]←cur_chr; hyf[k]←0; digit_sensed←false; | |
< end; | |
< end | |
< else begin hyf[k]←cur_chr-"0"; digit_sensed←true; | |
< end | |
< | |
< @ When the following code comes into play, the pattern $p↓1\ldotsm p↓k$ | |
< appears in |hc[1..k]|, and the corresponding sequence of numbers $n↓0\ldotsm | |
< n↓k$ appears in |hyf[0..k]|. | |
--- | |
> help1("(See Appendix H.)"); error; | |
> end; | |
> end; | |
> if k<63 then | |
> begin incr(k); hc[k]:=cur_chr; hyf[k]:=0; digit_sensed:=false; | |
> end; | |
> end | |
> else if k<63 then | |
> begin hyf[k]:=cur_chr-"0"; digit_sensed:=true; | |
> end | |
> | |
> @ When the following code comes into play, the pattern $p_1\ldots p_k$ | |
> appears in |hc[1..k]|, and the corresponding sequence of numbers $n_0\ldots | |
> n_k$ appears in |hyf[0..k]|. | |
15289,15302c18680,18693 | |
< begin @<Compute the trie op code, |v|, and set |l←0|@>; | |
< q←0; | |
< while l<k do | |
< begin incr(l); c←hc[l]; p←trie_l[q]; first_child←true; | |
< while (p>0)∧(c>trie_c[p]) do | |
< begin q←p; p←trie_r[q]; first_child←false; | |
< end; | |
< if (p=0)∨(c<trie_c[p]) then | |
< @<Insert a new trie node between |q| and |p|, and | |
< make |p| point to it@>; | |
< q←p; {now node |q| represents $p↓1\ldotsm p↓l$} | |
< end; | |
< if trie_o[q]≠min_quarterword then | |
< begin print_nl("! Duplicate pattern"); | |
--- | |
> begin @<Compute the trie op code, |v|, and set |l:=0|@>; | |
> q:=0; hc[0]:=cur_lang; | |
> while l<=k do | |
> begin c:=hc[l]; incr(l); p:=trie_l[q]; first_child:=true; | |
> while (p>0)and(c>so(trie_c[p])) do | |
> begin q:=p; p:=trie_r[q]; first_child:=false; | |
> end; | |
> if (p=0)or(c<so(trie_c[p])) then | |
> @<Insert a new trie node between |q| and |p|, and | |
> make |p| point to it@>; | |
> q:=p; {now node |q| represents $p_1\ldots p_{l-1}$} | |
> end; | |
> if trie_o[q]<>min_quarterword then | |
> begin print_err("Duplicate pattern"); | |
15304,15306c18695,18697 | |
< help1("(See Appendix H.)"); error; | |
< end; | |
< trie_o[q]←v; | |
--- | |
> help1("(See Appendix H.)"); error; | |
> end; | |
> trie_o[q]:=v; | |
15311,15313c18702,18705 | |
< incr(trie_ptr); trie_r[trie_ptr]←p; p←trie_ptr; trie_l[p]←0; | |
< if first_child then trie_l[q]←p@+else trie_r[q]←p; | |
< trie_c[p]←c; trie_o[p]←min_quarterword; | |
--- | |
> @:TeX capacity exceeded pattern memory}{\quad pattern memory@> | |
> incr(trie_ptr); trie_r[trie_ptr]:=p; p:=trie_ptr; trie_l[p]:=0; | |
> if first_child then trie_l[q]:=p@+else trie_r[q]:=p; | |
> trie_c[p]:=si(c); trie_o[p]:=min_quarterword; | |
15317,15320c18709,18714 | |
< l←k; v←min_quarterword; | |
< loop@+ begin if hyf[l]≠0 then v←new_trie_op(k-l,hyf[l],v); | |
< if l>0 then decr(l)@+else goto done1; | |
< end; | |
--- | |
> if hc[1]=0 then hyf[0]:=0; | |
> if hc[k]=0 then hyf[k]:=0; | |
> l:=k; v:=min_quarterword; | |
> loop@+ begin if hyf[l]<>0 then v:=new_trie_op(k-l,hyf[l],v); | |
> if l>0 then decr(l)@+else goto done1; | |
> end; | |
15323,15324c18717,18720 | |
< @ The following packing routine is rigged so that the root of the linked | |
< tree gets mapped into location 0 of |trie|, as required by the hyphenation | |
--- | |
> @ Finally we put everything together: Here is how the trie gets to its | |
> final, efficient form. | |
> The following packing routine is rigged so that the root of the linked | |
> tree gets mapped into location 1 of |trie|, as required by the hyphenation | |
15326c18722 | |
< ``take'' location@@0. | |
--- | |
> ``take'' location~1. | |
15328,15332c18724,18733 | |
< @<Pack the trie@>= | |
< init_trie_memory; | |
< if trie_root≠0 then | |
< begin first_fit(trie_root); trie_pack(trie_root); | |
< end; | |
--- | |
> @<Declare procedures for preprocessing hyphenation patterns@>= | |
> procedure init_trie; | |
> var @!p:trie_pointer; {pointer for initialization} | |
> @!j,@!k,@!t:integer; {all-purpose registers for initialization} | |
> @!r,@!s:trie_pointer; {used to clean up the packed |trie|} | |
> @!h:two_halves; {template used to zero out |trie|'s holes} | |
> begin @<Get ready to compress the trie@>; | |
> if trie_root<>0 then | |
> begin first_fit(trie_root); trie_pack(trie_root); | |
> end; | |
15334,15339c18735,18738 | |
< r←0; {finally, we will zero out the holes} | |
< h.rh←0; h.b0←min_quarterword; h.b1←0; {|trie_link←0|, | |
< |trie_op←min_quarterword|, |trie_op←0|} | |
< repeat s←trie_link(r); trie[r]←h; r←s; | |
< until r>trie_max | |
< @* \[43] Breaking vertical lists into pages. | |
--- | |
> trie_not_ready:=false; | |
> end; | |
> | |
> @* \[44] Breaking vertical lists into pages. | |
15355a18755 | |
> @^data structure assumptions@> | |
15360,15373c18760,18773 | |
< begin prev_p←temp_head; link(temp_head)←p; | |
< while p≠null do | |
< case type(p) of | |
< hlist_node,vlist_node,rule_node:@<Insert glue for |split_top_skip| | |
< and set@@|p←null|@>; | |
< whatsit_node,mark_node,ins_node: begin prev_p←p; p←link(prev_p); | |
< end; | |
< glue_node,kern_node,penalty_node: begin q←p; p←link(q); link(q)←null; | |
< link(prev_p)←p; flush_node_list(q); | |
< end; | |
< othercases confusion("pruning") | |
< @:confusion pruning}{\quad pruning@> | |
< endcases; | |
< prune_page_top←link(temp_head); | |
--- | |
> begin prev_p:=temp_head; link(temp_head):=p; | |
> while p<>null do | |
> case type(p) of | |
> hlist_node,vlist_node,rule_node:@<Insert glue for |split_top_skip| | |
> and set~|p:=null|@>; | |
> whatsit_node,mark_node,ins_node: begin prev_p:=p; p:=link(prev_p); | |
> end; | |
> glue_node,kern_node,penalty_node: begin q:=p; p:=link(q); link(q):=null; | |
> link(prev_p):=p; flush_node_list(q); | |
> end; | |
> othercases confusion("pruning") | |
> @:this can't happen pruning}{\quad pruning@> | |
> endcases; | |
> prune_page_top:=link(temp_head); | |
15377,15381c18777,18781 | |
< begin q←new_skip_param(split_top_skip_code); link(prev_p)←q; link(q)←p; | |
< {now |temp_ptr=glue_ptr(q)|} | |
< if width(temp_ptr)>height(p) then width(temp_ptr)←width(temp_ptr)-height(p) | |
< else width(temp_ptr)←0; | |
< p←null; | |
--- | |
> begin q:=new_skip_param(split_top_skip_code); link(prev_p):=q; link(q):=p; | |
> {now |temp_ptr=glue_ptr(q)|} | |
> if width(temp_ptr)>height(p) then width(temp_ptr):=width(temp_ptr)-height(p) | |
> else width(temp_ptr):=0; | |
> p:=null; | |
15385,15386c18785,18786 | |
< so as to obtain a box of height |h|, taking account of the |split_max_depth| | |
< parameter. A pointer to the beginning of the vertical list is given, | |
--- | |
> so as to obtain a box of height~|h|, with maximum depth~|d|. | |
> A pointer to the beginning of the vertical list is given, | |
15398c18798 | |
< @d set_height_zero(#)==active_height[#]←0 {initialize the height to zero} | |
--- | |
> @d set_height_zero(#)==active_height[#]:=0 {initialize the height to zero} | |
15402,15403c18802,18803 | |
< @p function vert_break(@!p:pointer; @!h:scaled):pointer; | |
< {finds optimum page break} | |
--- | |
> @p function vert_break(@!p:pointer; @!h,@!d:scaled):pointer; | |
> {finds optimum page break} | |
15406c18806 | |
< whether |p| is a legal breakpoint} | |
--- | |
> whether |p| is a legal breakpoint} | |
15410,15411c18810,18811 | |
< @!least_badness:integer; {the smallest badness found so far} | |
< @!best_place:pointer; {the most recent break that leads to |least_badness|} | |
--- | |
> @!least_cost:integer; {the smallest badness plus penalties found so far} | |
> @!best_place:pointer; {the most recent break that leads to |least_cost|} | |
15414,15421c18814,18821 | |
< begin prev_p←p; {an initial glue node is not a legal breakpoint} | |
< least_badness←awful_bad; do_all_six(set_height_zero); prev_dp←0; | |
< loop@+ begin @<If node |p| is a legal breakpoint, check if this break is | |
< the best known, and |goto done| if |p| is null or | |
< if the page-so-far is already too full to accept more stuff@>; | |
< prev_p←p; p←link(prev_p); | |
< end; | |
< done: vert_break←best_place; | |
--- | |
> begin prev_p:=p; {an initial glue node is not a legal breakpoint} | |
> least_cost:=awful_bad; do_all_six(set_height_zero); prev_dp:=0; | |
> loop@+ begin @<If node |p| is a legal breakpoint, check if this break is | |
> the best known, and |goto done| if |p| is null or | |
> if the page-so-far is already too full to accept more stuff@>; | |
> prev_p:=p; p:=link(prev_p); | |
> end; | |
> done: vert_break:=best_place; | |
15430c18830 | |
< shrinking} | |
--- | |
> shrinking} | |
15432,15434c18832,18834 | |
< @ A subtle point to be noted here is that |split_max_depth| might be negative, | |
< so |cur_height| and |prev_dp| might need to be corrected even after a | |
< glue or kern node. | |
--- | |
> @ A subtle point to be noted here is that the maximum depth~|d| might be | |
> negative, so |cur_height| and |prev_dp| might need to be corrected even | |
> after a glue or kern node. | |
15437,15441c18837,18841 | |
< if p=null then pi←eject_penalty | |
< else @<Use node |p| to update the current height and depth measurements; | |
< if this node is not a legal breakpoint, |goto not_found| | |
< or |update_heights|, | |
< otherwise set |pi| to the associated penalty at the break@>; | |
--- | |
> if p=null then pi:=eject_penalty | |
> else @<Use node |p| to update the current height and depth measurements; | |
> if this node is not a legal breakpoint, |goto not_found| | |
> or |update_heights|, | |
> otherwise set |pi| to the associated penalty at the break@>; | |
15443,15444c18843,18844 | |
< if |p| is a forced break or if the page-so-far is already too full@>; | |
< if (type(p)<glue_node)∨(type(p)>kern_node) then goto not_found; | |
--- | |
> if |p| is a forced break or if the page-so-far is already too full@>; | |
> if (type(p)<glue_node)or(type(p)>kern_node) then goto not_found; | |
15446,15450c18846,18850 | |
< respect to a glue or kern node |p|@>; | |
< not_found: if prev_dp>split_max_depth then | |
< begin cur_height←cur_height+prev_dp-split_max_depth; | |
< prev_dp←split_max_depth; | |
< end; | |
--- | |
> respect to a glue or kern node~|p|@>; | |
> not_found: if prev_dp>d then | |
> begin cur_height:=cur_height+prev_dp-d; | |
> prev_dp:=d; | |
> end; | |
15455,15457c18855,18857 | |
< cur_height←cur_height+prev_dp+height(p); prev_dp←depth(p); | |
< goto not_found; | |
< end; | |
--- | |
> cur_height:=cur_height+prev_dp+height(p); prev_dp:=depth(p); | |
> goto not_found; | |
> end; | |
15459,15465c18859,18865 | |
< glue_node: if precedes_break(prev_p) then pi←0 | |
< else goto update_heights; | |
< kern_node: begin if link(p)=null then t←penalty_node | |
< else t←type(link(p)); | |
< if t=glue_node then pi←0@+else goto update_heights; | |
< end; | |
< penalty_node: pi←penalty(p); | |
--- | |
> glue_node: if precedes_break(prev_p) then pi:=0 | |
> else goto update_heights; | |
> kern_node: begin if link(p)=null then t:=penalty_node | |
> else t:=type(link(p)); | |
> if t=glue_node then pi:=0@+else goto update_heights; | |
> end; | |
> penalty_node: pi:=penalty(p); | |
15468c18868 | |
< @:confusion vertbreak}{\quad vertbreak@> | |
--- | |
> @:this can't happen vertbreak}{\quad vertbreak@> | |
15471c18871,18873 | |
< @ @<Check if node |p| is a new champion breakpoint; then \(go)...@>= | |
--- | |
> @ @d deplorable==100000 {more than |inf_bad|, but less than |awful_bad|} | |
> | |
> @<Check if node |p| is a new champion breakpoint; then \(go)...@>= | |
15473,15482c18875,18886 | |
< begin @<Compute the badness, |b|, using |awful_bad| | |
< if the box is too full@>; | |
< if b≤inf_bad then | |
< if pi≤eject_penalty then b←pi@+else b←b+pi; | |
< if b≤least_badness then | |
< begin best_place←p; least_badness←b; | |
< best_height_plus_depth←cur_height+prev_dp; | |
< end; | |
< if (b=awful_bad)∨(pi≤eject_penalty) then goto done; | |
< end | |
--- | |
> begin @<Compute the badness, |b|, using |awful_bad| | |
> if the box is too full@>; | |
> if b<awful_bad then | |
> if pi<=eject_penalty then b:=pi | |
> else if b<inf_bad then b:=b+pi | |
> else b:=deplorable; | |
> if b<=least_cost then | |
> begin best_place:=p; least_cost:=b; | |
> best_height_plus_depth:=cur_height+prev_dp; | |
> end; | |
> if (b=awful_bad)or(pi<=eject_penalty) then goto done; | |
> end | |
15486,15490c18890,18894 | |
< if (active_height[3]≠0) or (active_height[4]≠0) or | |
< (active_height[5]≠0) then b←0 | |
< else b←badness(h-cur_height,active_height[2]) | |
< else if cur_height-h>active_height[6] then b←awful_bad | |
< else b←badness(cur_height-h,active_height[6]) | |
--- | |
> if (active_height[3]<>0) or (active_height[4]<>0) or | |
> (active_height[5]<>0) then b:=0 | |
> else b:=badness(h-cur_height,active_height[2]) | |
> else if cur_height-h>active_height[6] then b:=awful_bad | |
> else b:=badness(cur_height-h,active_height[6]) | |
15497,15504c18901,18908 | |
< if type(p)=kern_node then q←p | |
< else begin q←glue_ptr(p); | |
< active_height[2+stretch_order(q)]←@| | |
< active_height[2+stretch_order(q)]+stretch(q);@/ | |
< active_height[6]←active_height[6]+shrink(q); | |
< if (shrink_order(q)≠normal)∧(shrink(q)≠0) then | |
< begin@t@>@;@/ | |
< print_nl("! Infinite glue shrinkage found in box being split");@/ | |
--- | |
> if type(p)=kern_node then q:=p | |
> else begin q:=glue_ptr(p); | |
> active_height[2+stretch_order(q)]:=@| | |
> active_height[2+stretch_order(q)]+stretch(q);@/ | |
> active_height[6]:=active_height[6]+shrink(q); | |
> if (shrink_order(q)<>normal)and(shrink(q)<>0) then | |
> begin@t@>@;@/ | |
> print_err("Infinite glue shrinkage found in box being split");@/ | |
15506,15514c18910,18918 | |
< help4("The box you are \vsplitting contains some infinitely")@/ | |
< ("shrinkable glue, e.g., `\vss' or `\vskip 0pt minus 1fil'.")@/ | |
< ("Such glue doesn't belong there; but you can safely proceed,")@/ | |
< ("since the offensive shrinkability has been made finite."); | |
< error; r←new_spec(q); shrink_order(r)←normal; delete_glue_ref(q); | |
< glue_ptr(p)←r; | |
< end; | |
< end; | |
< cur_height←cur_height+prev_dp+width(q); prev_dp←0 | |
--- | |
> help4("The box you are \vsplitting contains some infinitely")@/ | |
> ("shrinkable glue, e.g., `\vss' or `\vskip 0pt minus 1fil'.")@/ | |
> ("Such glue doesn't belong there; but you can safely proceed,")@/ | |
> ("since the offensive shrinkability has been made finite."); | |
> error; r:=new_spec(q); shrink_order(r):=normal; delete_glue_ref(q); | |
> glue_ptr(p):=r; q:=r; | |
> end; | |
> end; | |
> cur_height:=cur_height+prev_dp+width(q); prev_dp:=0 | |
15521c18925 | |
< returns a box for a page of height@@|h|. The remainder of the vlist, if | |
--- | |
> returns a box for a page of height~|h|. The remainder of the vlist, if | |
15527,15529c18931,18933 | |
< The original box becomes ``absent'' if and only if it has been entirely | |
< extracted. The extracted box is ``absent'' if and only if the original | |
< box was absent (or if it was, erroneously, an hlist box). | |
--- | |
> The original box becomes ``void'' if and only if it has been entirely | |
> extracted. The extracted box is ``void'' if and only if the original | |
> box was void (or if it was, erroneously, an hlist box). | |
15531,15532c18935,18936 | |
< @p function vsplit(@!n:quarterword; @!h:scaled):pointer; | |
< {extracts a page of height |h| from box |n|} | |
--- | |
> @p function vsplit(@!n:eight_bits; @!h:scaled):pointer; | |
> {extracts a page of height |h| from box |n|} | |
15537,15543c18941,18947 | |
< begin v←box(n); | |
< if split_first_mark≠null then | |
< begin delete_token_ref(split_first_mark); split_first_mark←null; | |
< delete_token_ref(split_bot_mark); split_bot_mark←null; | |
< end; | |
< @<Dispense with trivial cases of absent or bad boxes@>; | |
< q←vert_break(list_ptr(v),h); | |
--- | |
> begin v:=box(n); | |
> if split_first_mark<>null then | |
> begin delete_token_ref(split_first_mark); split_first_mark:=null; | |
> delete_token_ref(split_bot_mark); split_bot_mark:=null; | |
> end; | |
> @<Dispense with trivial cases of void or bad boxes@>; | |
> q:=vert_break(list_ptr(v),h,split_max_depth); | |
15545,15549c18949,18953 | |
< link to |null| at the break@>; | |
< q←prune_page_top(q); p←list_ptr(v); free_node(v,box_node_size); | |
< if q=null then box(n)←null {the |eq_level| of the box stays the same} | |
< else box(n)←vpack(q,natural); | |
< vsplit←vpackage(p,h,exactly,split_max_depth); | |
--- | |
> link to |null| at the break@>; | |
> q:=prune_page_top(q); p:=list_ptr(v); free_node(v,box_node_size); | |
> if q=null then box(n):=null {the |eq_level| of the box stays the same} | |
> else box(n):=vpack(q,natural); | |
> vsplit:=vpackage(p,h,exactly,split_max_depth); | |
15552c18956 | |
< @ @<Dispense with trivial cases of absent or bad boxes@>= | |
--- | |
> @ @<Dispense with trivial cases of void or bad boxes@>= | |
15554,15559c18958,18962 | |
< begin vsplit←null; return; | |
< end; | |
< if type(v)≠vlist_node then | |
< begin help2("The box you are trying to split is an \hbox.")@/ | |
< ("I can't split such boxes, so I'll leave it alone."); | |
< print_nl("! \vsplit needs a \vbox"); error; vsplit←null; return; | |
--- | |
> begin vsplit:=null; return; | |
> end; | |
> if type(v)<>vlist_node then | |
> begin print_err(""); print_esc("vsplit"); print(" needs a "); | |
> print_esc("vbox"); | |
15561c18964,18967 | |
< end | |
--- | |
> help2("The box you are trying to split is an \hbox.")@/ | |
> ("I can't split such a box, so I'll leave it alone."); | |
> error; vsplit:=null; return; | |
> end | |
15567,15568c18973,18974 | |
< p←list_ptr(v); | |
< if p=q then list_ptr(v)←null | |
--- | |
> p:=list_ptr(v); | |
> if p=q then list_ptr(v):=null | |
15570,15584c18976,18990 | |
< if split_first_mark=null then | |
< begin split_first_mark←mark_ptr(p); | |
< split_bot_mark←split_first_mark; | |
< token_ref_count(split_first_mark)←@| | |
< token_ref_count(split_first_mark)+2; | |
< end | |
< else begin delete_token_ref(split_bot_mark); | |
< split_bot_mark←mark_ptr(p); | |
< add_token_ref(split_bot_mark); | |
< end; | |
< if link(p)=q then | |
< begin link(p)←null; goto done; | |
< end; | |
< p←link(p); | |
< end; | |
--- | |
> if split_first_mark=null then | |
> begin split_first_mark:=mark_ptr(p); | |
> split_bot_mark:=split_first_mark; | |
> token_ref_count(split_first_mark):=@| | |
> token_ref_count(split_first_mark)+2; | |
> end | |
> else begin delete_token_ref(split_bot_mark); | |
> split_bot_mark:=mark_ptr(p); | |
> add_token_ref(split_bot_mark); | |
> end; | |
> if link(p)=q then | |
> begin link(p):=null; goto done; | |
> end; | |
> p:=link(p); | |
> end; | |
15586c18992,18993 | |
< @* \[44] The page builder. | |
--- | |
> | |
> @* \[45] The page builder. | |
15589,15590c18996,18997 | |
< the calculations are done ``on line'' as new items are placed on the list. | |
< The main complication in this process is that insertions have to be put | |
--- | |
> the calculations are done ``on line'' as new items come in. | |
> The main complication in this process is that insertions must be put | |
15608,15609c19015,19016 | |
< the current |vsize| and |max_depth| are squirreled away into |page_size| | |
< and |page_depth_max|; the latter values will be used until the page has | |
--- | |
> the current |vsize| and |max_depth| are squirreled away into |page_goal| | |
> and |page_max_depth|; the latter values will be used until the page has | |
15613c19020 | |
< Although |page_size| starts out equal to |vsize|, it is decreased by the | |
--- | |
> Although |page_goal| starts out equal to |vsize|, it is decreased by the | |
15619,15623c19026,19031 | |
< The variables |best_page_break| and |least_page_badness| correspond to the | |
< variables |best_place| and |least_badness| in the |vert_break| routine | |
< that we have already studied; i.e., they record the location and value of | |
< the best place currently known for breaking the current page. The value of | |
< |page_size| at the time of the best break is stored in |best_size|. | |
--- | |
> The global variables |best_page_break| and |least_page_cost| correspond | |
> respectively to the local variables |best_place| and |least_cost| in the | |
> |vert_break| routine that we have already studied; i.e., they record the | |
> location and value of the best place currently known for breaking the | |
> current page. The value of |page_goal| at the time of the best break is | |
> stored in |best_size|. | |
15626c19034 | |
< {|page_contents| when an insert node has been contributed, but no boxes} | |
--- | |
> {|page_contents| when an insert node has been contributed, but no boxes} | |
15632,15633c19040 | |
< @!page_size:scaled; {desired height of information on page being built} | |
< @!page_depth_max:scaled; {maximum box depth on page being built} | |
--- | |
> @!page_max_depth:scaled; {maximum box depth on page being built} | |
15635,15636c19042,19043 | |
< @!least_page_badness:integer; {the score for this currently best page} | |
< @!best_size:scaled; {its |page_size|} | |
--- | |
> @!least_page_cost:integer; {the score for this currently best page} | |
> @!best_size:scaled; {its |page_goal|} | |
15640,15642c19047,19049 | |
< That is, the first element of the list is node |r@t$↓1$@>=link(page_ins_head)|; | |
< node $r↓j$ is followed by |r@t$↓{j+1}$@>=link(r@t$↓j$@>)|; and if there are | |
< |n| items we have |r@t$↓{n+1}$@>=page_ins_head|. The |subtype| field of | |
--- | |
> That is, the first element of the list is node |r@t$_1$@>=link(page_ins_head)|; | |
> node $r_j$ is followed by |r@t$_{j+1}$@>=link(r@t$_j$@>)|; and if there are | |
> |n| items we have |r@t$_{n+1}$@>=page_ins_head|. The |subtype| field of | |
15653c19060 | |
< If |type(r)=inserting|, then |width(r)| contains the total of the | |
--- | |
> If |type(r)=inserting|, then |height(r)| contains the total of the | |
15659c19066 | |
< insertion node that was tentatively split, and |width(r)| includes the | |
--- | |
> insertion node that was tentatively split, and |height(r)| includes also the | |
15669a19077,19080 | |
> The data structure definitions here use the fact that the |@!height| field | |
> appears in the fourth word of a box node. | |
> @^data structure assumptions@> | |
> | |
15673,15675c19084,19086 | |
< @d broken_ptr(#)==link(#+3) | |
< {an insertion for this class will break here if anywhere} | |
< @d broken_ins(#)==info(#+3) {this insertion might break at |broken_ptr|} | |
--- | |
> @d broken_ptr(#)==link(#+1) | |
> {an insertion for this class will break here if anywhere} | |
> @d broken_ins(#)==info(#+1) {this insertion might break at |broken_ptr|} | |
15680,15681c19091,19092 | |
< subtype(page_ins_head)←qi(255); | |
< type(page_ins_head)←split_up; link(page_ins_head)←page_ins_head; | |
--- | |
> subtype(page_ins_head):=qi(255); | |
> type(page_ins_head):=split_up; link(page_ins_head):=page_ins_head; | |
15683c19094 | |
< @ An array |page_so_far| records the heights and depths of everything that | |
--- | |
> @ An array |page_so_far| records the heights and depths of everything | |
15685,15686c19096,19099 | |
< similar arrays already considered in |line_break| and |vert_break|. The | |
< value of |page_so_far[1]| is also called |cur_page_height|. The stretch | |
--- | |
> similar arrays already considered in |line_break| and |vert_break|; and it | |
> also contains |page_goal| and |page_depth|, since these values are | |
> all accessible to the user via |set_page_dimen| commands. The | |
> value of |page_so_far[1]| is also called |page_total|. The stretch | |
15689c19102,19142 | |
< corrections are not, since they have been subtracted from |page_size|. | |
--- | |
> corrections are not, since they have been subtracted from |page_goal|. | |
> | |
> The variable |page_depth| records the depth of the current page; it has been | |
> adjusted so that it is at most |page_max_depth|. The variable | |
> |last_glue| points to the glue specification of the most recent node | |
> contributed from the contribution list, if this was a glue node; otherwise | |
> |last_glue=max_halfword|. (If the contribution list is nonempty, | |
> however, the value of |last_glue| is not necessarily accurate.) | |
> The variables |last_penalty| and |last_kern| are similar. And | |
> finally, |insert_penalties| holds the sum of the penalties associated with | |
> all split and floating insertions. | |
> | |
> @d page_goal==page_so_far[0] {desired height of information on page being built} | |
> @d page_total==page_so_far[1] {height of the current page} | |
> @d page_shrink==page_so_far[6] {shrinkability of the current page} | |
> @d page_depth==page_so_far[7] {depth of the current page} | |
> | |
> @<Glob...@>= | |
> @!page_so_far:array [0..7] of scaled; {height and glue of the current page} | |
> @!last_glue:pointer; {used to implement \.{\\lastskip}} | |
> @!last_penalty:integer; {used to implement \.{\\lastpenalty}} | |
> @!last_kern:scaled; {used to implement \.{\\lastkern}} | |
> @!insert_penalties:integer; {sum of the penalties for held-over insertions} | |
> | |
> @ @<Put each...@>= | |
> primitive("pagegoal",set_page_dimen,0); | |
> @!@:page_goal_}{\.{\\pagegoal} primitive@> | |
> primitive("pagetotal",set_page_dimen,1); | |
> @!@:page_total_}{\.{\\pagetotal} primitive@> | |
> primitive("pagestretch",set_page_dimen,2); | |
> @!@:page_stretch_}{\.{\\pagestretch} primitive@> | |
> primitive("pagefilstretch",set_page_dimen,3); | |
> @!@:page_fil_stretch_}{\.{\\pagefilstretch} primitive@> | |
> primitive("pagefillstretch",set_page_dimen,4); | |
> @!@:page_fill_stretch_}{\.{\\pagefillstretch} primitive@> | |
> primitive("pagefilllstretch",set_page_dimen,5); | |
> @!@:page_filll_stretch_}{\.{\\pagefilllstretch} primitive@> | |
> primitive("pageshrink",set_page_dimen,6); | |
> @!@:page_shrink_}{\.{\\pageshrink} primitive@> | |
> primitive("pagedepth",set_page_dimen,7); | |
> @!@:page_depth_}{\.{\\pagedepth} primitive@> | |
15691,15706c19144,19154 | |
< Another variable, |cur_page_depth|, records the depth of the current page, | |
< adjusted to be at most |page_depth_max|. The variable |last_page_glue| | |
< points to the glue specification of the most recent node contributed from | |
< the contribution list, if this was a glue node; otherwise | |
< |last_page_glue=max_halfword|. (If the contribution list is nonempty, | |
< however, the value of |last_page_glue| is not necessarily accurate.) And | |
< finally, |ins_penalties| holds the sum of the penalties associated with | |
< all split insertions. | |
< | |
< @d cur_page_height==page_so_far[1] {height of the current page} | |
< | |
< @<Glob...@>= | |
< @!page_so_far:array [1..6] of scaled; {height and glue of the current page} | |
< @!cur_page_depth:scaled; {depth of the current page} | |
< @!last_page_glue:pointer; {used to implement \.{\\lastskip}} | |
< @!ins_penalties:integer; {sum of the penalties for split insertions} | |
--- | |
> @ @<Cases of |print_cmd_chr|...@>= | |
> set_page_dimen: case chr_code of | |
> 0: print_esc("pagegoal"); | |
> 1: print_esc("pagetotal"); | |
> 2: print_esc("pagestretch"); | |
> 3: print_esc("pagefilstretch"); | |
> 4: print_esc("pagefillstretch"); | |
> 5: print_esc("pagefilllstretch"); | |
> 6: print_esc("pageshrink"); | |
> othercases print_esc("pagedepth") | |
> endcases; | |
15709,15710c19157,19158 | |
< @d print_plus(#)==if page_so_far[#]≠0 then | |
< begin print(" plus "); print_scaled(page_so_far[#]); print_plus_end | |
--- | |
> @d print_plus(#)==if page_so_far[#]<>0 then | |
> begin print(" plus "); print_scaled(page_so_far[#]); print_plus_end | |
15712,15738c19160,19199 | |
< @<Show the status of the current page@>= | |
< show_box(link(page_head)); | |
< if page_contents>empty then | |
< begin print_nl("total height "); print_scaled(page_so_far[1]); | |
< print_plus(2)(""); | |
< print_plus(3)("fil"); | |
< print_plus(4)("fill"); | |
< print_plus(5)("filll"); | |
< if page_so_far[6]≠0 then | |
< begin print(" minus "); print_scaled(page_so_far[6]); | |
< end; | |
< print_nl(" goal height"); print_scaled(page_size); | |
< r←link(page_ins_head); | |
< while r≠page_ins_head do | |
< begin print_ln; print_esc("insert"); a←qo(subtype(r)); | |
< print_int(a); print(" adds "); | |
< a←x_over_n(width(r),1000)*count(a); print_scaled(a); | |
< if type(r)=split_up then | |
< begin q←page_head; a←0; | |
< repeat q←link(q); | |
< if (type(q)=ins_node)∧(subtype(q)=subtype(r)) then incr(a); | |
< until q=broken_ins(r); | |
< print(", #"); print_int(a); print(" might split"); | |
< end; | |
< r←link(r); | |
< end; | |
< end | |
--- | |
> @p procedure print_totals; | |
> begin print_scaled(page_total); | |
> print_plus(2)(""); | |
> print_plus(3)("fil"); | |
> print_plus(4)("fill"); | |
> print_plus(5)("filll"); | |
> if page_shrink<>0 then | |
> begin print(" minus "); print_scaled(page_shrink); | |
> end; | |
> end; | |
> | |
> @ @<Show the status of the current page@>= | |
> if page_head<>page_tail then | |
> begin print_nl("### current page:"); | |
> if output_active then print(" (held over for next output)"); | |
> @.held over for next output@> | |
> show_box(link(page_head)); | |
> if page_contents>empty then | |
> begin print_nl("total height "); print_totals; | |
> @:total_height}{\.{total height}@> | |
> print_nl(" goal height "); print_scaled(page_goal); | |
> @.goal height@> | |
> r:=link(page_ins_head); | |
> while r<>page_ins_head do | |
> begin print_ln; print_esc("insert"); t:=qo(subtype(r)); | |
> print_int(t); print(" adds "); | |
> if count(t)=1000 then t:=height(r) | |
> else t:=x_over_n(height(r),1000)*count(t); | |
> print_scaled(t); | |
> if type(r)=split_up then | |
> begin q:=page_head; t:=0; | |
> repeat q:=link(q); | |
> if (type(q)=ins_node)and(subtype(q)=subtype(r)) then incr(t); | |
> until q=broken_ins(r); | |
> print(", #"); print_int(t); print(" might split"); | |
> end; | |
> r:=link(r); | |
> end; | |
> end; | |
> end | |
15743c19204 | |
< @d set_page_so_far_zero(#)==page_so_far[#]←0 | |
--- | |
> @d set_page_so_far_zero(#)==page_so_far[#]:=0 | |
15746,15749c19207,19217 | |
< begin page_contents←s; | |
< page_size←vsize; page_depth_max←max_depth; | |
< cur_page_depth←0; do_all_six(set_page_so_far_zero); | |
< least_page_badness←awful_bad; | |
--- | |
> begin page_contents:=s; | |
> page_goal:=vsize; page_max_depth:=max_depth; | |
> page_depth:=0; do_all_six(set_page_so_far_zero); | |
> least_page_cost:=awful_bad; | |
> @!stat if tracing_pages>0 then | |
> begin begin_diagnostic; | |
> print_nl("%% goal height="); print_scaled(page_goal); | |
> @.goal height@> | |
> print(", max depth="); print_scaled(page_max_depth); | |
> end_diagnostic(false); | |
> end;@;@+tats@;@/ | |
15759c19227,19228 | |
< generated by other parts of \TeX\ but not yet seen by the page builder. | |
--- | |
> generated by other parts of \TeX\ but have not yet been | |
> seen by the page builder. | |
15776c19245 | |
< type(page_head)←glue_node; subtype(page_head)←normal; | |
--- | |
> type(page_head):=glue_node; subtype(page_head):=normal; | |
15785c19254 | |
< output_active←false; | |
--- | |
> output_active:=false; insert_penalties:=0; | |
15792,15794c19261,19292 | |
< page_contents←empty; page_tail←page_head; link(page_head)←null;@/ | |
< last_page_glue←max_halfword; ins_penalties←0; | |
< cur_page_depth←0; page_depth_max←0; | |
--- | |
> page_contents:=empty; page_tail:=page_head; link(page_head):=null;@/ | |
> last_glue:=max_halfword; last_penalty:=0; last_kern:=0; | |
> page_depth:=0; page_max_depth:=0 | |
> | |
> @ At certain times box 255 is supposed to be void (i.e., |null|), | |
> or an insertion box is supposed to be ready to accept a vertical list. | |
> If not, an error message is printed, and the following subroutine | |
> flushes the unwanted contents, reporting them to the user. | |
> | |
> @p procedure box_error(@!n:eight_bits); | |
> begin error; begin_diagnostic; | |
> print_nl("The following box has been deleted:"); | |
> @.The following...deleted@> | |
> show_box(box(n)); end_diagnostic(true); | |
> flush_node_list(box(n)); box(n):=null; | |
> end; | |
> | |
> @ The following procedure guarantees that a given box register | |
> does not contain an \.{\\hbox}. | |
> | |
> @p procedure ensure_vbox(@!n:eight_bits); | |
> var p:pointer; {the box register contents} | |
> begin p:=box(n); | |
> if p<>null then if type(p)=hlist_node then | |
> begin print_err("Insertions can only be added to a vbox"); | |
> @.Insertions can only...@> | |
> help3("Tut tut: You're trying to \insert into a")@/ | |
> ("\box register that now contains an \hbox.")@/ | |
> ("Proceed, and I'll discard its present contents."); | |
> box_error(n); | |
> end; | |
> end; | |
15804c19302,19303 | |
< @p procedure build_page; {append contributions to the current page} | |
--- | |
> @p @t\4@>@<Declare the procedure called |fire_up|@>@;@/ | |
> procedure build_page; {append contributions to the current page} | |
15807,15809c19306,19307 | |
< @!q,@!r,@!s:pointer; {nodes being examined} | |
< @!prev_p:pointer; {precedessor of |p|} | |
< @!b:integer; {badness of current page} | |
--- | |
> @!q,@!r:pointer; {nodes being examined} | |
> @!b,@!c:integer; {badness and cost of current page} | |
15813,15816c19311,19313 | |
< @!wait:boolean; {should the present insertion be held over?} | |
< begin if (link(contrib_head)=null)∨ output_active then return; | |
< repeat continue: p←link(contrib_head);@/ | |
< @<Update the value of |last_page_glue|@>; | |
--- | |
> begin if (link(contrib_head)=null)or output_active then return; | |
> repeat continue: p:=link(contrib_head);@/ | |
> @<Update the values of |last_glue|, |last_penalty|, and |last_kern|@>; | |
15818,15819c19315,19316 | |
< put the nodes following the break back onto the contribution list, | |
< and |return| to the user's output routine if there is one@>; | |
--- | |
> put the nodes following the break back onto the contribution list, | |
> and |return| to the user's output routine if there is one@>; | |
15827,15828c19324,19325 | |
< if nest_ptr=0 then tail←contrib_head {vertical mode} | |
< else contrib_tail←contrib_head {other modes} | |
--- | |
> if nest_ptr=0 then tail:=contrib_head {vertical mode} | |
> else contrib_tail:=contrib_head {other modes} | |
15830,15831c19327,19329 | |
< @ @<Update the value of |last_page_glue|@>= | |
< if last_page_glue≠max_halfword then delete_glue_ref(last_page_glue); | |
--- | |
> @ @<Update the values of |last_glue|...@>= | |
> if last_glue<>max_halfword then delete_glue_ref(last_glue); | |
> last_penalty:=0; last_kern:=0; | |
15833,15835c19331,19336 | |
< begin last_page_glue←glue_ptr(p); add_glue_ref(last_page_glue); | |
< end | |
< else last_page_glue←max_halfword | |
--- | |
> begin last_glue:=glue_ptr(p); add_glue_ref(last_glue); | |
> end | |
> else begin last_glue:=max_halfword; | |
> if type(p)=penalty_node then last_penalty:=penalty(p) | |
> else if type(p)=kern_node then last_kern:=width(p); | |
> end | |
15845,15848c19346,19349 | |
< otherwise use node |p| to update the state of the current page; | |
< if this node is an insertion, |goto contribute|; otherwise if this node | |
< is not a legal breakpoint, |goto contribute| or |update_heights|; | |
< otherwise set |pi| to the penalty associated with this breakpoint@>; | |
--- | |
> otherwise use node |p| to update the state of the current page; | |
> if this node is an insertion, |goto contribute|; otherwise if this node | |
> is not a legal breakpoint, |goto contribute| or |update_heights|; | |
> otherwise set |pi| to the penalty associated with this breakpoint@>; | |
15850,15852c19351,19353 | |
< a page break, prepare for output, and either fire up the user's | |
< output routine and |return| or ship out the page and |goto done|@>; | |
< if (type(p)<glue_node)∨(type(p)>kern_node) then goto contribute; | |
--- | |
> a page break, prepare for output, and either fire up the user's | |
> output routine and |return| or ship out the page and |goto done|@>; | |
> if (type(p)<glue_node)or(type(p)>kern_node) then goto contribute; | |
15854,15855c19355,19356 | |
< glue or kern specified by node |p|@>; | |
< contribute: @<Make sure that |page_depth_max| is not exceeded@>; | |
--- | |
> glue or kern specified by node~|p|@>; | |
> contribute: @<Make sure that |page_max_depth| is not exceeded@>; | |
15861,15862c19362,19363 | |
< link(page_tail)←p; page_tail←p; | |
< link(contrib_head)←link(p); link(p)←null; goto done | |
--- | |
> link(page_tail):=p; page_tail:=p; | |
> link(contrib_head):=link(p); link(p):=null; goto done | |
15865c19366 | |
< link(contrib_head)←link(p); link(p)←null; flush_node_list(p) | |
--- | |
> link(contrib_head):=link(p); link(p):=null; flush_node_list(p) | |
15875,15878c19376,19379 | |
< @<Initialize the current page, insert the \.{\\topskip} glue | |
< ahead of |p|, and |goto continue|@> | |
< else @<Prepare to move a box or rule node to the current page, | |
< then |goto contribute|@>; | |
--- | |
> @<Initialize the current page, insert the \.{\\topskip} glue | |
> ahead of |p|, and |goto continue|@> | |
> else @<Prepare to move a box or rule node to the current page, | |
> then |goto contribute|@>; | |
15880c19381 | |
< then |goto contribute|@>; | |
--- | |
> then |goto contribute|@>; | |
15882,15883c19383,19384 | |
< else if precedes_break(page_tail) then pi←0 | |
< else goto update_heights; | |
--- | |
> else if precedes_break(page_tail) then pi:=0 | |
> else goto update_heights; | |
15885,15888c19386,19389 | |
< else if link(p)=null then return | |
< else if type(link(p))=glue_node then pi←0 | |
< else goto update_heights; | |
< penalty_node: if page_contents<box_there then goto done1@+else pi←penalty(p); | |
--- | |
> else if link(p)=null then return | |
> else if type(link(p))=glue_node then pi:=0 | |
> else goto update_heights; | |
> penalty_node: if page_contents<box_there then goto done1@+else pi:=penalty(p); | |
15892c19393 | |
< @:confusion page}{\quad page@> | |
--- | |
> @:this can't happen page}{\quad page@> | |
15897,15901c19398,19402 | |
< else page_contents←box_there; | |
< q←new_skip_param(top_skip_code); link(q)←p; {now |temp_ptr=glue_ptr(q)|} | |
< if width(temp_ptr)>height(p) then width(temp_ptr)←width(temp_ptr)-height(p) | |
< else width(temp_ptr)←0; | |
< link(q)←p; link(contrib_head)←q; goto continue; | |
--- | |
> else page_contents:=box_there; | |
> q:=new_skip_param(top_skip_code); {now |temp_ptr=glue_ptr(q)|} | |
> if width(temp_ptr)>height(p) then width(temp_ptr):=width(temp_ptr)-height(p) | |
> else width(temp_ptr):=0; | |
> link(q):=p; link(contrib_head):=q; goto continue; | |
15905,15906c19406,19407 | |
< begin cur_page_height←cur_page_height+cur_page_depth+height(p); | |
< cur_page_depth←depth(p); | |
--- | |
> begin page_total:=page_total+page_depth+height(p); | |
> page_depth:=depth(p); | |
15910,15915c19411,19416 | |
< @ @<Make sure that |page_depth_max| is not exceeded@>= | |
< if cur_page_depth>page_depth_max then | |
< begin cur_page_height←@| | |
< cur_page_height+cur_page_depth-page_depth_max;@/ | |
< cur_page_depth←page_depth_max; | |
< end; | |
--- | |
> @ @<Make sure that |page_max_depth| is not exceeded@>= | |
> if page_depth>page_max_depth then | |
> begin page_total:=@| | |
> page_total+page_depth-page_max_depth;@/ | |
> page_depth:=page_max_depth; | |
> end; | |
15918,15925c19419,19426 | |
< if type(p)=kern_node then q←p | |
< else begin q←glue_ptr(p); | |
< page_so_far[2+stretch_order(q)]←@| | |
< page_so_far[2+stretch_order(q)]+stretch(q);@/ | |
< page_so_far[6]←page_so_far[6]+shrink(q); | |
< if (shrink_order(q)≠normal)∧(shrink(q)≠0) then | |
< begin@t@>@;@/ | |
< print_nl("! Infinite glue shrinkage found on current page");@/ | |
--- | |
> if type(p)=kern_node then q:=p | |
> else begin q:=glue_ptr(p); | |
> page_so_far[2+stretch_order(q)]:=@| | |
> page_so_far[2+stretch_order(q)]+stretch(q);@/ | |
> page_shrink:=page_shrink+shrink(q); | |
> if (shrink_order(q)<>normal)and(shrink(q)<>0) then | |
> begin@t@>@;@/ | |
> print_err("Infinite glue shrinkage found on current page");@/ | |
15927,15936c19428,19437 | |
< help4("The page about to be output contains some infinitely")@/ | |
< ("shrinkable glue, e.g., `\vss' or `\vskip 0pt minus 1fil'.")@/ | |
< ("Such glue doesn't belong there; but you can safely proceed,")@/ | |
< ("since the offensive shrinkability has been made finite."); | |
< error; | |
< r←new_spec(q); shrink_order(r)←normal; delete_glue_ref(q); | |
< glue_ptr(p)←r; | |
< end; | |
< end; | |
< cur_page_height←cur_page_height+cur_page_depth+width(q); cur_page_depth←0 | |
--- | |
> help4("The page about to be output contains some infinitely")@/ | |
> ("shrinkable glue, e.g., `\vss' or `\vskip 0pt minus 1fil'.")@/ | |
> ("Such glue doesn't belong there; but you can safely proceed,")@/ | |
> ("since the offensive shrinkability has been made finite."); | |
> error; | |
> r:=new_spec(q); shrink_order(r):=normal; delete_glue_ref(q); | |
> glue_ptr(p):=r; q:=r; | |
> end; | |
> end; | |
> page_total:=page_total+page_depth+width(q); page_depth:=0 | |
15940,15958c19441,19478 | |
< begin @<Compute the badness, |b|, of the current page, | |
< using |awful_bad| if the box is too full@>; | |
< if b≤inf_bad then | |
< if pi≤eject_penalty then b←pi | |
< else b←b+pi+ins_penalties; | |
< if b≤least_page_badness then | |
< begin best_page_break←p; best_size←page_size; | |
< least_page_badness←b; | |
< r←link(page_ins_head); | |
< while r≠page_ins_head do | |
< begin best_ins_ptr(r)←last_ins_ptr(r); | |
< r←link(r); | |
< end; | |
< end; | |
< if (b=awful_bad)∨(pi≤eject_penalty) then | |
< @<Prepare to output the current page at the best place; | |
< then fire up the user's output routine and |return|, | |
< or ship out the page and |goto done|@>; | |
< end | |
--- | |
> begin @<Compute the badness, |b|, of the current page, | |
> using |awful_bad| if the box is too full@>; | |
> if b<awful_bad then | |
> if pi<=eject_penalty then c:=pi | |
> else if b<inf_bad then c:=b+pi+insert_penalties | |
> else c:=deplorable | |
> else c:=b; | |
> if insert_penalties>=10000 then c:=awful_bad; | |
> @!stat if tracing_pages>0 then @<Display the page break cost@>;@+tats@;@/ | |
> if c<=least_page_cost then | |
> begin best_page_break:=p; best_size:=page_goal; | |
> least_page_cost:=c; | |
> r:=link(page_ins_head); | |
> while r<>page_ins_head do | |
> begin best_ins_ptr(r):=last_ins_ptr(r); | |
> r:=link(r); | |
> end; | |
> end; | |
> if (c=awful_bad)or(pi<=eject_penalty) then | |
> begin fire_up(p); {output the current page at the best place} | |
> if output_active then return; {user's output routine will act} | |
> goto done; {the page has been shipped out by default output routine} | |
> end; | |
> end | |
> | |
> @ @<Display the page break cost@>= | |
> begin begin_diagnostic; print_nl("%"); | |
> print(" t="); print_totals;@/ | |
> print(" g="); print_scaled(page_goal);@/ | |
> print(" b="); | |
> if b=awful_bad then print_char("*")@+else print_int(b); | |
> @.*\relax@> | |
> print(" p="); print_int(pi); | |
> print(" c="); | |
> if c=awful_bad then print_char("*")@+else print_int(c); | |
> if c<=least_page_cost then print_char("#"); | |
> end_diagnostic(false); | |
> end | |
15961,15966c19481,19486 | |
< if cur_page_height<page_size then | |
< if (page_so_far[3]≠0) or (page_so_far[4]≠0) or@| | |
< (page_so_far[5]≠0) then b←0 | |
< else b←badness(page_size-cur_page_height,page_so_far[2]) | |
< else if cur_page_height-page_size>page_so_far[6] then b←awful_bad | |
< else b←badness(cur_page_height-page_size,page_so_far[6]) | |
--- | |
> if page_total<page_goal then | |
> if (page_so_far[3]<>0) or (page_so_far[4]<>0) or@| | |
> (page_so_far[5]<>0) then b:=0 | |
> else b:=badness(page_goal-page_total,page_so_far[2]) | |
> else if page_total-page_goal>page_shrink then b:=awful_bad | |
> else b:=badness(page_total-page_goal,page_shrink) | |
15970,15987c19490,19508 | |
< n←subtype(p); r←page_ins_head; | |
< while n≥subtype(link(r)) do r←link(r); | |
< n←qo(n); | |
< if subtype(r)≠qi(n) then | |
< @<Create a page insertion node with |subtype(r)=qi(n)|, and | |
< include the glue correction for box |n| in the | |
< current page state@>; | |
< if type(r)=inserting then | |
< begin last_ins_ptr(r)←p; | |
< delta←page_size-cur_page_height+page_so_far[6]; | |
< {this much room is left if we shrink the maximum} | |
< h←x_over_n(width(p),1000)*count(n); {this much room is needed} | |
< if (h≤delta)∧(width(p)+width(r)≤dimen(n)) then | |
< begin page_size←page_size-h; width(r)←width(r)+width(p); | |
< end | |
< else @<Find the best way to split the insertion, and change | |
< |type(r)| to |split_up|@>; | |
< end; | |
--- | |
> n:=subtype(p); r:=page_ins_head; | |
> while n>=subtype(link(r)) do r:=link(r); | |
> n:=qo(n); | |
> if subtype(r)<>qi(n) then | |
> @<Create a page insertion node with |subtype(r)=qi(n)|, and | |
> include the glue correction for box |n| in the | |
> current page state@>; | |
> if type(r)=split_up then insert_penalties:=insert_penalties+float_cost(p) | |
> else begin last_ins_ptr(r):=p; | |
> delta:=page_goal-page_total-page_depth+page_shrink; | |
> {this much room is left if we shrink the maximum} | |
> if count(n)=1000 then h:=height(p) | |
> else h:=x_over_n(height(p),1000)*count(n); {this much room is needed} | |
> if ((h<=0)or(h<=delta))and(height(p)+height(r)<=dimen(n)) then | |
> begin page_goal:=page_goal-h; height(r):=height(r)+height(p); | |
> end | |
> else @<Find the best way to split the insertion, and change | |
> |type(r)| to |split_up|@>; | |
> end; | |
15992,15994c19513,19515 | |
< of \.{\\box}@@|n| only when the first \.{\\insert}@@|n| node is | |
< encountered for a new page. A user who changes the contents of \.{\\box}@@|n| | |
< after that first \.{\\insert}@@|n| had better be either extremely careful | |
--- | |
> of \.{\\box}~|n| only when the first \.{\\insert}~|n| node is | |
> encountered for a new page. A user who changes the contents of \.{\\box}~|n| | |
> after that first \.{\\insert}~|n| had better be either extremely careful | |
15998,16016c19519,19538 | |
< begin q←get_node(page_ins_node_size); link(q)←link(r); link(r)←q; r←q; | |
< subtype(r)←qi(n); type(r)←inserting; | |
< if box(n)=null then width(r)←0 | |
< else width(r)←height(box(n))+depth(box(n)); | |
< best_ins_ptr(r)←null;@/ | |
< q←skip(n); h←x_over_n(width(r),1000)*count(n); | |
< page_size←page_size-h;@/ | |
< page_so_far[1]←page_so_far[1]+width(q);@/ | |
< page_so_far[2+stretch_order(q)]←@|page_so_far[2+stretch_order(q)]+stretch(q);@/ | |
< page_so_far[6]←page_so_far[6]+shrink(q); | |
< if (shrink_order(q)≠normal)∧(shrink(q)≠0) then | |
< begin print_nl("! Infinite glue shrinkage inserted from \skip "); | |
< @.Infinite glue shrinkage@> | |
< print_int(n); | |
< help3("The correction glue for page breaking with insertions")@/ | |
< ("must have finite shrinkability. But you may proceed,")@/ | |
< ("since the offensive shrinkability has been made finite."); | |
< error; | |
< end; | |
--- | |
> begin q:=get_node(page_ins_node_size); link(q):=link(r); link(r):=q; r:=q; | |
> subtype(r):=qi(n); type(r):=inserting; ensure_vbox(n); | |
> if box(n)=null then height(r):=0 | |
> else height(r):=height(box(n))+depth(box(n)); | |
> best_ins_ptr(r):=null;@/ | |
> q:=skip(n); | |
> if count(n)=1000 then h:=height(r) | |
> else h:=x_over_n(height(r),1000)*count(n); | |
> page_goal:=page_goal-h-width(q);@/ | |
> page_so_far[2+stretch_order(q)]:=@|page_so_far[2+stretch_order(q)]+stretch(q);@/ | |
> page_shrink:=page_shrink+shrink(q); | |
> if (shrink_order(q)<>normal)and(shrink(q)<>0) then | |
> begin print_err("Infinite glue shrinkage inserted from "); print_esc("skip"); | |
> @.Infinite glue shrinkage...@> | |
> print_int(n); | |
> help3("The correction glue for page breaking with insertions")@/ | |
> ("must have finite shrinkability. But you may proceed,")@/ | |
> ("since the offensive shrinkability has been made finite."); | |
> error; | |
> end; | |
16030,16039c19552,19577 | |
< begin if count(n)≤0 then w←max_dimen | |
< else w←x_over_n(delta,count(n))*1000; | |
< if w>dimen(n)-width(r) then w←dimen(n)-width(r); | |
< q←vert_break(ins_ptr(p),w); | |
< width(r)←width(r)+best_height_plus_depth; | |
< best_height_plus_depth←x_over_n(best_height_plus_depth,1000)*count(n); | |
< page_size←page_size-best_height_plus_depth; | |
< type(r)←split_up; broken_ptr(r)←q; broken_ins(r)←p; | |
< if q=null then ins_penalties←ins_penalties+eject_penalty | |
< else if type(q)=penalty_node then ins_penalties←ins_penalties+penalty(q); | |
--- | |
> begin if count(n)<=0 then w:=max_dimen | |
> else begin w:=page_goal-page_total-page_depth; | |
> if count(n)<>1000 then w:=x_over_n(w,count(n))*1000; | |
> end; | |
> if w>dimen(n)-height(r) then w:=dimen(n)-height(r); | |
> q:=vert_break(ins_ptr(p),w,depth(p)); | |
> height(r):=height(r)+best_height_plus_depth; | |
> @!stat if tracing_pages>0 then @<Display the insertion split cost@>;@+tats@;@/ | |
> if count(n)<>1000 then | |
> best_height_plus_depth:=x_over_n(best_height_plus_depth,1000)*count(n); | |
> page_goal:=page_goal-best_height_plus_depth; | |
> type(r):=split_up; broken_ptr(r):=q; broken_ins(r):=p; | |
> if q=null then insert_penalties:=insert_penalties+eject_penalty | |
> else if type(q)=penalty_node then insert_penalties:=insert_penalties+penalty(q); | |
> end | |
> | |
> @ @<Display the insertion split cost@>= | |
> begin begin_diagnostic; print_nl("% split"); print_int(n); | |
> @.split@> | |
> print(" to "); print_scaled(w); | |
> print_char(","); print_scaled(best_height_plus_depth);@/ | |
> print(" p="); | |
> if q=null then print_int(eject_penalty) | |
> else if type(q)=penalty_node then print_int(penalty(q)) | |
> else print_char("0"); | |
> end_diagnostic(false); | |
16048,16049c19586,19593 | |
< program uses the fact that |bot_mark≠null| implies |first_mark≠null|; | |
< |bot_mark=null| implies |top_mark=first_mark=null|. | |
--- | |
> program uses the fact that |bot_mark<>null| implies |first_mark<>null|; | |
> it also knows that |bot_mark=null| implies |top_mark=first_mark=null|. | |
> | |
> The |fire_up| subroutine prepares to output the current page at the best | |
> place; then it fires up the user's output routine, if there is one, | |
> or it simply ships out the page. There is one parameter, |c|, which represents | |
> the node that was being contributed to the page when the decision to | |
> force an output was made. | |
16051c19595,19604 | |
< @<Prepare to output the current page at the best place...@>= | |
--- | |
> @<Declare the procedure called |fire_up|@>= | |
> procedure fire_up(@!c:pointer); | |
> label exit; | |
> var p,@!q,@!r,@!s:pointer; {nodes being examined and/or changed} | |
> @!prev_p:pointer; {predecessor of |p|} | |
> @!n:min_quarterword..255; {insertion box number} | |
> @!wait:boolean; {should the present insertion be held over?} | |
> @!save_vbadness:integer; {saved value of |vbadness|} | |
> @!save_vfuzz: scaled; {saved value of |vfuzz|} | |
> @!save_split_top_skip: pointer; {saved value of |split_top_skip|} | |
16053,16057c19606,19610 | |
< if bot_mark≠null then | |
< begin if top_mark≠null then delete_token_ref(top_mark); | |
< top_mark←bot_mark; add_token_ref(top_mark); | |
< delete_token_ref(first_mark); first_mark←null; | |
< end; | |
--- | |
> if bot_mark<>null then | |
> begin if top_mark<>null then delete_token_ref(top_mark); | |
> top_mark:=bot_mark; add_token_ref(top_mark); | |
> delete_token_ref(first_mark); first_mark:=null; | |
> end; | |
16059,16066c19612,19622 | |
< |bot_mark|, append insertions to their boxes, and put the | |
< remaining nodes back on the contribution list@>; | |
< if (top_mark≠null)∧(first_mark=null) then | |
< begin first_mark←top_mark; add_token_ref(top_mark); | |
< end; | |
< if output_routine≠null then @<Fire up the user's output routine and |return|@> | |
< else @<Perform the default output routine and |goto done|@>; | |
< end | |
--- | |
> |bot_mark|, append insertions to their boxes, and put the | |
> remaining nodes back on the contribution list@>; | |
> if (top_mark<>null)and(first_mark=null) then | |
> begin first_mark:=top_mark; add_token_ref(top_mark); | |
> end; | |
> if output_routine<>null then | |
> if dead_cycles>=max_dead_cycles then | |
> @<Explain that too many dead cycles have occurred in a row@> | |
> else @<Fire up the user's output routine and |return|@>; | |
> @<Perform the default output routine@>; | |
> exit:end; | |
16070,16072c19626,19628 | |
< begin geq_word_define(int_base+output_penalty_code,penalty(best_page_break)); | |
< penalty(best_page_break)←inf_penalty; | |
< end | |
--- | |
> begin geq_word_define(int_base+output_penalty_code,penalty(best_page_break)); | |
> penalty(best_page_break):=inf_penalty; | |
> end | |
16075,16076c19631,19633 | |
< @ As the page is finally being prepared for output, |p| runs through the vlist, | |
< with |prev_p| trailing behind, and |q| is the tail of a list of insertions that | |
--- | |
> @ As the page is finally being prepared for output, | |
> pointer |p| runs through the vlist, with |prev_p| trailing behind; | |
> pointer |q| is the tail of a list of insertions that | |
16080c19637 | |
< if p=best_page_break then best_page_break←null; {|p| not yet linked in} | |
--- | |
> if c=best_page_break then best_page_break:=null; {|c| not yet linked in} | |
16082,16095c19639,19658 | |
< @<Prepare all the boxes involved in insertions to act as queues@>; | |
< q←hold_head; link(q)←null; prev_p←page_head; p←link(prev_p); | |
< while p≠best_page_break do | |
< begin if type(p)=ins_node then @<Either insert the material | |
< specified by node |p| into the appropriate box, or | |
< hold it for the next page; also delete node |p| from | |
< the current page@> | |
< else if type(p)=mark_node then @<Update the values of | |
< |first_mark| and |bot_mark|@>; | |
< prev_p←p; p←link(prev_p); | |
< end; | |
< @<Break the current page at node |p|, put it in box@@255, | |
< and put the remaining nodes on the contribution list@>; | |
< @<Delete the page-insertion nodes@> | |
--- | |
> insert_penalties:=0; {this will count the number of insertions held over} | |
> save_split_top_skip:=split_top_skip; | |
> if holding_inserts<=0 then | |
> @<Prepare all the boxes involved in insertions to act as queues@>; | |
> q:=hold_head; link(q):=null; prev_p:=page_head; p:=link(prev_p); | |
> while p<>best_page_break do | |
> begin if type(p)=ins_node then | |
> begin if holding_inserts<=0 then | |
> @<Either insert the material specified by node |p| into the | |
> appropriate box, or hold it for the next page; | |
> also delete node |p| from the current page@>; | |
> end | |
> else if type(p)=mark_node then @<Update the values of | |
> |first_mark| and |bot_mark|@>; | |
> prev_p:=p; p:=link(prev_p); | |
> end; | |
> split_top_skip:=save_split_top_skip; | |
> @<Break the current page at node |p|, put it in box~255, | |
> and put the remaining nodes on the contribution list@>; | |
> @<Delete \(t)the page-insertion nodes@> | |
16098,16104c19661,19667 | |
< if box(255)≠null then | |
< begin print_nl("! \box255 is not absent"); | |
< @:box255}{\.{\\box255 is not absent}@> | |
< help2("You shouldn't use \box255 except in \output routines.")@/ | |
< ("Proceed, and I'll discard its present contents."); | |
< error; flush_node_list(box(255)); box(255)←null; | |
< end | |
--- | |
> if box(255)<>null then | |
> begin print_err(""); print_esc("box"); print("255 is not void"); | |
> @:box255}{\.{\\box255 is not void}@> | |
> help2("You shouldn't use \box255 except in \output routines.")@/ | |
> ("Proceed, and I'll discard its present contents."); | |
> box_error(255); | |
> end | |
16108,16112c19671,19675 | |
< begin first_mark←mark_ptr(p); | |
< add_token_ref(first_mark); | |
< end; | |
< if bot_mark≠null then delete_token_ref(bot_mark); | |
< bot_mark←mark_ptr(p); add_token_ref(bot_mark); | |
--- | |
> begin first_mark:=mark_ptr(p); | |
> add_token_ref(first_mark); | |
> end; | |
> if bot_mark<>null then delete_token_ref(bot_mark); | |
> bot_mark:=mark_ptr(p); add_token_ref(bot_mark); | |
16121c19684,19687 | |
< and only if |prev_p=page_tail|. | |
--- | |
> and only if |prev_p=page_tail|. Error messages are suppressed within | |
> |vpackage|, since the box might appear to be overfull or underfull simply | |
> because the stretch and shrink from the \.{\\skip} registers for inserts | |
> are not actually present in the box. | |
16124,16136c19690,19706 | |
< if p≠null then | |
< begin if link(contrib_head)=null then | |
< if nest_ptr=0 then tail←page_tail | |
< else contrib_tail←page_tail; | |
< link(page_tail)←link(contrib_head); | |
< link(contrib_head)←p; | |
< link(prev_p)←null; | |
< end; | |
< box(255)←vpackage(link(page_head),best_size,exactly,page_depth_max); | |
< @<Start a new current page@>; | |
< if q≠hold_head then | |
< begin link(page_head)←link(hold_head); page_tail←q; | |
< end | |
--- | |
> if p<>null then | |
> begin if link(contrib_head)=null then | |
> if nest_ptr=0 then tail:=page_tail | |
> else contrib_tail:=page_tail; | |
> link(page_tail):=link(contrib_head); | |
> link(contrib_head):=p; | |
> link(prev_p):=null; | |
> end; | |
> save_vbadness:=vbadness; vbadness:=inf_bad; | |
> save_vfuzz:=vfuzz; vfuzz:=max_dimen; {inhibit error messages} | |
> box(255):=vpackage(link(page_head),best_size,exactly,page_max_depth); | |
> vbadness:=save_vbadness; vfuzz:=save_vfuzz; | |
> if last_glue<>max_halfword then delete_glue_ref(last_glue); | |
> @<Start a new current page@>; {this sets |last_glue:=max_halfword|} | |
> if q<>hold_head then | |
> begin link(page_head):=link(hold_head); page_tail:=q; | |
> end | |
16145,16162c19715,19733 | |
< r←link(page_ins_head); | |
< while r≠page_ins_head do | |
< begin if best_ins_ptr(r)≠null then | |
< begin n←qo(subtype(r)); | |
< if box(n)=null then box(n)←new_null_box; | |
< p←box(n)+list_offset; | |
< while link(p)≠null do p←link(p); | |
< last_ins_ptr(r)←p; | |
< end; | |
< r←link(r); | |
< end | |
< | |
< @ @<Delete the page-insertion nodes@>= | |
< r←link(page_ins_head); | |
< while r≠page_ins_head do | |
< begin q←link(r); free_node(r,page_ins_node_size); r←q; | |
< end; | |
< link(page_ins_head)←page_ins_head | |
--- | |
> begin r:=link(page_ins_head); | |
> while r<>page_ins_head do | |
> begin if best_ins_ptr(r)<>null then | |
> begin n:=qo(subtype(r)); ensure_vbox(n); | |
> if box(n)=null then box(n):=new_null_box; | |
> p:=box(n)+list_offset; | |
> while link(p)<>null do p:=link(p); | |
> last_ins_ptr(r):=p; | |
> end; | |
> r:=link(r); | |
> end; | |
> end | |
> | |
> @ @<Delete \(t)the page-insertion nodes@>= | |
> r:=link(page_ins_head); | |
> while r<>page_ins_head do | |
> begin q:=link(r); free_node(r,page_ins_node_size); r:=q; | |
> end; | |
> link(page_ins_head):=page_ins_head | |
16164,16165c19735,19736 | |
< @ We will set |best_ins_ptr←null| and package the box corresponding to | |
< insertion node@@|r|, just after making the final insertion into that box. | |
--- | |
> @ We will set |best_ins_ptr:=null| and package the box corresponding to | |
> insertion node~|r|, just after making the final insertion into that box. | |
16170,16182c19741,19752 | |
< begin r←link(page_ins_head); | |
< while subtype(r)≠subtype(p) do r←link(r); | |
< if best_ins_ptr(r)=null then wait←true | |
< else begin wait←false; s←ins_ptr(p); {|s≠null|} | |
< link(last_ins_ptr(r))←s; s←last_ins_ptr(r); | |
< if best_ins_ptr(r)=p then | |
< @<Wrap up the box specified by node |r|, splitting node |p| if | |
< called for; set |wait←true| if node |p| holds a remainder after | |
< splitting@> | |
< else begin while link(s)≠null do s←link(s); | |
< last_ins_ptr(r)←s; | |
< end; | |
< end; | |
--- | |
> begin r:=link(page_ins_head); | |
> while subtype(r)<>subtype(p) do r:=link(r); | |
> if best_ins_ptr(r)=null then wait:=true | |
> else begin wait:=false; s:=last_ins_ptr(r); link(s):=ins_ptr(p); | |
> if best_ins_ptr(r)=p then | |
> @<Wrap up the box specified by node |r|, splitting node |p| if | |
> called for; set |wait:=true| if node |p| holds a remainder after | |
> splitting@> | |
> else begin while link(s)<>null do s:=link(s); | |
> last_ins_ptr(r):=s; | |
> end; | |
> end; | |
16184c19754 | |
< from the current page, or delete |node(p)|@>; | |
--- | |
> from the current page, or delete |node(p)|@>; | |
16189,16201c19759,19772 | |
< if (broken_ins(r)=p)∧(broken_ptr(r)≠null) then | |
< begin while link(s)≠broken_ptr(r) do s←link(s); | |
< ins_ptr(p)←prune_page_top(broken_ptr(r)); | |
< if ins_ptr(p)≠null then | |
< begin temp_ptr←vpack(ins_ptr(p),natural); | |
< width(p)←height(temp_ptr)+depth(temp_ptr); | |
< free_node(temp_ptr,box_node_size); | |
< end; | |
< link(s)←null; wait←(ins_ptr(p)≠null); | |
< end; | |
< best_ins_ptr(r)←null; | |
< n←qo(subtype(r)); | |
< temp_ptr←list_ptr(box(n)); | |
--- | |
> if (broken_ins(r)=p)and(broken_ptr(r)<>null) then | |
> begin while link(s)<>broken_ptr(r) do s:=link(s); | |
> link(s):=null; | |
> split_top_skip:=split_top_ptr(p); | |
> ins_ptr(p):=prune_page_top(broken_ptr(r)); | |
> if ins_ptr(p)<>null then | |
> begin temp_ptr:=vpack(ins_ptr(p),natural); | |
> height(p):=height(temp_ptr)+depth(temp_ptr); | |
> free_node(temp_ptr,box_node_size); wait:=true; | |
> end; | |
> end; | |
> best_ins_ptr(r):=null; | |
> n:=qo(subtype(r)); | |
> temp_ptr:=list_ptr(box(n)); | |
16203c19774 | |
< box(n)←vpack(temp_ptr,natural); | |
--- | |
> box(n):=vpack(temp_ptr,natural); | |
16207c19778 | |
< link(prev_p)←link(p); link(p)←null; | |
--- | |
> link(prev_p):=link(p); link(p):=null; | |
16209,16212c19780,19785 | |
< begin link(q)←p; q←p; | |
< end | |
< else free_node(p,ins_node_size); | |
< p←prev_p | |
--- | |
> begin link(q):=p; q:=p; incr(insert_penalties); | |
> end | |
> else begin delete_glue_ref(split_top_ptr(p)); | |
> free_node(p,ins_node_size); | |
> end; | |
> p:=prev_p | |
16218,16226c19791,19808 | |
< @<Perform the default output routine and |goto done|@>= | |
< begin if link(page_head)≠null then | |
< begin if link(contrib_head)=null then | |
< if nest_ptr=0 then tail←page_tail@+else contrib_tail←page_tail | |
< else link(page_tail)←link(contrib_head); | |
< link(contrib_head)←link(page_head); | |
< link(page_head)←null; page_tail←page_head; | |
< end; | |
< ship_out(box(255)); box(255)←null; goto done; | |
--- | |
> @<Perform the default output routine@>= | |
> begin if link(page_head)<>null then | |
> begin if link(contrib_head)=null then | |
> if nest_ptr=0 then tail:=page_tail@+else contrib_tail:=page_tail | |
> else link(page_tail):=link(contrib_head); | |
> link(contrib_head):=link(page_head); | |
> link(page_head):=null; page_tail:=page_head; | |
> end; | |
> ship_out(box(255)); box(255):=null; | |
> end | |
> | |
> @ @<Explain that too many dead cycles have occurred in a row@>= | |
> begin print_err("Output loop---"); print_int(dead_cycles); | |
> @.Output loop...@> | |
> print(" consecutive dead cycles"); | |
> help3("I've concluded that your \output is awry; it never does a")@/ | |
> ("\shipout, so I'm shipping \box255 out myself. Next time")@/ | |
> ("increase \maxdeadcycles if you want me to be more patient!"); error; | |
16230,16231c19812,19814 | |
< begin output_active←true; | |
< push_nest; mode←-vmode; prev_depth←ignore_depth; mode_line←-line; | |
--- | |
> begin output_active:=true; | |
> incr(dead_cycles); | |
> push_nest; mode:=-vmode; prev_depth:=ignore_depth; mode_line:=-line; | |
16233c19816 | |
< new_save_level(output_group); | |
--- | |
> new_save_level(output_group); normal_paragraph; | |
16242c19825,19829 | |
< begin end_graf; unsave; output_active←false; | |
--- | |
> begin if (loc<>null) or | |
> ((token_type<>output_text)and(token_type<>backed_up)) then | |
> @<Recover from an unbalanced output routine@>; | |
> end_token_list; {conserve stack space in case more outputs are triggered} | |
> end_graf; unsave; output_active:=false; insert_penalties:=0;@/ | |
16244,16253c19831,19840 | |
< if tail≠head then {current list goes after heldover insertions} | |
< begin link(page_tail)←link(head); | |
< page_tail←tail; | |
< end; | |
< if link(page_head)≠null then {and both go before heldover contributions} | |
< begin if link(contrib_head)=null then contrib_tail←page_tail; | |
< link(page_tail)←link(contrib_head); | |
< link(contrib_head)←link(page_head); | |
< link(page_head)←null; page_tail←page_head; | |
< end; | |
--- | |
> if tail<>head then {current list goes after heldover insertions} | |
> begin link(page_tail):=link(head); | |
> page_tail:=tail; | |
> end; | |
> if link(page_head)<>null then {and both go before heldover contributions} | |
> begin if link(contrib_head)=null then contrib_tail:=page_tail; | |
> link(page_tail):=link(contrib_head); | |
> link(contrib_head):=link(page_head); | |
> link(page_head):=null; page_tail:=page_head; | |
> end; | |
16256a19844,19852 | |
> @ @<Recover from an unbalanced output routine@>= | |
> begin print_err("Unbalanced output routine"); | |
> @.Unbalanced output routine@> | |
> help2("Your sneaky output routine has problematic {'s and/or }'s.")@/ | |
> ("I can't handle that very well; good luck."); error; | |
> repeat get_token; | |
> until loc=null; | |
> end {loops forever if reading from a file, since |null=min_halfword<=0|} | |
> | |
16258,16267c19854,19864 | |
< if box(255)≠null then | |
< begin help3("Your \output commands should empty \box255,")@/ | |
< ("e.g., by saying `\shipout\box255'.")@/ | |
< ("Proceed; I'll discard its present contents."); | |
< print_nl("! \output routine didn't use all of \box255"); error; | |
< @:output_}{\.{\\output routine didn't use...}@> | |
< flush_node_list(box(255)); box(255)←null; | |
< end | |
< @* \[45] The chief executive. | |
< \hskip-1.1pt % avoid overfull box in published version! | |
--- | |
> if box(255)<>null then | |
> begin print_err("Output routine didn't use all of "); | |
> print_esc("box"); print_int(255); | |
> @.Output routine didn't use...@> | |
> help3("Your \output commands should empty \box255,")@/ | |
> ("e.g., by saying `\shipout\box255'.")@/ | |
> ("Proceed; I'll discard its present contents."); | |
> box_error(255); | |
> end | |
> | |
> @* \[46] The chief executive. | |
16272c19869 | |
< In a sense, this is the grand climax of the program: It applies all of the | |
--- | |
> In a sense, this is the grand climax of the program: It applies all the | |
16283,16284c19880,19881 | |
< using |get_nc_token|. Then the program branches at high speed into one of | |
< about 100 possible directions, based on the the value of the current | |
--- | |
> using |get_x_token|. Then the program branches at high speed into one of | |
> about 100 possible directions, based on the value of the current | |
16307c19904 | |
< with special care. | |
--- | |
> with particular care. | |
16314,16318c19911,19917 | |
< @d main_loop=70 {go here to typeset |cur_chr| in the current font} | |
< @d main_loop_1=71 {like |main_loop|, but |(f,c)| = current font and char} | |
< @d main_loop_2=72 {like |main_loop_1|, but |c| is known to be in range} | |
< @d main_loop_3=73 {like |main_loop_2|, but several variables are set up} | |
< @d append_normal_space=74 {go here to append a normal space between words} | |
--- | |
> @d main_loop=70 {go here to typeset a string of consecutive characters} | |
> @d main_loop_wrapup=80 {go here to finish a character or ligature} | |
> @d main_loop_move=90 {go here to advance the ligature cursor} | |
> @d main_loop_move_lig=95 {same, when advancing past a generated ligature} | |
> @d main_loop_lookahead=100 {go here to bring in another character, if any} | |
> @d main_lig_loop=110 {go here to check for ligatures or kerning} | |
> @d append_normal_space=120 {go here to append a normal space between words} | |
16323,16327c19922,19929 | |
< label big_switch,reswitch,main_loop,main_loop_1,main_loop_2,main_loop_3, | |
< append_normal_space,exit; | |
< var t:integer; {general-purpose temporary variable} | |
< @<Local variables for the inner loop of |main_control|@>@; | |
< begin big_switch: get_nc_token;@/ | |
--- | |
> label big_switch,reswitch,main_loop,main_loop_wrapup, | |
> main_loop_move,main_loop_move+1,main_loop_move+2,main_loop_move_lig, | |
> main_loop_lookahead,main_loop_lookahead+1, | |
> main_lig_loop,main_lig_loop+1,main_lig_loop+2, | |
> append_normal_space,exit; | |
> var@!t:integer; {general-purpose temporary variable} | |
> begin if every_job<>null then begin_token_list(every_job,every_job_text); | |
> big_switch: get_x_token;@/ | |
16330,16332c19932,19938 | |
< hmode+letter,hmode+other_char: goto main_loop; | |
< hmode+char_num: begin scan_char_num; cur_chr←cur_val; goto main_loop; | |
< end; | |
--- | |
> hmode+letter,hmode+other_char,hmode+char_given: goto main_loop; | |
> hmode+char_num: begin scan_char_num; cur_chr:=cur_val; goto main_loop;@+end; | |
> hmode+no_boundary: begin get_x_token; | |
> if (cur_cmd=letter)or(cur_cmd=other_char)or(cur_cmd=char_given)or | |
> (cur_cmd=char_num) then cancel_boundary:=true; | |
> goto reswitch; | |
> end; | |
16334c19940 | |
< else app_space; | |
--- | |
> else app_space; | |
16339,16341c19945,19947 | |
< main_loop:@<Append character |cur_chr| and the following characters (if@@any) | |
< to the current hlist in the current font; |goto reswitch| when | |
< a non-character has been fetched@>; | |
--- | |
> main_loop:@<Append character |cur_chr| and the following characters (if~any) | |
> to the current hlist in the current font; |goto reswitch| when | |
> a non-character has been fetched@>; | |
16343c19949 | |
< then |goto big_switch|@>; | |
--- | |
> then |goto big_switch|@>; | |
16351,16399c19957,19979 | |
< if interrupt>0 then if OK_to_interrupt then | |
< begin back_input; pause_for_instructions; goto big_switch; | |
< end; | |
< debug if panicking then check_mem(false);@+@;@+gubed | |
< if tracing_commands≠0 then | |
< begin begin_diagnostic; print_nl("{"); | |
< if mode≠shown_mode then | |
< begin print_mode(mode); print(": "); shown_mode←mode; | |
< end; | |
< print_cmd_chr(cur_cmd,cur_chr); print_char("}"); | |
< end_diagnostic; | |
< end | |
< | |
< @ In the following program, |l| is the current character or ligature; | |
< it might grow into a longer ligature. One or more characters has been | |
< used to define |l|, and the last of these was |c|. The chief use of |c| | |
< will be to modify |space_factor| and to insert discretionary nodes after | |
< explicit hyphens in the text. | |
< | |
< @<Local variables for the inner loop of |main_control|@>= | |
< @!l:quarterword; {the current character or ligature} | |
< @!c:eight_bits; {the most recent character} | |
< @!f:internal_font_number; {the current font} | |
< @!r:halfword; {the next character for ligature/kern matching} | |
< @!p:pointer; {the current |char_node|} | |
< @!k:0..font_mem_size; {index into |font_info|} | |
< @!q:pointer; {where a ligature should be detached} | |
< @!i:four_quarters; {character information bytes for |l|} | |
< @!j:four_quarters; {ligature/kern command} | |
< @!s:integer; {space factor code} | |
< @!ligature_present:boolean; {should a ligature node be made?} | |
< | |
< @ @<Append character |cur_chr| and the following characters...@>= | |
< @^inner loop@> | |
< f←cur_font; | |
< if f=undefined_font then | |
< begin missing_font; goto big_switch; | |
< end; | |
< c←cur_chr; | |
< main_loop_1: if (c<font_bc[f])∨(c>font_ec[f]) then | |
< b |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment