forked from JohnWall2016/the-texbook-cn
-
Notifications
You must be signed in to change notification settings - Fork 0
/
chapter23.tex
executable file
·1536 lines (1464 loc) · 83.8 KB
/
chapter23.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
% -*- coding: utf-8 -*-
\input macros
%\beginchapter Chapter 23. Output Routines
\beginchapter Chapter 23. 输出例行程序
\origpageno=251
%We investigated \TeX's page-building technique in Chapter 15, where we
%discussed the basic two-stage strategy that is used: \TeX\ gathers
%material until it has accumulated more than will fit on a page; then it
%spews out one page of data, based on what it thinks is the best breakpoint
%between pages; then it returns to gather material for the next page in
%the same way. Page numbers, headings, and similar things are attached
%after each page has been ejected, by a special sequence of \TeX\ commands
%called the current {\sl^{output routine}}.
\1在第十五章,我们讨论了 \TeX\ 组建页面的方法,它分为两个基本阶段:
\TeX\ 收集超过一个页面的内容;
接着按照页面之间的最佳断点分出一个页面;
再接下来用同样的方法收集下一个页面的内容。%
页码,页眉等类似的内容在分页后由一个 \TeX\ 的一系列特殊命令添加上去,
这就是所谓的当前{\KT{10}输出例行程序}。
%Plain \TeX\ has an output routine that takes care of ordinary jobs. It
%handles the simple things that most manuscripts require, and it also
%copes with more complicated things like the insertions made with
%^|\footnote| and ^|\topinsert|, as described in the dangerous bends of
%Chapter~15. We shall begin the present chapter by discussing how to make
%simple changes to the behavior of plain \TeX's output routine; then we
%shall turn to the details of how to define output routines that do more
%complex tasks.
Plain \TeX\ 有一个输出例行程序,由它完成普通的任务。%
它处理大多数文稿所要求的简单任务,以及象 |\footnote| 和 |\topinsert|~%
所做的插入对象这些更复杂的任务,
就象第十五章中``危险''段落中讨论的那样。%
在本章我们将首先讨论怎样直接改变 plain \TeX\ 输出例行程序的设置;
接着将转到怎样定义输出例行程序的详细内容,以处理更复杂的任务。
%If you run \TeX\ without modifying the ^{plain \TeX\ format}, you get
%^^{page format, modifying}
%pages that are numbered at the bottom; and each page will be approximately
%8$1\over2$~inches wide and 11~inches tall, including 1-inch margins at
%all four sides. This format is suitable for preprints of
%technical papers, but you might well want to change it, especially if
%you are not using \TeX\ to make a preprint of a technical paper.
如果你不加修改地运行 plain \TeX\ 的格式,得到的页码就在底部;
并且每个页面的宽为 8$1\over2$ 英寸,高为 11 英寸,在四个边缘是 1 英寸的页边。%
这种格式对专业论文的预印比较合适,但是你可能希望改变它,
特别是在你要得到的不是专业论文的预印格式时。
%For example, we saw in the experiments of Chapter 6 that the width of the
%material on a page can be changed by giving a different value to the
%horizontal line size, ^|\hsize|. Plain \TeX\ format says `|\hsize=6.5in|',
%in order to obtain 8.5-inch pages with 1-inch margins; you can change
%|\hsize| to whatever you want. Similarly, you can control the vertical
%size of a page by changing ^|\vsize|. Plain \TeX\ sets |\vsize=8.9in|
%(not |9in|, since |\vsize| doesn't include the space for page numbers at the
%bottom of each page); if you say `|\vsize=4in|' you will get shorter pages,
%with only 4 inches of copy per sheet. It's best not to monkey with
%|\hsize| and |\vsize| except at the very beginning of a job, or after you
%have ejected all pages from \TeX's memory.
例如,在第六章的实战中我们已经看到,页面中内容的宽度由水平行尺寸 |\hsize| 的%
不同值来确定。%
在 plain \TeX\ 的格式中,由设置`|\hsize=6.5in|'得到的 8.5 英寸%
页面中,页边为 1 英寸;
你可以按自己的要求改变 |\hsize|。%
同样,要改变页面的垂直尺寸就要改变 |\vsize|。%
Plain \TeX\ 设置 |\vsize=8.9in|(不是 |9in|, 因为 |\vsize| 没有把每个页面底部%
页码的空间包括进去);
如果给出`|\vsize=4in|', 就得到更短的页码,每页只用了 4 英寸。%
除了在任务最开头或者已经把所有页面从 \TeX\ 的内存中去掉后以外,
最好别乱改动 |\hsize| 和 |\vsize|。
%If you want your output to be positioned differently when it is ultimately
%printed, you can offset it by giving nonzero values to ^|\hoffset| and
%^|\voffset|. For example,
%\begintt
%\hoffset=.5in \voffset=1.5in
%\endtt
%will move the output half an inch to the right of its normal position, and
%1.5 inches down. You should be careful not to offset the output so much
%that it falls off the edge of the physical medium on which it is being
%printed, unless you know that such out-of-bounds activity won't cause trouble.
如果要改变你的输出结果最后打印的位置,可以把它偏移,即给 |\hoffset|~%
和 |\voffset| 一个非零值。%
例如,
\begintt
\hoffset=.5in \voffset=1.5in
\endtt
就把输出从正常位置向右平移半英寸,向下平移 1.5 英寸。%
注意别偏移得超出所用打印的物理介质的边缘,
除非你知道这样超出边界不会出现问题。
%\TeX\ is often used to typeset announcements, ^{brochures}, or other
%documents for which ^{page numbers} are inappropriate. If you say
%\begintt
%\nopagenumbers
%\endtt
%at the beginning of your manuscript, plain \TeX\ will refrain from inserting
%numbers at the bottom of each page.
\TeX\ 常常用于排版公告,小册子或者其它没有页码的文档。%
如果在文稿开头声明了
\begintt
\nopagenumbers
\endtt
那么 plain \TeX\ 就不在每个页码的底部插入数字了。
%\danger In fact, ^|\nopagenumbers| is a special case of a much more general
%mechanism by which you can control headings and footings. The plain \TeX\
%output routine puts out a special line of text called the {\sl^{headline}\/}
%at the top of each page, and another special line of text called the
%{\sl^{footline}\/} at the bottom. The headline is normally blank, and
%the footline is normally a centered page number, but you can specify any
%headline and footline that you want by redefining the control sequences
%^|\headline| and ^|\footline|. For example, ^^|\hrulefill|
%\begintt
%\headline={\hrulefill}
%\endtt
%will put a horizontal rule at the top of every page. The basic idea is
%that plain \TeX\ puts `|\line{\the\headline}|' at the top and
%`|\line{\the\footline}|' at the bottom, with blank lines separating these
%extra lines from the other material. \ (Recall that ^|\line| is an
%abbreviation for `|\hbox to\hsize|'; hence the headline and footline are
%put into boxes as wide as the normal lines on the page itself.) \ The
%normal value of\/ |\headline| is `|\hfil|', so that no heading is visible.
%The |\nopagenumbers| macro described earlier is simply an abbreviation for
%`|\footline={\hfil}|'.
\danger \1实际上,~|\nopagenumbers| 是控制页眉和页脚的更广泛的方法的一个特殊情形。%
Plain \TeX\ 的输出例行程序把一个叫{\KT{9}页眉}~{\sl^{headline}\/} 的特殊的行放在每个页面的顶部,
把另一个叫{\KT{9}页脚}~{\sl^{footline}\/} 的特殊行放在底部。%
此页眉一般是空的,而页脚一般是居中的页码,
但是通过重新定义控制系列 |\headline| 和 |\footline|, 可以得到你所要的页眉和页脚。%
例如,
\begintt
\headline={\hrulefill}
\endtt
将把水平线放在每个页眉的顶部。%
基本思路是,~plain \TeX\ 把`|\line{\the\headline}|'放在顶部,
把\allowbreak`|\line{\the\footline}|'放在底部,在这些额外行和其它内容之间是一个空行。%
(记住,|\line| 的定义是`|\hbox to\hsize|';
因此,页眉和页脚被放在宽度为正常页面行宽的盒子中。)
|\headline| 的正常值是`|\hfil|', 这样就没有可见的页眉。%
前面给出的宏 |\nopagenumbers| 的定义就是`|\footline={\hfil}|'。
%\danger The normal value of\/ |\footline| is `|\hss\tenrm\folio\hss|';
%this centers the page number on a line, using font ^|\tenrm|, because
%^|\folio| is a control sequence that produces the number of the current
%page in text form.
\danger |\footline| 的正常值是 `|\hss\tenrm\folio\hss|';
它用 |\tenrm| 字体在一行中显示居中的页码,
因为 |\folio| 是生成当前页码的文本形式的控制系列。
%\danger The page number appears in \TeX's internal register |\count0|,
%as explained in Chapter~15, and plain \TeX\ makes ^|\pageno| an
%abbreviation for ^|\count0|. Thus you can say `|\pageno=100|' if you want
%the next page of your output to be number~100. The |\folio| macro
%converts negative page numbers to ^{roman numerals}; if your manuscript
%begins with `|\pageno=-1|', the pages will be numbered i, ii, iii, iv,
%v,~etc. In fact, Appendix~B defines |\folio| to be an abbreviation for
%^^|\romannumeral|^^|\number|
%\begintt
%\ifnum\pageno<0 \romannumeral-\pageno \else\number\pageno \fi
%\endtt
\danger 就象第十五章中讨论的那样,页码在 \TeX\ 的内部寄存器 |\count0| 中,
并且 plain \TeX\ 把 |\pageno| 定义为 |\count0|。%
因此,如果要让输出的下一页的页码为 100, 就要给出 `|\pageno=100|'。%
宏 |\folio| 把负的页码变成 Roman 数字;
如果你的文稿以`|\pageno=-1|'开始,那么页码就是 i, ii, iii, iv, v 等等。%
实际上,附录 B 把 |\folio| 定义为
\begintt
\ifnum\pageno<0 \romannumeral-\pageno \else\number\pageno \fi
\endtt
%\danger It is important to include the name of each font explicitly
%whenever you are defining a headline or footline, because an output routine
%in \TeX\ can come into action at somewhat unpredictable times. For example,
%suppose that |\footline| had been set to `|\hss\folio\hss|', without
%specifying |\tenrm|; then the page number would be typeset in whatever
%font happens to be current when \TeX\ decides to output a page.
%Mysterious effects can occur in such cases, because \TeX\ is typically
%in the midst of page~101 when it is outputting page~100.
\danger 重要的是把所定义页码和页脚的每个字体名称明确包括进来,
因为 \TeX\ 中的输出例行程序在某些预料不到的时候要用到。%
例如,假定 |\footline| 已经设定为`|\hss\folio\hss|', 而没有使用 |\tenrm|;
这样,当 \TeX\ 要输出页码时,页码就用任何当前字体进行排版。%
在这样的情况下,就会出现预想不到的结果,
因为当输出页面 100 时 \TeX\ 最可能在页面 101 的中间。
%\dangerexercise Explain how to put ^{en-dashes} around the page numbers in a
%plain \TeX\ job. For example, `\hbox{ -- 4 -- }' should appear at the bottom
%of page~4.
%\answer |\footline={\hss\tenrm-- \folio\ --\hss}|
\dangerexercise 看看怎样把连接号放在页码两边。
例如,`\hbox{ -- 4 -- }' 出现在第 4 页的底部。
\answer |\footline={\hss\tenrm-- \folio\ --\hss}|
%\danger Here is an example of a headline in which the page numbers
%appear at the top. Furthermore, odd-numbered and even-numbered pages are
%treated differently:
%\begintt
%\nopagenumbers % suppress footlines
%\headline={\ifodd\pageno\rightheadline \else\leftheadline\fi}
%\def\rightheadline{\tenrm\hfil RIGHT RUNNING HEAD\hfil\folio}
%\def\leftheadline{\tenrm\folio\hfil LEFT RUNNING HEAD\hfil}
%\voffset=2\baselineskip
%\endtt
%English-language books traditionally have ^{odd-numbered pages} on the
%right and ^{even-numbered pages} on the left. Text that appears as a
%headline on several pages is often called a ``^{running head}.'' When
%you use headlines, it is generally wise to set ^|\voffset| to the
%equivalent of two lines of text, as shown in this example, so that there
%will still be a margin of one inch at the top of your output pages.
\danger 下面是页眉的一个例子,其中页码放在顶部。%
还有,奇数和偶数页面要做不同的对待:
\begintt
\nopagenumbers % suppress footlines
\headline={\ifodd\pageno\rightheadline \else\leftheadline\fi}
\def\rightheadline{\tenrm\hfil RIGHT RUNNING HEAD\hfil\folio}
\def\leftheadline{\tenrm\folio\hfil LEFT RUNNING HEAD\hfil}
\voffset=2\baselineskip
\endtt
\1习惯上,英文书籍的奇数页面在右边,偶数页面在左边。%
作为某些页上的页眉的文本常常称为``可变页眉''。%
当使用页眉时,象本例这样用 |\voffset| 向下偏移两行文字的空间一般是比较明智的,
这样在所得到页面的顶部仍然是一英寸的页边。
%\dangerexercise Suppose that you're using \TeX\ to typeset your ^{r\'esum\'e},
%which is several pages long. Explain how to define |\headline| so that
%the first page is headed by `{\bf R\'ESUM\'E}', centered in boldface type,
%while each subsequent page has a headline like this: ^^{Thor}
%$$\line{R\'esum\'e of A. U. Thor \dotfill\ Page 2}$$
%\answer |\headline={\ifnum\pageno=1 \hss\tenbf R\'ESUM\'E\hss|\parbreak
% | \else\tenrm R\'esum\'e of A. U. Thor \dotfill\ Page \folio\fi}|
%\smallskip\noindent (You should also say |\nopagenumbers| and
%|\voffset=2\baselineskip|.)
\dangerexercise 假定要用 \TeX\ 排版个人简历(r\'esum\'e),它包含几个页面。
看看怎样定义 |\headline| 才能使第一页的页眉为居中的黑体 `{\bf R\'ESUM\'E}',
而其它页眉是这样:
$$\line{R\'esum\'e of A. U. Thor \dotfill\ Page 2}$$
\answer |\headline={\ifnum\pageno=1 \hss\tenbf R\'ESUM\'E\hss|\parbreak
| \else\tenrm R\'esum\'e of A. U. Thor \dotfill\ Page \folio\fi}|
\smallskip\noindent (你应当另外写上 |\nopagenumbers| 和
|\voffset=2\baselineskip|。)
%\danger If you don't change the |\vsize|, all of the headlines and footlines
%will occur in the same place regardless of the contents of the page
%between them. Thus, for example, if you are using ^|\raggedbottom| as
%explained in Chapter~15, so that pages do not always contain the same
%amount of text, the raggedness will occur above the footline; the
%footline won't move up. If you do change ^|\vsize|, the footline position
%will change correspondingly, while the headline will stay put.
\danger 如果不修改 |\vsize|, 那么所有的页眉和页脚都出现在同样的位置,
而不管它们中间页面的内容如何。%
因此,例如,如果象第十五章中讨论的那样使用了 |\raggedbottom|,
从而导致每个页面所包含的内容长度不尽相同,那么页脚上面就变得参差不齐;
页脚也不会向上移动。%
如果改变了 |\vsize|, 那么页脚的位置就会相应地改变,而页面不变。
%\ddanger The rest of this chapter is intended for people who want an
%output format that is substantially different from what plain \TeX\ provides.
%Double dangerous bends are used in all of the subsequent paragraphs, because
%you should be familiar with the rest of \TeX\ before you plunge into these
%final mysteries of the language. Chapter~22 taught you how to be a \TeX\
%Master, i.e., a person who can produce complicated tables using |\halign|
%and |\valign|; the following material will take you all the way to the
%rank of ^{Grandmaster}, i.e., a person who can design output routines.
%When you are ready for this rank, you will be pleased to discover
%that---like alignments---output routines are not really so mysterious as
%they may seem at first.
\ddanger 本章剩下的内容把对象限制在要得到与 plain \TeX\ 所给出的输出例行程序不同的格式的人。
随后的所有段落都有双``危险''标记,因为在攻入本语言最后的堡垒时要精通 \TeX\ 的其它内容。
第二十二章教出了 \TeX\ 大师,即,能用 |\halign| 和 |\valign| 排版出复杂表格的人;
接下来的内容将使你一鼓作气地达到统帅的等级,即,可以设计输出例行程序的人。
当你学会后,就会欣喜地发现,就象对齐阵列一样,输出例行程序不象刚开始看起来那样神秘。
%\ninepoint % it's all \ddangerous from here on
%\ddanger Let's begin by recapping some of the rules at the end of Chapter~15.
%\TeX\ periodically chooses to output a page of information, by breaking
%its main vertical list at what it thinks is the best place, and at such times
%it enters internal vertical mode and begins to read the commands in the
%current |\output| routine. When the output routine begins, ^|\box255|
%contains the page that \TeX\ has completed; the output routine is supposed to
%do something with this vbox. When the output routine ends, the list of
%items that it has constructed in internal vertical mode is placed just
%before the material that follows the page break. In this way \TeX's
%page-break decisions can effectively be changed: Some or all of the material
%on the broken-off page can be removed and carried forward to the next page.
\ninepoint % it's all \ddangerous from here on
\ddanger 我们首先来回顾一下第十五章结尾的一些规则。%
\TeX\ 周期性地输出一个页面的内容,这是通过把主垂直列在所选定的最佳处裂分而得到的,
并且在这时它进入内部垂直模式并且开始读入当前 |\output| 例行程序的命令。%
当输出例行程序开始时,|\box255| 中包含 \TeX\ 已经完成的页面;
输出例行程序可以看作对此 vbox 进行一些处理。%
当输出例行程序结束时,在内部垂直模式下构建的项目列就放在分页后面的内容的紧前面。%
用这种方法, \TeX\ 的分页结果会被明显修改:
已完成分页的页面的某些或全部内容会被去掉并且送到下一页。
%\ddanger The current ^|\output| routine is defined as a token list
%parameter, just like ^|\everypar| or ^|\errhelp|, except that \TeX\
%automatically inserts a begin-group symbol~`|{|' at the beginning
%and an end-group symbol~`|}|' at the end. These ^{grouping characters}
%help to keep the output routine from interfering with what
%\TeX\ was doing when the page break was chosen; for example, an output
%routine often changes the ^|\baselineskip| when it puts a headline
%or footline on a page, and the extra ^{braces} keep this change local.
%If no |\output| routine has been specified, or if the user has said
%`|\output={}|', \TeX\ supplies its own routine, which is essentially
%equivalent to `|\output={\shipout\box255}|'; this outputs the page without
%any headline or footline, and without changing the page number.
%^^{default output routine}^^|\shipout|
\ddanger 当前 |\output| 例行程序被定义为一个记号列参数,就像 |\everypar|
或者 |\errhelp| 一样,只是 \TeX\ 自动在开头插入组开始符号,
在结尾插入组结束符号而已。这些编组符号有利于输出例行程序不受分页时 \TeX\
的状态的干扰;例如,当输出例行程序在页面上放置页眉和页脚时,
常常修改 |\baselineskip|,这样额外的花括号就使得这个修改被限制在局部中。
如果没有给出 |\output| 例行程序,或者用户声明了 `|\output={}|',那么 \TeX\
就使用自己的例行程序,它实际上等价于 `|\output={\shipout\box255}|';
它输出的页面没有页眉和页脚,也没有页码。
%\ddanger \TeX's primitive command |\shipout|\<box> is what actually
%causes output. It sends the contents of the box to the |dvi| file,
%which is \TeX's main output file; after \TeX\ has finished,
%the ^|dvi| file will contain a compact device-independent encoding of
%instructions that specify exactly what should be printed. When a
%box is shipped out, \TeX\ displays the values of\/ |\count0| through
%|\count9| on your terminal, ^^|\count0| as explained in Chapter~15; these
%ten counters are also recorded in the |dvi| file, where they can be used
%to identify the page. All of the ^|\openout|, ^|\closeout|, and ^|\write|
%commands that appear inside of the \<box> are performed in their natural
%order as that box is being shipped out. Since a |\write| command
%expands macros, as explained in Chapter~21, \TeX's scanning mechanism
%might detect syntax errors while a |\shipout| is in progress. If
%^|\tracingoutput| is nonzero at the time of a |\shipout|, the contents
%of the \<box> being shipped are written into your log file in symbolic
%form. You can say |\shipout| anywhere, not only in an output routine.
\ddanger \1实际上是 \TeX\ 的原始命令 |\shipout|\<box> 产生的输出。%
它把盒子的内容送到 \TeX\ 的主要输出文件——|dvi| 文件;
在 \TeX\ 运行结束后,|dvi| 文件就包含了一个紧凑的与设备无关的指令编码,
它准确地给出了要输出的信息。%
当盒子被送出时, \TeX\ 把 |\count0| 到 |\count9| 的值都显示在你的终端上,
就象第十五章中讨论的那样;
这十个计数器都保存在 |dvi| 文件中,它们就确定了此页面。%
当盒子被送出时,在 \<box> 中出现的所有 |\openout|, |\closeout| 和 |\write| 命令都按照%
它们的正常顺序被执行。%
因为命令 |\write| 展开一个宏,就象第二十一章讨论的那样,所以当 |\shipout| 正在%
进行时 \TeX\ 的扫描程序可能会发现语法错误。%
如果在 |\shipout| 时 |\tracingoutput| 不为零,那么要被送出的 \<box> 的内容%
将用符号的形式写入你的 log 文件。%
可以在任何地方使用 |\shipout|, 而不仅仅是输出例行程序中。
%\ddanger The delayed aspect of\/ |\write| imposes a noteworthy restriction:
%It is necessary to be sure that all macros that might appear within the
%text of a |\write| are properly defined when a |\shipout| command is
%given. For example, the plain \TeX\ format in Appendix~B temporarily makes
%spaces active and says `|\global\let|\]|=|^|\space|'; the reason is that
%^|\obeyspaces| might be in force during a |\write| command, so a definition
%for \] as an active character should exist during the next |\shipout|,
%even though \TeX\ might no longer be making ^{spaces active} at that time.
\ddanger |\write| 延迟性强加了一个值得注意的限制:
当命令 |\shipout| 给定时,必须确保出现在 |\write| 文本中的所有宏要有正确的定义。%
例如,附录 B 中的 plain \TeX\ 格式暂时把空格变成活动符,
并且声明`|\global\let|\]|=|^|\space|';
这是因为 |\obeyspaces| 可能在 |\write| 命令中起作用,
因此把 \] 定义为活动符应该持续到下一个 |\shipout|,
即使此时 \TeX\ 可能不再用空格作活动符。
%\ddanger Chapter 15 points out that \TeX\ gives special values to
%certain internal registers and parameters, in addition to |\box255|,
%just before the output routine begins. Insertions are put into their
%own vboxes, and ^|\insertpenalties| is set equal to the total number of
%heldover insertions; furthermore the ^|\outputpenalty| parameter is
%set to the value of the penalty at the current breakpoint. An output
%routine can be made to do special things when these quantities have
%special values. For example, the output routine of plain \TeX\ recognizes
%a ^|\supereject| (which ejects all held-over insertions) by the fact that
%|\supereject| causes |\outputpenalty| to be $-20000$, and by using
%|\insertpenalties| to decide if any insertions are being held over.
\ddanger 第十五章提到,在输出例行程序开始之前, \TeX\ 把特殊值赋予给了%
包括 |\box255| 在内的某些内部寄存器和参数。%
插入对象被放在它自己的 vbox 中,并且 |\insertpenalties| 被设为与延迟的插入对象%
的总数相等;还有,参数 |\outputpenalty| 被设为当前断点的惩罚的值。%
当这些量赋予特殊值后,输出例行程序就可以用来做很多特殊的工作。%
例如,~plain \TeX\ 的输出例行程序用到一个命令 |\supereject|(它把所有延迟的%
插入对象都驱出), 原因是 |\supereject| 把 |\outputpenalty| 变成 $-20000$,
并且用 |\insertpenalties| 来确定是否所有的插入对象都被延迟了。
%\ddanger The default output routine, `|\shipout\box255|', illustrates one
%extreme in which nothing is put into the vertical list that is carried over
%to the next page. The other extreme is
%\begintt
%\output={\unvbox255
% \ifnum\outputpenalty<10000 \penalty\outputpenalty\fi}
%\endtt
%which ships nothing out and puts {\sl everything\/} back onto the main
%vertical list. \ (The command `^|\unvbox||255|' takes the completed page
%out of its box, and the command `|\penalty\outputpenalty|' reinserts the
%penalty at the chosen breakpoint.) \ This makes a seamless join between
%the completed page and the subsequent material, because \TeX\ has still
%not discarded glue and penalties at the breakpoint when it invokes
%an |\output| routine; hence \TeX\ will go back and reconsider the page
%break. If the |\vsize| hasn't changed, and if all insertions have been
%held in place, the same page break will be found; but it will be found
%much faster than before, because the vertical list has already been
%constructed---the paragraphing doesn't need to be done again. Of course,
%an output routine like this makes \TeX\ spin its wheels endlessly, so
%it~is of no use except as an example of an extreme case.
\ddanger 默认的输出例行程序`|\shipout\box255|'给出的是一个极端的情况,
它不把任何内容放在下一个页面的垂直列中。%
另一个极端是
\begintt
\output={\unvbox255 \penalty\outputpenalty}
\endtt
它什么也不输出,并且把{\KT{9}所有内容}都放回主垂直列。%
(命令`|\unvbox||255|'把这个页面从盒子中取出,命令`|\penalty\outputpenalty|'%
在选定的断点处重新插入惩罚。)
这使得整个页面与其后的内容恰好合并起来,
因为当 \TeX\ 调用 |\output| 例行程序时没有丢掉任何断点处的粘连和惩罚;
这样 \TeX\ 就回来重新考虑分页。%
如果 |\vsize| 没有改变,并且所有的插入对象都还在原地,那么就得到同样的分页;
但是找到它的速度比以前要更快,因为垂直列已经构建好了——%
不需要再次分段为行了。%
当然,这样的输出例行程序使得 \TeX\ 陷入死循环,
因此它仅仅是个极端的例子,而没有什么用处。
%\ddanger To prevent such looping, your output routine should always
%make progress of some sort whenever it comes into play. If you make a mistake,
%\TeX\ may be able to help you diagnose the error, because a special
%loop-detection mechanism has been built in:
%There is an internal integer variable called ^|\deadcycles|,
%which is cleared to zero after every |\shipout| and increased by~1
%just before every |\output|. Thus, |\deadcycles| keeps track of how
%many times an output routine has been initiated since the most recent
%|\shipout|, unless you change the value of\/ |\deadcycles| yourself.
%There's also an integer parameter called |\maxdeadcycles|, which plain
%\TeX\ sets to~25. If\/ |\deadcycles| is greater than or equal to
%|\maxdeadcycles| when your output routine is about to be started (i.e.,
%when |\deadcycles| is about to be increased), \TeX\ issues an error
%message and performs the ^{default output routine} instead of yours.
\ddanger \1为了防止这样的循环,在出现这种情况时要对你的输出例行程序进行一些改进。%
如果你出现了失误, \TeX\ 可能会帮你找出错误,因为内置了一个特殊的循环检测方法:
有一个叫 |\deadcycles| 的内部整数变量,在每次 |\shipout| 后都回到零,
并且在每个 |\output| 紧前面要增加 1。%
这样,|\deadcycles| 跟踪的就是最近一次 |\shipout| 后输出例行程序启动的次数,
只要你自己不改变 |\deadcycles| 的值。%
还有一个整数参数叫做 |\maxdeadcycles|, ~plain \TeX\ 把它设置为 25。%
当输出例行程序将要启动时(即当 |\deadcycles| 要增加时),
如果 |\deadcycles| 大于或等于 |\maxdeadcycles|, \TeX\ 就输出错误信息,
并且执行默认的输出例行程序,来代替你的例行程序。
%\ddanger When your output routine is finished, |\box255| should be void.
%In other words, you must do something with the information in that
%box; it should either be shipped out or put into some other place.
%Similarly, ^|\box255| should be void when \TeX\ is getting ready to
%fill it with a new page of material, just before starting an output
%routine. If\/ |\box255| is nonvoid at either of those times, \TeX\ will
%complain that you are misusing this special register, and the
%register contents will be destroyed.
\ddanger 当输出例行程序结束时,|\box255| 应该被置空。%
换句话说,你必须用一些方法来处理此盒子中的信息;
它应该被送出或者是放在某些其它地方。%
类似地,当 \TeX\ 准备放入下一页内容,在启动输出例行程序紧前面,
|\box255| 应该被置空。%
如果在某个这些时刻 |\box255| 没有被置空,那么 \TeX\ 将告诉说你误用了这个特殊寄存器,
并且此寄存器的内容将被毁掉。
%\ddanger But let's not talk forever about borderline cases and special
%parameters; let's look at some real examples. The output routine of
%plain \TeX, found in Appendix~B\null, is set up by saying
%`|\output={\plainoutput}|', where ^|\plainoutput| is an abbreviation for
%\begintt
%\shipout\vbox{\makeheadline
% \pagebody
% \makefootline}
%\advancepageno
%\ifnum\outputpenalty>-20000 \else\dosupereject\fi
%\endtt
%Let us consider this ``program'' one line at a time:\enddanger
\ddanger 然而让我们别再讨论边界情形和特殊参数了;我们来看看一些真实的例子。
在附录 B 中的 plain \TeX\ 的输出例行程序被设置为 `|\output={\plainoutput}|',
其中 |\plainoutput| 被定义为
\begintt
\shipout\vbox{\makeheadline
\pagebody
\makefootline}
\advancepageno
\ifnum\outputpenalty>-20000 \else\dosupereject\fi
\endtt
下面我们逐行讨论这个``程序'':\enddanger
%\medskip
%\textindent{1)} The ^|\makeheadline| macro constructs a vbox of height
%and depth zero in such a way that the headline is properly positioned
%above the rest of the page. Its actual code is ^^|\headline|^^|\nointerlineskip|
%\begintt
%\vbox to 0pt{\vskip-22.5pt
% \line{\vbox to8.5pt{}\the\headline}\vss}
%\nointerlineskip
%\endtt
%The magic constant $-22.5\pt$ is equal to $\bigl(\hbox{topskip}-\hbox{height of
%strut}-2(\hbox{baselineskip})\bigr)$, i.e., $10\pt-8.5\pt-24\pt$;
%^^{strut}^^|\vss| ^^|\line| this places the reference point of the headline
%exactly $24\pt$ above the reference point of the top line on the page,
%unless the headline or the top line are excessively large.
\medskip
\textindent{1)} 宏 |\makeheadline| 构建了一个高度和深度都为零的 vbox,
这样页眉就正好放在页面的空白处了。%
它的实际定义是:
\begintt
\vbox to 0pt{\vskip-22.5pt
\line{\vbox to8.5pt{}\the\headline}\vss}
\nointerlineskip
\endtt
$-22.5\pt$ 这个神秘的常数等于 $\bigl(\hbox{顶部粘连}-\hbox{支架高度}
-2(\hbox{行高})\bigr)$, 即 $10\pt-8.5\pt-24\pt$;
它把页眉的基点正好放在页面顶行基点上面正好 $24\pt$ 的地方,
只要页眉或顶行不是太宽即可。
%\medbreak
%\textindent{2)} The ^|\pagebody| macro is an abbreviation for
%\begintt
%\vbox to\vsize{\boxmaxdepth=\maxdepth \pagecontents}
%\endtt
%The value of\/ ^|\boxmaxdepth| is set to ^|\maxdepth| so that the vbox
%will be constructed under the assumptions that \TeX's page builder has
%used to set up |\box255|.
\medbreak
\textindent{2)} 宏 |\pagebody| 的定义是
\begintt
\vbox to\vsize{\boxmaxdepth=\maxdepth \pagecontents}
\endtt
|\boxmaxdepth| 的值设置为 |\maxdepth|, 这样就构建了 vbox,
其中假定 \TeX\ 的页面已经设置为 |\box255| 了。
%\medbreak
%\textindent{3)} The ^|\pagecontents| macro produces a vertical list for
%everything that belongs on the main body of the page, namely the contents
%of\/ |\box255| together with illustrations (inserted at the top)
%and footnotes (inserted at the bottom): ^^|\topins| ^^|\footnote|
%\begintt
%\ifvoid\topins \else\unvbox\topins\fi
%\dimen0=\dp255 \unvbox255
%\ifvoid\footins\else % footnote info is present
% \vskip\skip\footins
% \footnoterule
% \unvbox\footins\fi
%\ifraggedbottom \kern-\dimen0 \vfil \fi
%\endtt
%Here ^|\topins| and ^|\footins| are the insertion class numbers for
%the two kinds of insertions used in plain \TeX; if more classes of
%^{insertions} are added, |\pagecontents| should be changed accordingly.
%Notice that the boxes are unboxed so that the glue coming from
%insertions can help out the glue on the main page. The ^|\footnoterule|
%macro in Appendix~B places a dividing line between the page and its
%footnotes; it makes a net contribution of $0\pt$ to the height of
%the vertical list. ^{Ragged-bottom setting} is achieved by inserting ^^|\vfil|
%^{infinite glue}, which overpowers the stretchability of\/ ^|\topskip|.
\medbreak
\textindent{3)} \1宏 |\pagecontents| 得到了一个垂直列,它的所有内容都是页面的主体,
即 |\box255| 的内容以及图表(插入在顶部)和脚注(插入在底部):
\begintt
\ifvoid\topins \else\unvbox\topins\fi
\dimen0=\dp255 \unvbox255
\ifvoid\footins\else % footnote info is present
\vskip\skip\footins
\footnoterule
\unvbox\footins\fi
\ifraggedbottom \kern-\dimen0 \vfil \fi
\endtt
这里的 |\topins| 和 |\footins| 是 plain \TeX\ 中用到的两种插入对象的类代码;
如果要添加更多插入对象的类,|\pagecontents| 应该随之改变。%
注意,这些盒子要去掉外围盒子,这样来自插入对象的粘连才能变成主页面的粘连。%
附录 B 中的宏 |\footnoterule| 把一个分隔线放在页面和脚注之间;
它的垂直列净高度是 $0\pt$。%
设置底部不对齐要插入无限大粘连,它的级别要比 |\topskip| 的伸长能力高。
%\medbreak
%\textindent{4)} The ^|\makefootline| macro puts ^|\footline| into
%its proper position:
%\begintt
%\baselineskip=24pt
%\line{\the\footline}
%\endtt
\medbreak
\textindent{4)} 宏 |\makefootline| 把 |\footline| 放在相应的位置:
\begintt
\baselineskip=24pt
\line{\the\footline}
\endtt
%\medbreak
%\textindent{5)} The ^|\advancepageno| macro normally advances ^|\pageno|
%by~$+1$; but if\/ |\pageno| is negative (for roman numerals), the advance is
%by~$-1$. The new value of\/ |\pageno| will be appropriate for the next time
%the output routine is called into action. ^^|\global|^^|\advance|
%\begintt
%\ifnum\pageno<0 \global\advance\pageno by-1
%\else \global\advance\pageno by 1 \fi
%\endtt
\medbreak
\textindent{5)} 宏 |\advancepageno| 一般要把 |\pageno| 加 $+1$;
但是如果 |\pageno| 是负的(Roman 数字), 就加 $-1$。%
新的 |\pageno| 值在下一次输出例行程序中被调用。
\begintt
\ifnum\pageno<0 \global\advance\pageno by-1
\else \global\advance\pageno by 1 \fi
\endtt
%\medbreak
%\textindent{6)} Finally, the ^|\dosupereject| macro is designed to clear
%out any insertions that have been held over, whether they are illustrations
%or footnotes or both: ^^|\insertpenalties| ^^|\supereject|
%\begintt
%\ifnum\insertpenalties>0
% \line{} \kern-\topskip \nobreak
% \vfill\supereject\fi
%\endtt
%The mysterious negative ^|\kern| here cancels out the natural space of the
%^|\topskip| glue that goes above the empty |\line|; that empty line box
%prevents the ^|\vfill| from disappearing into a page break. The vertical
%list that results from |\dosupereject| is placed on \TeX's list of things
%to put out next, just after the straggling insertions have been
%reconsidered as explained in Chapter~15. Hence another super-eject will
%occur, and the process will continue until no insertions remain.
\medbreak
\textindent{6)} 最后,宏 |\dosupereject| 是为了把所有延迟的插入对象清除掉,
不管它们是图表还是脚注:
\begintt
\ifnum\insertpenalties>0
\line{} \kern-\topskip \nobreak
\vfill\supereject\fi
\endtt
这里的负 |\kern| 是为了抵消空 |\line| 上面出现的粘连 |\topskip| 的自然间距;
此空行的盒子是防止 |\vfill| 在分页时丢失。%
|\dosupereject| 所得到的垂直列被放在 \TeX\ 的列中以便下次使用,
就在延迟的插入对象象在第十五章中讨论的那样被重新考虑后。%
因此,出现了另一个 |\supereject|, 并且这个过程一直持续到没有插入对象为止。
%\ddangerexercise Explain how to change the output routine of plain \TeX\
%so that it will produce twice as many pages. The material that would
%ordinarily go on pages 1,~2, 3,~etc., should go onto pages 1,~3, 5,~\dots;
%and the even-numbered pages should be entirely blank except for the
%headline and footline. \ (Imagine that photographs will be mounted
%on those blank pages later.)
%\answer |\output={\plainoutput\blankpageoutput}|\parbreak
% |\def\blankpageoutput{\shipout\vbox{\makeheadline|\parbreak
% | \vbox to\vsize{}\makefootline}\advancepageno}|
\ddangerexercise 看看如何改变 plain \TeX\ 的输出例行程序才能得到两倍的页面。
原来放在第 1、2、3 页上的内容现在放在第 1、3、5 页上面;
偶数页面除了页眉和页脚之外是空白。(想象以后要把照片贴在这些空白页上。)
\answer |\output={\plainoutput\blankpageoutput}|\parbreak
|\def\blankpageoutput{\shipout\vbox{\makeheadline|\parbreak
| \vbox to\vsize{}\makefootline}\advancepageno}|
%\ddanger Suppose now that ^{double-column} format is desired.
%More precisely, let's attempt to modify plain \TeX\ so that it sets type
%in columns whose width is ^|\hsize||=3.2in|. Each actual page of
%output should contain two such columns separated by $0.1\rm\,in$ of
%space; thus the text area of each page will still be 6.5~inches wide.
%The headlines and footlines should span both columns, but the columns
%themselves should contain independent insertions as if they were the
%facing pages of a book. In other words, each column should contain
%its own footnotes and its own illustrations; we do not have to change
%the ^|\pagebody| macro. ^^{two-column format} ^^{multicolumn format}
\ddanger \1假定现在要得到双栏的格式。%
更准确地说,我们要修改 plain \TeX\ 使得它的每栏宽度为 |\hsize||=3.2in|。%
所输出的每个页面应该包含两个这样的栏,中间有 $0.1\rm\,in$ 的间距;
这样,每页的文本区仍然是 6.5 英寸宽。%
页眉和页脚要横贯两个栏,但是栏自己要象书籍对开的页面那样包含各自的插入对象。%
换句话说,每个栏有自己的脚注和图表;
我们不必改变宏 |\pagebody|。
%\ddanger In order to solve this problem, let us first introduce a
%new dimension register called ^|\fullhsize| that represents the
%width of an entire page.
%\begintt
%\newdimen\fullhsize
%\fullhsize=6.5in \hsize=3.2in
%\def\fullline{\hbox to\fullhsize}
%\endtt
%The ^|\makeheadline| and ^|\makefootline| macros should be modified
%so that they use `^|\fullline|' instead of `^|\line|'.
\ddanger 为了完成这个任务,我们首先引入新的尺寸寄存器 |\fullhsize|,
它表示整个页面的宽度。
\begintt
\newdimen\fullhsize
\fullhsize=6.5in \hsize=3.2in
\def\fullline{\hbox to\fullhsize}
\endtt
宏 |\makeheadline| 和 |\makefootline| 应该变成用`|\fullline|'而不是`|\line|'。
%\ddanger The new output routine will make use of a control sequence
%|\lr| that is set to either `|L|' or `|R|', according as the
%next column belongs at the left or at the right of the next page.
%When a left column has been completed, the output routine simply
%saves it in a box register; when a right column has been completed,
%the routine outputs both columns and increases the page number.
%^^|\advancepageno|
%\begintt
%\let\lr=L \newbox\leftcolumn
%\output={\if L\lr
% \global\setbox\leftcolumn=\columnbox \global\let\lr=R
% \else \doubleformat \global\let\lr=L\fi
% \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
%\def\doubleformat{\shipout\vbox{\makeheadline
% \fullline{\box\leftcolumn\hfil\columnbox}
% \makefootline}
% \advancepageno}
%\def\columnbox{\leftline{\pagebody}}
%\endtt
%The |\columnbox| macro uses |\leftline| in order to ensure that it produces a
%box whose width is |\hsize|. The width of\/ |\box255| is usually, but not
%always, equal to |\hsize| at the beginning of an output routine; any other
%width would louse up the format.
\ddanger 新输出例行程序将用控制系列 |\lr| 来设置`|L|'或`|R|',
根据下一栏在下一页面的左边还是右边而定。%
当左栏结束时,输出例行程序直接把它保存在盒子寄存器中;
当右栏结束时,例行程序输出两个栏并且增加页码。
\begintt
\let\lr=L \newbox\leftcolumn
\output={\if L\lr
\global\setbox\leftcolumn=\columnbox \global\let\lr=R
\else \doubleformat \global\let\lr=L\fi
\ifnum\outputpenalty>-20000 \else\dosupereject\fi}
\def\doubleformat{\shipout\vbox{\makeheadline
\fullline{\box\leftcolumn\hfil\columnbox}
\makefootline}
\advancepageno}
\def\columnbox{\leftline{\pagebody}}
\endtt
宏 |\columnbox| 使用 |\leftline| 是为了确保它得到的盒子的宽度是 |\hsize|。%
但是在输出例行程序的开头,|\box255| 的宽度通常——但不总是——等于 |\hsize|;
任何其它宽度都会把格式毁坏。
%\ddanger When double-column setting ends, there's a 50-50 chance that the
%final column has fallen at the left, so it will not yet have been output.
%The code
%\begintt
%\supereject
%\if R\lr \null\vfill\eject\fi
%\endtt
%supplies an empty right-hand column in this case, ensuring that all
%of the accumulated material will be printed. It's possible to do
%fancier column balancing on the last page, but the details are tricky
%if footnotes and other insertions need to be accommodated as well.
%Appendix~E includes the macros that were used to balance the columns at the
%end of the index in Appendix~I\null, and to start two-column format in mid-page.
\ddanger 当双栏设置完毕时,最后一栏处在左边有一半的几率,
因此仍然不能输出。%
在这种情况下,代码
\begintt
\supereject
\if R\lr \null\vfill\eject\fi
\endtt
补上一个空白的右栏,以确保所有的内容都被输出。%
在最后一页,可以把两栏对齐,但是如果还要容纳下脚注和其它插入对象就要有些技巧。%
附录 E 中有用来对齐附录 I 中索引结尾的宏,
并且在页面中间开始一个双栏格式。
%\ddangerexercise How should the example above be modified if you want
%^{three-column output}?
%\answer Set |\hsize=2.1in|, allocate `|\newbox\midcolumn|', and use the
%following code:
%\begintt
%\output={\if L\lr
% \global\setbox\leftcolumn=\columnbox \global\let\lr=M
% \else\if M\lr
% \global\setbox\midcolumn=\columnbox \global\let\lr=R
% \else \tripleformat \global\let\lr=L\fi\fi
% \ifnum\outputpenalty>-20000 \else\dosupereject\fi}
%\def\tripleformat{\shipout\vbox{\makeheadline
% \fullline{\box\leftcolumn\hfil\box\midcolumn\hfil\columnbox}
% \makefootline}
% \advancepageno}
%\endtt
%At the end, |\supereject| and say `|\if L\lr \else\null\vfill\eject\fi|'
%twice.
\ddangerexercise 怎样修改上面的例子才能得到三栏的输出?
\answer 设定 |\hsize=2.1in|,分配 `|\newbox\midcolumn|',然后使用下面的代码:
\begintt
\output={\if L\lr
\global\setbox\leftcolumn=\columnbox \global\let\lr=M
\else\if M\lr
\global\setbox\midcolumn=\columnbox \global\let\lr=R
\else \tripleformat \global\let\lr=L\fi\fi
\ifnum\outputpenalty>-20000 \else\dosupereject\fi}
\def\tripleformat{\shipout\vbox{\makeheadline
\fullline{\box\leftcolumn\hfil\box\midcolumn\hfil\columnbox}
\makefootline}
\advancepageno}
\endtt
在最后,使用 |\supereject| 并写两遍 `|\if L\lr \else\null\vfill\eject\fi|'。
%\ddanger Since \TeX's output routine lags behind its page-construction
%activity, you can get erroneous results if you change the |\headline| or the
%|\footline| in an uncontrolled way. For example, suppose that you are
%typesetting a book, and that the format you are using allows chapters
%to start in the middle of a page; then it would be a mistake to change
%the ^{running headline} at the moment you begin a new chapter, since the
%next actual page of output might not yet include anything from the new
%chapter. Consider also the task of typesetting a dictionary or a
%membership roster; a well-designed reference book displays the current range
%of entries at the top of each page or pair of pages, so that it is
%easy for readers to thumb through the book when they are searching for
%isolated words or names. But \TeX's asynchronous output mechanism
%makes it difficult, if not impossible, to determine just what range
%of entries is actually present on a page.
\ddanger \1因为 \TeX\ 的输出例行程序滞后于其构建页面的动作,
所以如果要无限制地改动 |\headline| 或者 |\footline| 就会得到错误的结果。%
例如,假定要排版一本书,你所使用的格式允许在页面中间开始一章;
这样,如果在开始新的章时改动可变的页眉是不对的,
因为实际的页面可能还没有包括新章的任何内容。%
再看看排版字典或会员册;
设计精良的参考书在每页或每对开页的顶部都给出了当前内容的区间,
使得读者在查找单个单词或人名时很容易翻阅。%
但是 \TeX\ 非同步的输出方法使得难以找出当前页上内容的区间,即使可以找见。
%\ddanger Therefore \TeX\ provides a way to put ``^{marks}'' into a list;
%these marks inform the output routine about the range of information on
%each page. The general idea is that you can say ^^|\mark|
%\begindisplay
%|\mark{|\<mark text>|}|
%\enddisplay
%in the midst of the information you are typesetting, where the
%\<mark text> is a token list that is expanded as in the commands
%|\edef|, |\message|, etc. \TeX\ puts an internal representation of
%the mark text into the list it is building; then later on, when a
%completed page is packed into |\box255|, \TeX\ allows the output
%routine to refer to the first and last mark texts on that page.
\ddanger 因此, \TeX\ 给出了一种方法,把``标记''放在列中;
这些标记告诉输出例行程序每个页面内容的区间。%
一般思路是,可以在你所排版的内容中间声明
\begindisplay
|\mark{|\<mark text>|}|
\enddisplay
其中 \<mark text> 是一个记号列,展开后是命令 |\edef|, |\message| 等等。%
\TeX\ 把这些标记文本的内部表示放在正在建立的列中;
接着随后,当整个页被封装在 |\box255| 中时,
\TeX\ 允许输出例行程序调用本页的第一和最后一个标记文本。
%\ddanger The best way to think of this is probably to imagine that
%\TeX\ generates an arbitrarily long vertical list of boxes, glue,
%and other items such as penalties and marks. Somehow that long vertical
%list gets divided up into pages, and the pages are made available to
%the output routine, one at a time. Whenever a page is put in |\box255|,
%\TeX\ sets up the value of three quantities that act essentially
%like macros:\enddanger
%\smallskip
%\item\bull ^|\botmark| is the mark text most recently encountered on the
%page that was just boxed;
\ddanger 理解它的最好方法可能是把它想像为 \TeX\ 输出的一个任意长的垂直列,
其中有盒子,粘连和象惩罚和标记这样的其它项目。%
由于某种原因,整个长的垂直列被分割为页面,并且这些页面一次只有一个进入输出例行程序。%
只要页面被放在 |\box255| 中, \TeX\ 设定了本质上与宏一样的三个量的值:\enddanger
\smallskip
\item\bull ^|\botmark| 是在刚刚放在盒子中的页面上最近出现的标记文本;
%\item\bull ^|\firstmark| is the mark text that was first encountered on
%the page that was just boxed;
\item\bull ^|\firstmark| 是在刚刚放在盒子中的页面上第一次出现的标记文本;
%\item\bull ^|\topmark| has the value that |\botmark| had just before the
%current page was boxed.
%\smallbreak\noindent
%Before the first page, all three of these are null, i.e., they expand
%to nothing. When there is no mark on a page, all three are equal to
%the previous |\botmark|.
\item\bull ^|\topmark| 的值为当前页面盒子紧前面的 |\botmark| 的值。
\smallbreak\noindent
在第一个页面前,所有这三个值都是空的,即它们展开时什么也没有。%
当在页面上没有标记时,所有三个标记都等于前一个 |\botmark|。
%\ddanger For example, suppose that your manuscript includes exactly four
%marks, and that the pages are broken in such a way that |\mark{|$\alpha$|}|
%happens to fall on page~2, |\mark{|$\beta$|}| and |\mark{|$\gamma$|}|
%on page~4, and |\mark{|$\delta$|}| on page~5. Then
%$$\halign{\indent\hfil#\hfil&&\qquad\hfil#\hfil\cr
%On page&|\topmark| is&|\firstmark| is&|\botmark| is\cr
%\noalign{\vskip2pt}
%1&null&null&null\cr
%2&null&$\alpha$&$\alpha$\cr
%3&$\alpha$&$\alpha$&$\alpha$\cr
%4&$\alpha$&$\beta$&$\gamma$\cr
%5&$\gamma$&$\delta$&$\delta$\cr
%6&$\delta$&$\delta$&$\delta$\cr}$$
\ddanger 例如,假定你的文稿包括四个标记,并且分页方式如下:
|\mark{|$\alpha$|}| 出现在第 2 页,|\mark{|$\beta$|}| 和 |\mark{|$\gamma$|}|~%
在第 4 页,|\mark{|$\delta$|}| 在第 5 页。%
这样,
$$\halign{\indent\hfil#\hfil&&\qquad\hfil#\hfil\cr
页面&|\topmark| 为&|\firstmark| 为&|\botmark| 为\cr
\noalign{\vskip2pt}
1&null&null&null\cr
2&null&$\alpha$&$\alpha$\cr
3&$\alpha$&$\alpha$&$\alpha$\cr
4&$\alpha$&$\beta$&$\gamma$\cr
5&$\gamma$&$\delta$&$\delta$\cr
6&$\delta$&$\delta$&$\delta$\cr}$$
%\ddanger When you use a |\mark| command in vertical mode, \TeX\ puts a
%mark into the main vertical list. When you use a |\mark| command in
%horizontal mode, \TeX\ treats it as vertical mode material like
%^|\vadjust| and ^|\insert|; i.e., after the paragraph has been broken
%into lines, each mark will go into the main vertical list just after the
%box for the line where that mark originally appeared. If
%you use |\mark| in restricted horizontal mode, the mark may migrate out to
%the enclosing vertical list in the same way that |\insert| and |\vadjust|
%items do (see Chapter~24); but a mark that is locked too deeply inside
%a box will not ^{migrate}, so it will never appear as a |\firstmark|
%or |\botmark|. Similarly, a |\mark| that occurs in internal vertical mode
%goes into a vbox, and it is not accessible in the main vertical list.
\ddanger \1当在垂直模式下使用 |\mark| 命令时, \TeX\ 把一个标记放在主垂直列中。%
当在水平模式下使用 |\mark| 命令时, \TeX\ 把它看作象 |\vadjust| 和 |\insert|~%
那样垂直模式下的内容;
即,在分段为行后,每个标记在主垂直列中的位置就在它最初出现的行的紧后面。%
如果在受限水平模式下使用 |\mark|, 那么标记就用与 |\insert| 和 |\vadjust|~%
同样的方法移出封装的垂直列(见第二十四章);
但是在盒子中埋得太深的标记不会移出,因此它不会作为 |\firstmark| 或%
~|\botmark| 而出现。%
类似地,出现在内部垂直模式下的 |\mark| 将放在一个 vbox 中,
并且它也不进入主垂直列。
%\ddanger Chapter 15 discusses the ^|\vsplit| command, which allows you to
%break up vertical lists by yourself. This operation sometimes provides
%a useful alternative to \TeX's ordinary page-building mechanism.
%For example, if you simply want to typeset some material in two columns
%of equal height, you can put that material into a vbox, then |\vsplit|
%the box into two pieces; no output routine is needed at all. The
%|\vsplit| operation sets up the values of two macro-like quantities
%that were not mentioned in Chapter~15: ^|\splitfirstmark| and
%^|\splitbotmark| expand to the mark texts of the first and last
%marks that appear in the vertical list that was split off by the most
%recent |\vsplit| command. Both quantities are null if there were no
%such marks. The values of\/ |\topmark|, |\firstmark|, |\botmark|,
%|\splitfirstmark|, and |\splitbotmark| are global; i.e., they are
%not affected by \TeX's ^{grouping} mechanism.
\ddanger 第十五章讨论了命令 |\vsplit|, 它本身就可以分割垂直列。%
这个命令有时候可以用在 \TeX\ 普通的页面构建上。%
例如,如果要直接把某些内容放在等高的两个栏中,就可以把它们放在一个 vbox 中,
接着用 |\vsplit| 把盒子分为两半;根本不需要任何输出例行程序。%
命令 |\vsplit| 设置了两个类似于宏的量,它们在第十五章没有被讨论:
|\splitfirstmark| 和 |\splitbotmark| 就延伸为最近的 |\vsplit| 命令所裂分的垂直列中%
出现的第一和最后一个标记文本。%
如果没有这样的标记,它们就是空的。%
|\topmark|, |\firstmark|, |\botmark|,
|\splitfirstmark| 和 |\splitbotmark| 的值是全局的;即,
它们不受 \TeX\ 编组的影响。
%\ddanger Most dictionaries use the equivalent of\/ |\firstmark| and |\botmark|
%to give ^{guide words} at the top of each pair of facing pages. For example,
%if the definition of the word `type' starts on page~1387 and continues
%onto page~1388, the guide word on page~1387 (a right-hand page)
%will be `type'; but the guide word at the top of page~1388 (a left-hand page)
%will be the next word in the dictionary (e.g., `typecast') even though
%the top of page~1388 is about `type'.
\ddanger 大多数字典在对开页面的顶部用 |\firstmark| 和 |\botmark| 配对来给出引导词。%
例如,如果单词`type'的定义起于第 1387 页,并且延续到第 1388 页,
那么在 1387 页(页在右边)的引导词为`type';
但是在 1388 页(页在左边)的引导词为字典中的下一个词(比如,`typecast'),
即使 1388 页上还有`type'的内容。
%\ddanger The dictionary scheme works fine for dictionaries, since a reader
%should start reading each dictionary entry at its beginning. But a different
%scheme is appropriate for a technical book like the author's {\sl^{Art
%of Computer Programming}}, ^^{Knuth} where Section~1.2.8 (for example)
%starts in the middle of page~78, but the top of page~78 contains
%exercises 19--24 of Section~1.2.7. The headline at the top of page~78
%refers to `1.2.7', because that will help somebody who is searching
%for exercise 1.2.7--22. Notice that the dictionary convention would put
%`1.2.8' at the top of page~78, but that would be appropriate only if
%Section~1.2.8 had begun exactly at the top of that page.
\ddanger 字典的程序可以很好地处理字典,因为读者每次是从头开始查阅字典的。%
但是对象作者的专业书籍 {\sl^{Art of Computer Programming}} 需要用不同的方法,
其中第 1.2.8 节(例如)从第 78 页的中间开始,但是第 78 页的顶部包含有第 1.2.7 节%
的练习 19--24。%
第 78 页的页眉指的是`1.2.7', 这样对查找练习 1.2.7--22 有好处。%
注意,字典的约定是把 1.2.8 放在第 78 页,但是只有当第 1.2.8 节从此页顶部就开始%
这才比较合适。
%\ddanger Continuing this example from {\sl The Art of Computer Programming},
%let's suppose that the \TeX\ manuscript for Section~1.2.8 begins with
%a macro call like
%\begintt
%\beginsection 1.2.8. Fibonacci Numbers.
%\endtt
%How should |\beginsection| be defined? Here is one attempt:
%\begintt
%\def\beginsection #1. #2.
% {\sectionbreak
% \leftline{\sectionfont #1. #2}
% \mark{#1}
% \nobreak\smallskip\noindent}
%\endtt
%The |\sectionbreak| macro should encourage \TeX\ either to break the page at the
%current position, or to leave a goodly amount of blank space; e.g.,
%|\sectionbreak| might be an abbreviation for `|\penalty-200| |\vskip18pt|
%|plus4pt| |minus6pt|'. The |\beginsection| macro ends with commands that
%suppress indentation of the first paragraph in the section. But the thing
%that concerns us with respect to output routines is the |\mark| command
%that follows |\leftline|. In the example we have been considering, the