-
Notifications
You must be signed in to change notification settings - Fork 17
/
Copy pathchapter20.tex
executable file
·2832 lines (2692 loc) · 145 KB
/
chapter20.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 20. Definitions\\(also called Macros)
\beginchapter Chapter 20. 宏定义
\origpageno=199
%You can often save time typing math formulas by letting ^{control sequences}
%stand for constructions that occur frequently in a particular manuscript.
%For example, if some document uses the vector `$(x_1,\ldots,x_n)$' a lot,
%you can type
%\begintt
%\def\xvec{(x_1,\ldots,x_n)}
%\endtt
%and |\xvec| will henceforth be an abbreviation for `|(x_1,\ldots,x_n)|'.
%Complex displays \rlap{like}
%$$\def\xvec{(x_1,\ldots,x_n)}
%\sum_{\xvec\ne(0,\ldots,0)} \bigl(f\xvec+g\xvec\bigr)$$
%can then be typed simply as
%\begintt
%$$\sum_{\xvec\ne(0,\ldots,0)} \bigl(f\xvec+g\xvec\bigr)$$
%\endtt
%instead of in a tedious long form. By ^{defining a control sequence}
%like |\xvec|, you not only cut down on the number of keystrokes that you need
%to make, you also reduce your chances of introducing typographical errors
%and inconsistencies. ^^{abbreviations, see macros}
\1在 \TeX\ 文稿中,把经常用到的命令和符号的组合用控制系列来表示,
在输入时就可以节约时间了。%
例如,如果在文档中用到很多`$(x_1,\ldots,x_n)$',
那么就可以输入
\begintt
\def\xvec{(x_1,\ldots,x_n)}
\endtt
这样就把 |\xvec| 定义为`|(x_1,\ldots,x_n)|'了。%
因此,象
$$\def\xvec{(x_1,\ldots,x_n)}
\sum_{\xvec\ne(0,\ldots,0)} \bigl(f\xvec+g\xvec\bigr)$$
这样复杂的陈列公式就可以简单地输入为
\begintt
$$\sum_{\xvec\ne(0,\ldots,0)} \bigl(f\xvec+g\xvec\bigr)$$
\endtt
而不需要用冗长的输入。%
通过定义象 |\xvec| 这样的控制系列,不但可以减轻输入的工作量,
还可以在输入时减少出现错误和矛盾的机会。
%Of course, you usually won't be making a definition just to speed up the
%typing of one isolated formula; that doesn't gain anything, because time goes by
%when you're deciding whether or not to make a definition, and when you're
%typing the definition itself. The real payoff comes when some cluster of
%symbols is used dozens of times throughout a manuscript. A wise typist will
%look through a document before typing anything, thereby getting a feeling
%for what sorts of problems will arise and what sorts of definitions will
%be helpful. For example, Chapter~16 recommends that the control sequence
%|\Ahat| be defined at the beginning of any manuscript that makes frequent
%use of the symbol~$\hat A$.
当然,通常不要单单为快速输入一个公式而给出定义;
这样没什么好处,因为在你决定是否给出定义时,以及输入定义本身时就花掉时间了。%
只有当整个文稿中用到某些符号组合的次数超过一打时,才真正能得到好处。%
在排版前,聪明的人会浏览一下整个文档,对要出现的问题和要用到的定义有一个印象。%
例如,第十六章建议,对频繁使用符号 $\hat A$ 的文稿,在其开头给出控制系列 |\Ahat| 的定义。
%Abbreviations like |\xvec| turn out to be useful in many applications of
%computers, and they have come to be known as {\sl^{macros}\/} because they
%are so powerful; one little macro can represent an enormous amount of
%material, so it has a sort of macroscopic effect. System programs like
%\TeX\ that are designed to deal with macro definitions are said to {\sl
%expand\/} the user's macros; for example, |\xvec| expands into
%|(x_1,\ldots,x_n)|, and ^|\ldots| in turn is a macro that expands into
%|\mathinner{\ldotp\ldotp\ldotp}|. Thus, |\xvec| is actually an
%abbreviation for `|(x_1,\mathinner{\ldotp\ldotp\ldotp},x_n)|'. \ (The
%expansion stops here, because ^|\mathinner| is a primitive control
%sequence of \TeX, and because |\ldotp| has been defined with
%^|\mathchardef|; thus |\mathinner| and |\ldotp| are not macros.)
像 |\xvec| 这样的缩写在很多计算机应用中都很有用,
并且因为其威力巨大而被称为{\KT{10}宏};
一个很小的宏可以表示很多的内容,因此它有一种宏观效果。
像 \TeX\ 这样的系统程序,它处理用户定义的方法被称为{\KT{10}宏展开};
例如 |\xvec| 展开为 |(x_1,\ldots,x_n)|,而 |\ldots| 实际也是一个宏,
它接着展开为 |\mathinner{\ldotp\ldotp|\allowbreak |\ldotp}|。因此,
|\xvec| 实际上是 `|(x_1,\mathinner{\ldotp\ldotp|\allowbreak|\ldotp},x_n)|'
的缩写。(展开到此为止,因为 |\mathinner| 是 \TeX\ 的原始控制系列,
而且 |\ldotp| 已经由 |\mathchardef| 定义好了;
因此,|\mathinner| 和 |\ldotp| 不是宏。)
%\TeX\ users generally build up their own personal ^{library of macros} for
%things that they want to do in different documents. For example, it is common
%to have a file called |macros.tex| that contains definitions of your favorite
%special control sequences, perhaps together with commands that load your
%favorite special fonts, etc. If you begin a document with the command
%\begintt
%\input macros
%\endtt
%then \TeX\ will read all those definitions, ^^|\input|
%saving you all the trouble of retyping them. Of course, \TeX's memory is
%limited, and it takes time to read a file, so you shouldn't put thousands
%of definitions into |macros.tex|. A large collection of macro definitions
%(e.g., the set of definitions in Appendix~B) is called a {\sl^{format}\/}
%(e.g., ``plain \TeX\ format''); \TeX\ has a special way to input
%a format at high speed, assuming that the format doesn't change very often.
\TeX\ 用户一般要建立自己个人的宏库,以便在不同的文档中使用。%
例如,一般建立一个叫 |macros.tex| 的文件,其中有你喜爱的专用控制系列的定义,
可能还有载入所喜欢的特殊字体的命令,等等。%
如果在文稿开头输入命令:
\begintt
\input macros
\endtt
那么 \TeX\ 将读入所有这些定义,省得你再次输入它们了。%
当然, \TeX\ 的内存有限,读入文件要花时间,
因此不要在 |macros.tex| 中放上千个定义。%
\1一个大的宏定义集(比如,附录 B 中的定义集)称为一个{\KT{10}格式}(比如,%
``plain \TeX\ 格式'');
如果格式不经常改变,那么 \TeX\ 能用一种特殊的方式快速输入一个格式。
%The |\xvec| and |\Ahat| examples apply to math formulas, but you can make
%good use of macro definitions even when you aren't doing any math at all.
%For example, if you are using \TeX\ for ^{business correspondence},
%you can have a |\yours| macro that stands for `Sincerely yours, A.~U.
%^{Thor}'. If you often write ^{form letters} you can have macros that
%generate entire sentences or paragraphs or groups of paragraphs.
%The ^{Internal Revenue Service} could, for example, make use of the
%following two macros:
%\begintt
%\def\badcheck{A penalty has been added because your
% check to us was not honored by your bank.\par}
%\def\cheater{A penalty of 50\% of the underpaid tax
% has been added for fraud.\par}
%\endtt
%Simple macro definitions, like these, start with `|\def|'; then comes the
%control sequence name, e.g., `|\badcheck|'; and then comes the replacement
%text enclosed in `|{|' and~`|}|'. The ^{braces} do not represent
%^{grouping} in this case; they simply show the extent of the replacement
%text in the definition. You could, of course, define a macro that
%includes actual braces in its replacement text, as long as those braces
%match each other properly. For example, `|\def\xbold{{\bf x}}|'
%makes |\xbold| an abbreviation for `|{\bf x}|'.
例子 |\xvec| 和 |\Ahat| 是应用于数学公式的,但是即使与数学无关时,
宏定义也非常有用。%
例如,如果要用 \TeX\ 进行商业通信,
就可以用宏 |\yours| 了表示`Sincerely yours, A.~U. ^{Thor}'。%
如果经常用到格式信函,就可以用宏生成整个句子或段落,或者是一组段落。%
例如,税务机关可以用下面两个宏:
\begintt
\def\badcheck{A penalty has been added because your
check to us was not honored by your bank.\par}
\def\cheater{A penalty of 50\% of the underpaid tax
has been added for fraud.\par}
\endtt
象这样简单的宏定义以`|\def|'开始;
接着是控制系列的名字,比如`|\badcheck|';
再接着是要替换的文本,它们要封装在`|{|'和`|}|'中。%
在这种情况下,大括号不表示编组;
它们直接表明定义中要替换的文本的范围。%
当然,在替换文本中包含大括号的宏也是可以定义的,
只要这些大括号互相正确匹配即可。%
例如,`|\def\xbold{{\bf x}}|'把 |\xbold| 定义为`|{\bf x}|'。
%\exercise
%Write a |\punishment| macro that prints 100 lines containing the message
%`I must not talk in class.' \ [{\sl Hint:\/} First write a macro |\mustnt|
%that prints the message once; then write a macro |\five| that prints it
%five times.] \checkequals\punishexno\exno
%\answer |\def\mustnt{I must not talk in class.\par}|\parbreak
% |\def\five{\mustnt\mustnt\mustnt\mustnt\mustnt}|\parbreak
% |\def\twenty{\five\five\five\five}|\parbreak
% |\def\punishment{\twenty\twenty\twenty\twenty\twenty}|\par
%\smallskip\noindent Solutions to more complicated problems of this type are
%discussed later.
\exercise
定义 |\punishment| 宏,它要将 `I must not talk in class.' 这句话打印 100 行。%
[{\KT{10}提示}:首先定义打印一次的宏 |\mustnt|,再定义把 |\mustnt| 输出五次的宏。]
\checkequals\punishexno\exno
\answer |\def\mustnt{I must not talk in class.\par}|\parbreak
|\def\five{\mustnt\mustnt\mustnt\mustnt\mustnt}|\parbreak
|\def\twenty{\five\five\five\five}|\parbreak
|\def\punishment{\twenty\twenty\twenty\twenty\twenty}|\par
\smallskip\noindent 稍后我们将讨论如何解决这种类型的更复杂的问题。
%\dangerexercise What is the expansion of\/ |\puzzle|, given the following
%definitions?
%\begintt
%\def\a{\b}
%\def\b{A\def\a{B\def\a{C\def\a{\b}}}}
%\def\puzzle{\a\a\a\a\a}
%\endtt
%\answer |ABCAB|. \ (The first |\a| expands into |A\def\a{B...}|; this redefines
%|\a|, so the second |\a| expands into |B...|, etc.) \ At least, that's what
%happens if\/ |\puzzle| is encountered when \TeX\ is building a list. But if
%|\puzzle| is expanded in an ^|\edef| or ^|\message| or something like that,
%we will see later that the interior |\def| commands are not performed
%while the expansion is taking place, and the control sequences following
%|\def| are expanded; so the result is an infinite string
%\begintt
%A\def A\def A\def A\def A\def A\def A\def A\def A...
%\endtt
%which causes \TeX\ to abort because the program's input stack is finite.
%This example points out that a control sequence (e.g., |\b|) need not be
%defined when it appears in the replacement text of a definition. The example
%also shows that \TeX\ doesn't expand a macro until it needs to.
\dangerexercise 对于下面给出的宏定义,|\puzzle| 宏展开后是什么?
\begintt
\def\a{\b}
\def\b{A\def\a{B\def\a{C\def\a{\b}}}}
\def\puzzle{\a\a\a\a\a}
\endtt
\answer |ABCAB|。(第一个 |\a| 展开为 |A\def\a{B...}|;它重定义了 |\a|,
因此第二个 |\a| 展开为 |B...|,依次类推。)%
至少,若 \TeX\ 是在构建列表时遇到 |\puzzle|,这就是所得到的结果。
但如果 |\puzzle| 是在类似 ^|\edef| 或 ^|\message| 的地方展开,
我们稍后将看到,当执行宏展开时,内部的 |\def| 命令将不会被执行,
而 |\def| 之后的控制系列却被展开;因此结果就是一个无穷的字符串:
\begintt
A\def A\def A\def A\def A\def A\def A\def A\def A...
\endtt
\TeX\ 的输入栈是有限的,因此这导致它中止执行。
此例子指出,控制系列(比如 |\b|)在宏定义的替换文本出现时可以还未定义。
此例子还显示 \TeX\ 仅在需要用到时才展开一个宏。
%\danger As soon as you get the hang of simple macros like those illustrated
%above, you will probably begin to think, ``Boy, wouldn't it be nice if I could
%have a macro in which some of the text in the expansion is changeable? I'd like
%to be able to stick different things into the middle of that text.'' Well,
%\TeX\ has good news for you: Control sequences can be defined in terms of
%{\sl^{parameters}}, and you can supply {\sl^{arguments}\/} that will be
%substituted for the parameters.
\danger 只要你略微思考一下上面例子中的简单宏,可能就会想:
``小子,如果宏展开后某些文本可以改变不是更好?
最好能把不同的东西放在那些文本中间。''
好, \TeX\ 带来了好消息:
控制系列可以用{\KT{10}参数}的方式来定义,
并且你可以给出要代替参数的{\KT{10}参量}。
%\danger For example, let's consider |\xvec| again. Suppose that you not only
%refer to `$(x_1,\ldots,x_n)$', but you also make frequent use of
%`$(y_1,\ldots,y_n)$' and other similar things. Then you might want to type
%\begintt
%\def\row#1{(#1_1,\ldots,#1_n)}
%\endtt
%\def\row#1{(#1_1,\ldots,#1_n)}%
%after which |\row x| will produce `$\row x$' and |\row y| will produce
%`$\row y$'. The symbol |#1| ^^{sharpsign} stands for the first parameter to
%the macro, and when you say `|\row|~|x|' the |x| is a so-called argument that
%will be inserted in place of the |#1|'s in the replacement text. In this
%case the argument consists of a single letter, |x|. You can also say
%|\row\alpha|, in which case the argument will be the control sequence
%^|\alpha|, and the result will be `$\row\alpha$'. If you want the argument
%to contain more than one symbol or control sequence, you can simply enclose
%it in ^{braces}; for example, |\row{x'}| yields $\row{x'}$. The argument
%in this case is |x'| (without the braces). Incidentally, if you say
%|\row{{x'}}|, you get $\row{{x'}}$; the reason is that only one pair of
%braces is stripped off when the argument is collected, and
%$({x'}_1,\ldots,{x'}_n)$ is what you get from
%|({x'}_1,\ldots,{x'}_n)| in math mode, according to the rules
%of Chapter~16. ^^{apostrophe}
\danger 例如,再来看看 |\xvec|。%
假定你不只需要`$(x_1,\ldots,x_n)$', 还需要频繁用到`$(y_1,\ldots,y_n)$'%
和其它类似的公式。%
那么你可能要输入
\begintt
\def\row#1{(#1_1,\ldots,#1_n)}
\endtt
\def\row#1{(#1_1,\ldots,#1_n)}%
\1此后,|\row x| 得到的就是`$\row x$', |\row y| 得到的是`$\row y$'。%
符号 |#1| 表示宏的第一个参数,并且当你输入`|\row|~|x|'时,|x| 就是所谓的参量,
它要代替的是替换文本中 |#1|。%
在这种情况下,参量由单个字母 |x| 组成。%
你还可以使用 |\row\alpha|, 这时参量是一个控制系列,所得到的结果是`$\row\alpha$'。%
如果要让参量包含不止一个符号或控制系列,
那么可以把它们封装在大括号中;
例如,|\row{x'}| 得到的是 $\row{x'}$。%
在这种情况下,参量是 |x'|~(没有大括号)。%
顺便说一句,如果输入 |\row{{x'}}|, 那么得到的是 $\row{{x'}}$;
原因是当取参量时,只剥去一对大括号,
并且按照第十六章的规则,$({x'}_1,\ldots,{x'}_n)$ 是从 |({x'}_1,\ldots,{x'}_n)| 的%
数学模式得到的。%
%\dangerexercise Continuing this example, what is the result of
%|$\row{\bf x}$|?
%\answer \def\row#1{(#1_1,\ldots,#1_n)}$\row{\bf x}$. Note that the
%subscripts are bold here, because the expansion |(\bf x_1,\ldots,\bf x_n)|
%doesn't ``turn off'' ^|\bf|. To prevent this, one should write
%|\row{{\bf x}}|; or (better), |\row\xbold|, in conjunction with
%|\def\xbold{{\bf x}}|.
\dangerexercise 继续讨论这个例子,|$\row{\bf x}$| 得到的是什么?
\answer \def\row#1{(#1_1,\ldots,#1_n)}$\row{\bf x}$。
注意因为宏展开 |(\bf x_1,\ldots,\bf x_n)| 并未 ``关闭'' ^|\bf|,这里的下标也被加粗了。
要避免这个结果,你应该写为 |\row{{\bf x}}|;或者写为 |\row\xbold|,
并补充 |\def\xbold{{\bf x}}|。
%\danger The notation `|#1|' suggests that there might be an opportunity to have
%more than one parameter, and indeed there is. You can write, for example,
%\begintt
%\def\row#1#2{(#1_1,\ldots,#1_#2)}
%\endtt
%\def\row#1#2{(#1_1,\ldots,#1_#2)}%
%after which `|\row xn|' would be the proper protocol for `$\row xn$'. There can
%be as many as nine parameters, |#1| to~|#9|, and when you use them you must
%number them~in order. For example, you can't use |#5| in a definition unless
%the previous parameter in~that definition was called |#4|. \ (This restriction
%applies only to the initial statement of parameters, before the replacement
%text starts; the stated parameters can be used any number of times, in any
%order, in the replacement text itself.)
\danger 符号`|#1|'意味着可以有不止一个参数,的确如此。%
例如,可以输入
\begintt
\def\row#1#2{(#1_1,\ldots,#1_#2)}
\endtt
\def\row#1#2{(#1_1,\ldots,#1_#2)}%
此后,`|\row xn|'就能得到`$\row xn$'了。%
至多可以有九个参数,|#1| 到 |#9|, 并且在使用时必须按顺序来。%
例如,如果定义中没有叫做 |#4| 的前一个参数,就不能用 |#5|。%
(这个限制只适用于替换文本开始前参数的初始声明;
在替换文本自己中,所声明的参数可以任意次序地使用任意次。)
%\danger A control sequence has only one definition at a
%time, so the second definition of\/ |\row| would supersede the first one if
%both had appeared in the same document. Whenever \TeX\ encounters a macro
%that it wants to expand, it uses the most recent definition. However,
%definitions are ^{local} to the group that contains them; old definitions
%will be restored in the usual way when a ^{group} ends.
\danger 一个控制系列同时只能有一个定义,因此,
如果在同一文稿中出现两个 |\row| 的定义,那么第二个就替掉第一个。%
只要 \TeX\ 遇见要展开的宏,它就使用最近的定义。%
但是,对于包含定义的组而言,定义是局部的;
当组结束时,旧定义将按照通常的方法恢复。
%\danger Caution: When you define a macro with simple parameters, as in
%these examples, you must be careful not to put blank spaces before the
%`|{|' that begins the replacement text. For example, `|\def\row #1 #2 {...}|'
%will not give the same result as `|\def\row#1#2{...}|', because the spaces
%after |#1| and~|#2| tell \TeX\ to look for arguments that are followed by
%spaces. \ (Arguments can be ``delimited'' in a fairly general way, as
%explained below.) \ But the space after |\row| is optional, as usual,
%because \TeX\ always disregards spaces after control words. After
%you have said `|\def\row#1#2{...}|', you are allowed to put spaces
%between the arguments (e.g., `|\row x n|'), because \TeX\ doesn't
%use single spaces as undelimited arguments.
\danger 注意:当象这些例子中用简单参数定义宏时,必须注意不要在替换文本%
前面的`|{|'前留下空格。%
例如,`|\def\row #1 #2 {...}|'与`|\def\row#1#2{...}|'得到的结果是不同的,
因为 |#1| 和 |#2| 后的空格就要求 \TeX\ 去寻找后面带空格的参量。%
(就象下面讨论的那样,参量可以用相当一般的方法来``分界''。)
但是 |\row| 的空格象通常那样是任意的,因为 \TeX\ 总是忽略掉控制词后的空格。%
在给出`|\def\row#1#2{...}|'后,就允许在参量之间放置空格(比如`|\row x n|'),
因为 \TeX\ 不把单个空格当作未分界的参量。
%\danger The following exercise is particularly recommended for people who
%want to learn to write \TeX\ macros. Even if you have gotten into the
%dangerous habit of skimming other exercises, you should try your hand
%at this one.
\danger 下面的练习特别推荐给要掌握 \TeX\ 宏的人。%
即使你略过其它的练习,也要亲手做下面这个。
%\dangerexercise Extending exercise 20.\punishexno, write a ``generalized
%punishment'' macro that has two parameters, so that |\punishment{run}{the
%halls}| will produce 100 paragraphs that say `I~must not run in the halls.'
%\answer The catch is that the parameters have to percolate down to the
%|\mustnt| macro, if you extend the previous answer:
%\begintt
%\def\mustnt#1#2{I must not #1 in #2.\par}
%\def\five#1#2{\mustnt{#1}{#2}...\mustnt{#1}{#2}}
%\def\twenty#1#2{\five{#1}{#2}...\five{#1}{#2}}
%\def\punishment#1#2{\twenty{#1}{#2}...\twenty{#1}{#2}}
%\endtt
%When you pass parameters from one macro to another in this way, you need to
%enclose them in braces as shown. But actually this particular solution
%punishes \TeX\ much more than it needs to, because it takes a lot of
%time to copy the parameters and read them again and again. There's a
%much more efficient way to do the job, by defining control sequences:
%\begintt
%\def\mustnt{I must not \doit\ in \thatplace.\par}
%\def\punishment#1#2{\def\doit{#1}\def\thatplace{#2}%
% \twenty\twenty\twenty\twenty\twenty}
%\endtt
%and by defining |\five| and |\twenty| without parameters as before.
%You can also delve more deeply into \TeX nicalities, constructing solutions
%that are more efficient yet; \TeX\ works even faster when macros
%communicate with each other via ^{boxes}.
%^^{efficient macros} ^^{communication between macros}
%For example,
%\begintt
%\def\mustnt{\copy0 }
%\def\punishment#1#2{\setbox0=
% \vbox{\strut I must not #1 in #2.\strut}%
% \twenty\twenty\twenty\twenty\twenty}
%\endtt
%sets 100 identical paragraphs at high speed, because \TeX\ has to
%process the paragraph and break it into lines only once. It's much faster
%to ^{copy a box} than to build it up from scratch. \ (The ^{struts} in
%this example keep the interbaseline distances correct between boxed
%paragraphs, as explained in Chapter~12. Two struts are used, for if the
%message takes more than one line there will be a strut at both top
%and bottom. If it were known that each sentence will occupy only a single
%line, no struts would be needed, because interline glue is added as
%usual when a box created by |\copy| is appended to the current vertical list.)
\dangerexercise 扩展练习 20.\punishexno ,
定义一个适用更广的``处罚''宏,它有两个参数,且使用
|\punishment{run}{the halls}| 得到的是 100 句 `I~must not run in the halls.'。
\answer 陷阱在于,如果你在之前答案的基础上改进,
参数必须逐级传入到 |\mustnt| 宏的定义中:
\begintt
\def\mustnt#1#2{I must not #1 in #2.\par}
\def\five#1#2{\mustnt{#1}{#2}...\mustnt{#1}{#2}}
\def\twenty#1#2{\five{#1}{#2}...\five{#1}{#2}}
\def\punishment#1#2{\twenty{#1}{#2}...\twenty{#1}{#2}}
\endtt
当你用这种方式将参数从一个宏传递到另一个宏,你需要如上所示将参数包围在花括号中。
但实际上此种解法太过为难 \TeX 了,因为它将让 \TeX\ 费时地一次次复制并读取参数。
还有一种更有效率的解决方法,即定义下面的控制系列:
\begintt
\def\mustnt{I must not \doit\ in \thatplace.\par}
\def\punishment#1#2{\def\doit{#1}\def\thatplace{#2}%
\twenty\twenty\twenty\twenty\twenty}
\endtt
而且像之前那样将 |\five| 和 |\twenty| 定义为无参数的宏。
通过深入探究 \TeX\ 技术,你还可以构造更加有效率的解法;
当宏与宏之间利用^{盒子}传递内容时,\TeX\ 的运行速度快多了。
^^{efficient macros} ^^{communication between macros}
例如,
\begintt
\def\mustnt{\copy0 }
\def\punishment#1#2{\setbox0=
\vbox{\strut I must not #1 in #2.\strut}%
\twenty\twenty\twenty\twenty\twenty}
\endtt
将以高速设定 100 个相同的段落,因为 \TeX\ 只需处理段落并分段为行一次。
复制一个盒子比从零开始构建它速度快多了。(如同第 12 章中所解释的,
这个例子中的^{支架}用于让盒子中的段落保持正确的基线间距离。
我们需要两个支架,因为如果消息文本需占用超过一行,这将让顶部和底部都有支架。
如果已知道每个句子都只占用一行,则无需使用支架,
因为当用 |\copy| 制造的盒子被添加到当前垂直列时,行间粘连本来将会被加上。)
%\ninepoint % the rest of this chapter is all dangerous
%\ddanger \TeX\ also allows you to define macros whose parameters are delimited
%in quite a general way; you needn't always enclose arguments in braces.
%For example,
%\begintt
%\def\cs #1. #2\par{...}
%\endtt
%defines a control sequence |\cs| with two parameters, and its two arguments
%will be determined as follows: |#1| will consist of all tokens between
%|\cs| and the next subsequent appearance of `|.|\]' (period and space);
%|#2| will consist of all tokens between that `|.|\]' and the next
%|\par| token. \ (The ^|\par| might be given explicitly, or it might be
%generated by a blank line as explained in Chapter~8.) \ For example, when
%\TeX\ expands
%\begintt
%\cs You owe \$5.00. Pay it.\par
%\endtt
%the first argument is `|You owe \$5.00|' and the second is `|Pay it.|'.
%The period in `|\$5.00|' doesn't stop |#1|, in this example,
%because \TeX\ keeps going until finding a period that is followed immediately
%by a space.
\ninepoint % the rest of this chapter is all dangerous
\ddanger \1\TeX\ 还允许定义这样的宏,其参数用相当普遍的方法来分界;
你不需要总是把参量封装在大括号中。%
例如,
\begintt
\def\cs #1. #2\par{...}
\endtt
定义了一个控制系列 |\cs|, 它有两个参数,并且这两个参数如下确定出:
|#1| 由 |\cs| 和下一个随后出现的`|.|\]'\allowbreak(句点和空格)之间的所有内容组成;
|#2| 由这个`|.|\]'和其后出现的 |\par| 之间的所有内容组成。%
(|\par| 可以明确给出,也可以由第十八章讨论的空行生成。)
例如,当 \TeX\ 展开
\begintt
\cs You owe \$5.00. Pay it.\par
\endtt
时,第一个参量是`|You owe \$5.00|', 而第二个是`|Pay it.|'。%
本例中,`|\$5.00|'中的句点不能结束 |#1|,
因为 \TeX\ 要找的是后面紧跟着空格的句点。
%\ddanger Furthermore, an argument will not stop when its delimiter is enclosed
%in braces, because that would produce unbalanced braces. For example, in
%\begintt
%\def\cs #1.#2\par{...}
%\endtt
%the first argument is now delimited by a single period, so |#1| would be
%`|You owe \$5|' and the |#2| would be `|00. Pay it.|' if\/ |\cs| were
%invoked as above. But
%\begintt
%\cs You owe {\$5.00}. Pay it.\par
%\endtt
%satisfactorily hides the first period, making it part of argument |#1|,
%which becomes \hbox{`|You owe {\$5.00}|'}.
\ddanger 还有,如果参量的分界符被封装在大括号时,这个参量不在此结束,
因为这样就得到了不匹配的大括号。例如,在
\begintt
\def\cs #1.#2\par{...}
\endtt
中,现在第一个参量到一个单句点处结束,因此,如果像上面那样调用 |\cs|,
|#1| 为 `|You owe \$5|',而 |#2| 为 `|00. Pay it.|'。但是,
\begintt
\cs You owe {\$5.00}. Pay it.\par
\endtt
圆满地藏起第一个句点,使得它不能结束参量 |#1|,
此时 |#1| 就是 \hbox{`|You owe {\$5.00}|'}。
%\ddanger If you are designing a format for mathematical papers, you will
%probably want to include a macro for the statement of ^{theorems},
%definitions, lemmas, corollaries, and such things. For example, you might
%want to typeset a statement like\enddanger
\ddanger 如果你要设计一个数学论文的格式,那么可能要有陈述定理,定义,引理,
推论等东西的宏。%
例如,可能要排版象下面这样的陈述:
\enddanger
%\proclaim Theorem 1. \TeX\ has a powerful macro capability.\par
%\noindent from the input
%\begintt
%\proclaim Theorem 1. \TeX\ has a powerful macro capability.\par
%\endtt
%In fact, plain \TeX\ includes a ^|\proclaim| macro that does just that;
%its definition is
%\begintt
%\def\proclaim #1. #2\par{\medbreak
% \noindent{\bf#1.\enspace}{\sl#2}\par\medbreak}
%\endtt
%^^{enunciations, see proclaim} ^^{enspace}
%so the arguments are delimited exactly as in our first |\cs| example. The
%replacement text here uses |\medbreak| to separate the proclaimed
%paragraph from what precedes and follows; the title of the proclamation is
%set in bold face type, while the text itself is set slanted. \ (The
%actual definition of\/ |\proclaim| in Appendix~B is not quite the same as
%this; the final |\medbreak| has been modified so that a break between
%pages will be discouraged immediately following the statement of a
%theorem. Hence a short theorem will tend to appear at the top of a page
%rather than at the bottom.)
\proclaim Theorem 1. \TeX\ has a powerful macro capability.\par
\noindent 它用下列方法得到:
\begintt
\proclaim Theorem 1. \TeX\ has a powerful macro capability.\par
\endtt
实际上,~plain \TeX\ 中有一个象这样的宏 |\proclaim|;
其定义为
\begintt
\def\proclaim #1. #2\par{\medbreak
\noindent{\bf#1.\enspace}{\sl#2}\par\medbreak}
\endtt
这样,参量就象我们 |\cs| 的第一个例子那样分界。%
这里的替换文本用 |\medbreak| 把要 proclaim 的段落与其前后内容分开;
proclaim 的题目设置为 bold 字体,而文本设置为 slanted。%
(附录 B 中 |\proclaim| 的实际定义与它不完全一样;
为了使分页不出现在定理陈述紧后面,而修改了最后的 |\medbreak|。%
因此,短小的定理更倾向于放在页面顶部而不是底部。)
%\ddanger By making changes to the |\proclaim| macro, you can change the
%format of all the proclamations in your paper, without changing the text
%of the paper itself. For example, you could produce something like\enddanger
\ddanger 通过改变宏 |\proclaim|, 你可以改变论文中所有 proclaim 的格式,
而不需要改动论文自己的文本。%
例如,可以得到象下面这样的东西:
\enddanger
%\medbreak
%\font\tencsc=cmcsc10
%\noindent {\tencsc Theorem 1:}\enspace
%{\it\TeX\ has a powerful macro capability.}
%\goodbreak\medbreak\noindent
%by making simple alterations to the replacement text of\/ |\proclaim|,
%assuming that you have a ``^{caps and small caps}'' font. \TeX\ is
%intended to support ^{higher-level languages for composition} in which all of
%the control sequences that a user actually types are macros rather than
%\TeX\ primitives. The ideal is to be able to describe important classes of
%documents in terms of their components, without mentioning actual fonts or
%point sizes or details of spacing; a single ^{style-independent document}
%^^{format-independent document}^^{generic coding}
%can then be set in many different styles.
\medbreak
\font\tencsc=cmcsc10
\noindent {\tencsc Theorem 1:}\enspace
{\it\TeX\ has a powerful macro capability.}
\goodbreak\medbreak\noindent
\1这只需要直接修改 |\proclaim| 的替换文本即可,我们假定你有所用到的字体。%
\TeX\ 希望支持复合的高级语言,其中用户使用的所有的控制系列都是宏,
而不是 \TeX\ 原始命令。%
思路是要能用几个要素来描述出重要类型的文档,
而不涉及到实际的字体,字体尺寸或详细的间距;
因此,可以用很多不同的字体来设置一个与字体无关的文档。
%\ddanger Now that we have seen a number of examples, let's look at the
%precise rules that govern \TeX\ macros. Definitions have the general form
%\begindisplay
%|\def|\<control sequence>\<parameter text>|{|\<replacement text>|}|
%\enddisplay
%where the \<parameter text> contains no ^{braces}, and where all occurrences
%of |{| and |}| in the \<replacement text> are properly nested. Furthermore
%the |#| symbol has a special significance: In the \<parameter text>, the
%first appearance of |#| must be followed by~|1|, the next by~|2|, and
%so on; up to nine |#|'s are allowed. In the \<replacement text> each~|#|
%must be followed by a digit that appeared after~|#| in the \<parameter text>,
%or else the~|#| should be followed by another~|#|. The latter case stands
%for a single~|#| token when the macro is expanded; the former case stands
%for insertion of the corresponding argument.
\ddanger 现在我们已经看到一些例子,接下来我们讨论 \TeX\ 宏的准确规则。%
定义的一般形式为
\begindisplay
|\def|\<control sequence>\<parameter text>|{|\<replacement text>|}|
\enddisplay
其中 \<parameter text> 不包含大括号,
并且在 \<replacement text> 中所出现的 |{| 和 |}| 要正确嵌套。%
还有,符号 |#| 有特殊含义:
在 \<parameter text> 中,第一个出现的 |#| 后面必须跟 |1|,
下一个要跟 |2|, 等等;
只允许九个 |#|。%
在 \<replacement text> 中,每个 |#| 后面必须跟一个在 \<parameter text> 中%
的 |#| 后面出现过的数字,或者一个 |#| 后面跟一个 |#|。%
表示当宏展开时,后一种情况表示一个单个 |#|;
前一种情况表示插入相应的参量。
%\ddanger For example, let's consider a ``random'' definition that doesn't
%do anything useful except that it does exhibit \TeX's rules. The definition
%\begintt
%\def\cs AB#1#2C$#3\$ {#3{ab#1}#1 c##\x #2}
%\endtt
%says that the control sequence |\cs| is to have a parameter text consisting of
%nine tokens
%\begindisplay
%|A|$_{11}$, \ |B|$_{11}$, \ |#1|, \ |#2|, \ |C|$_{11}$, \
% |$|$_3$, \ |#3|, \ \cstok{\char`$}, \ \]$_{10}$
%\enddisplay
%(assuming the ^{category codes} of plain \TeX), and a replacement text
%of twelve tokens
%\begindisplay
%|#3|, \ |{|$_1$, \ |a|$_{11}$, \ |b|$_{11}$, \ |#1|, \
% |}|$_2$, \ |#1|, \ \]$_{10}$, \ |c|$_{11}$, \ |#|$_6$, \ \cstok{x}, \ |#2|.
%\enddisplay
%Henceforth when \TeX\ reads the control sequence |\cs| it will expect that
%the next two tokens will be |A|$_{11}$ and |B|$_{11}$ (otherwise you will
%get the error message `|Use| |of| |\cs| |doesn't| |match| |its|
%|definition|'); then comes argument~|#1|, followed by argument~|#2|,
%then~|C|$_{11}$, then~|$|$_3$, then argument~|#3|, then |\$|, and finally
%a space token. It is customary to use the word ``argument'' to mean the
%string of tokens that gets substituted for a parameter; parameters appear
%in a definition, and arguments appear when that definition is used. \ (For
%the purposes of these rules, we are extending Chapter~7's definition of
%^{token}: In addition to control sequences and (character code, category
%code) pairs, \TeX\ also recognizes ``^{parameter tokens},'' denoted here
%by |#1|~to~|#9|. Parameter tokens can appear only in token lists for macros.)
\ddanger 例如,我们讨论一个``随便的''定义,
它只是为了展示 \TeX\ 的规则。%
定义
\begintt
\def\cs AB#1#2C$#3\$ {#3{ab#1}#1 c##\x #2}
\endtt
表示,控制系列 |\cs| 有一个参数文本,它由 9 个记号组成(假定采用 plain \TeX\ 的类代码):
\begindisplay
|A|$_{11}$, \ |B|$_{11}$, \ |#1|, \ |#2|, \ |C|$_{11}$, \
|$|$_3$, \ |#3|, \ \cstok{\char`$}, \ \]$_{10}$
\enddisplay
有一个替换文本,由 12 个记号组成:
\begindisplay
|#3|, \ |{|$_1$, \ |a|$_{11}$, \ |b|$_{11}$, \ |#1|, \
|}|$_2$, \ |#1|, \ \]$_{10}$, \ |c|$_{11}$, \ |#|$_6$, \ \cstok{x}, \ |#2|.
\enddisplay
因此,当 \TeX\ 读入控制系列 |\cs| 后,要读入的下两个记号应该是 |A|$_{11}$ 和%
~|B|$_{11}$~(否则就会得到错误信息`|Use| |of| |\cs| |doesn't| |match| |its|
|definition|');
接下来是参量 |#1|, 参量 |#2|, ~|C|$_{11}$, ~|$|$_3$, 再接着是参量 |#3|,
|\$|, 最后是空格记号。%
习惯上用``参量''这个词表示要替换参数的记号串;
参数出现在定义中,而当使用定义时,出现的是参量。%
(为此,我们要扩展第七章记号的定义:除了控制系列和(字符代码,类代码)对外,
\TeX\ 还有``参数记号'', 在这里它用 |#1| 到 |#9| 来 表示。%
参数记号只出现在宏的记号列中。
%\ddanger How does \TeX\ determine where an argument stops, you ask.
%Answer: There are two cases. A {\sl^{delimited parameter}\/} is followed
%in the \<parameter text> by one or more non-parameter tokens, before
%reaching the end of the parameter text or the next parameter token;
%in this case the corresponding argument is the shortest (possibly empty)
%sequence of tokens with properly nested |{...}| groups that is followed in
%the input by this particular list of non-parameter tokens. \ (Category
%codes and character codes must both match, and control sequence names
%must be the same.) \ An {\sl^{undelimited parameter}\/} is followed immediately
%in the \<parameter text> by a parameter token, or it occurs at the very end
%of the parameter text; in this case the corresponding argument is the
%next nonblank token, unless that token is `|{|', when the argument will
%be the entire |{...}| group that follows. In both cases, if the argument
%found in this way has the form `|{|\<nested tokens>|}|', where \<nested
%tokens> stands for any sequence of tokens that is properly nested with
%respect to braces, the outermost braces enclosing the argument are removed
%and the \<nested tokens> will remain. For example, let's continue with
%|\cs| as defined above and suppose that the subsequent text contains
%\begintt
%\cs AB {\Look}C${And\$ }{look}\$ 5.
%\endtt
%Argument |#1| will be the token \cstok{Look}, since |#1| is an undelimited
%parameter (it is followed immediately by~|#2| in the definition);
%in this case \TeX\ ignores the blank space after |B|, and strips the
%braces off~of |{\Look}|. Argument~|#2| will be empty, since |C$| follows
%immediately. And argument~|#3| will be the thirteen tokens corresponding
%to the text |{And\$|\]|}{look}|, because |#3| is to be followed by `|\$|\]',
%and because the first occurrence of `|\$|\]' is within braces. Even though
%argument~|#3| begins with a left brace and ends with a right brace, the
%braces are not removed, since that would leave the unnested tokens `|And\$
%}{look|'. The net effect then, after substituting arguments for
%parameters in the replacement text, will be that \TeX\ will next read the
%token list
%\begintt
%{And\$ }{look}{ab\Look}\Look|]c#\x5.
%\endtt
%The space \] here will be part of the resulting token list, even though
%it follows the control word |\Look|, because ^{spaces} are removed
%after ^{control word} tokens only when \TeX\ first converts input lines to
%token lists as described in Chapter~8.
\ddanger 问: \TeX\ 怎样才能知道参量在哪里结束?
答:分两种情况。%
在 \<parameter text> 中,{\KT{9}分界的参数}要跟一个或多个非参数记号,
才能到达参数文本的结尾或下一个参数记号;
在这种情况下,相应的参量是长度最短(可能是空)的记号序列,并且组的嵌套要正确,
后面跟的是在输入中的非参数记号列。%
(类代码和字符代码都要匹配,而且控制系列命名必须相同。)
在 \<parameter text> 中,{\KT{9}未分界的参数}后面要紧接一个参数记号,
或者要出现在参数文本的最结尾;
\1在这种情况下,相应的参量就是下一个非空的记号,如果此记号是`|{|', 这时%
参量是所跟的整个组 |{...}|。%
在所有两种情况下,如果用这两种方法找到的的参量的形式为`|{|\<nested tokens>|}|',
其中 \<nested tokens>~ 表示关于大括号正确嵌套的任意记号列,
那么就去掉封装记号的最外层的盒子,只留下 \<nested tokens>。%
例如,我们继续讨论上面的例子 |\cs|, 假定接下来的文本包含
\begintt
\cs AB {\Look}C${And\$ }{look}\$ 5.
\endtt
参量 |#1| 将是记号 \cstok{Look}, 因为 |#1| 是未分界的参数(在定义中,
它后面紧跟的是 |#2|);
在这种情况下, \TeX\ 将忽略掉 |B| 后面的空格,并且剥去 |{\Look}| 外面的大括号。%
参量 |#2| 将是空的,因为 |C$| 紧跟着。%
而参量 |#3| 将是对应于文本 |{And\$|\]|}{look}| 的 13 个记号,
因为 |#3| 后面跟着`|\$|\]',
并且因为第一个出现的`|\$|\]'在大括号里面。%
即使参量 |#3| 以左大括号开头,以右大括号结尾,这些大括号也不会被剥去,
因为那样得到的是未嵌套的记号`|And\$ }{look|'。%
因此,总的结果是,在替换文本中用参量替换参数后, \TeX\ 下一个要读入的记号列为
\begintt
{And\$ }{look}{ab\Look}\Look|]c#\x5.
\endtt
这里的空格 \] 是得到的记号列的一部分,即使它跟在控制词 |\Look|, 因为只有当%
\TeX\ 首先把输入行转换为记号列时控制词后面的空格才去掉,就象第八章讨论的那样。%
%\ddangerexercise The example definition of\/ |\cs| includes a |##| in
%its replacement text, but the way |##| is actually used in that example
%is rather pointless. Give an example of a definition where |##| serves
%a useful purpose. ^^{sharp sharp}
%\answer The |##| feature is indispensable when the replacement text of
%a definition contains other definitions. For example, consider
%\begintt
%\def\a#1{\def\b##1{##1#1}}
%\endtt
%after which `|\a!|'\ will expand to `|\def\b#1{#1!}|'. We will see later
%that |##| is also important for alignments; see, for example, the definition
%of\/ |\matrix| in Appendix~B.
\ddangerexercise 在定义 |\cs| 的例子中,替换文本里面包含一个 |##|,
但是在此例子中这样使用 |##| 没什么意义。给出一个让 |##| 有意义的例子。
\answer 如果宏定义的替换文本中还包含另一个定义,|##| 的这个功能就是不可或缺的。
比如在下面宏定义
\begintt
\def\a#1{\def\b##1{##1#1}}
\endtt
之后,`|\a!|' 将展开为 `|\def\b#1{#1!}|'。我们稍后将看到 |##|
对于对齐阵列也是很重要的;比如看附录 B 中 |\matrix| 的定义。
%\ddanger A special extension is allowed to these rules: If the very
%last character of the \<parameter text> is~|#|, so that this~|#| is
%immediately followed by~|{|, \TeX\ will behave as if the~|{| had been
%inserted at the right end of both the parameter text and the replacement text.
%For example, if you say `|\def\a#1#{\hbox to #1}|', the
%subsequent text `|\a3pt{x}|' will expand to `|\hbox to 3pt{x}|', because
%the argument of\/ |\a| is delimited by a left brace.
%^^{dimensions as arguments}
\ddanger 这些规则允许一个特殊的扩展:
如果 \<parameter text> 的最后一个字符是 |#|, 使得这个 |#| 后面紧跟着 |{|,
那么看起来就好像 \TeX\ 把 |{| 插入到参数文本的右结尾和替换文本的右结尾处。%
例如,如果给出`|\def\a#1#{\hbox to #1}|', 那么在后面文本中的`|\a3pt{x}|'将%
展开为`|\hbox to 3pt{x}|', 因为 |\a| 的参量以左大括号为定界符。
%\ddanger Tokens that precede the first parameter token in the \<parameter
%text> of a definition are required to follow the control sequence; in
%effect, they become part of the control sequence name. For example, the author
%might have said
%\begintt
%\def\TeX/{...}
%\endtt
%instead of defining ^|\TeX| without the slash. Then it would be necessary
%to type |\TeX/| each time the \TeX\ logo is desired, but the new definition
%would have the advantage that spaces are {\sl not\/} ignored after
%`|\TeX/|'. You can use this idea to define macros that are intended to
%be used in sentences, so that users don't have to worry about the possible
%disappearance of ^{spaces}.
\ddanger 在定义的 \<parameter text> 中,在第一个参数记号前面的记号要跟在控制系列%
后面;实际上,它们变成了控制系列名字的一部分。%
例如,作者可能给出过
\begintt
\def\TeX/{...}
\endtt
而没有使用无斜线的 |\TeX| 的定义。%
这样,每次要得到 \TeX\ 标志时必须输入 |\TeX/|,
但是新定义的优点是,`|\TeX/|'的空格{\KT{9}不}被忽略掉。%
可以利用这种思路来定义在句子中使用的宏,使得用户不必担心空格可能会被吃掉。
%\ddangerexercise Define a control sequence |\a| such that |\a{...}| expands
%to |\b{...}|, and such that \TeX\ gives an error message if\/ |\a| is not
%immediately followed by a left brace.
%\answer |\def\a#{\b}|.
\ddangerexercise 定义一个控制系列 |\a| 使得 |\a{...}| 展开为 |\b{...}|,
并且使得如果 |\a| 后面没有紧跟一个左花括号 \TeX\ 就给出错误信息。
\answer |\def\a#{\b}|。
%\ddanger Complicated macros have a habit of behaving differently from what
%you expect, when you first define them, even though \TeX's rules are
%not especially complicated. If you have trouble understanding why some
%|\def| doesn't work the way you think it should, help is available:
%You can set |\tracingmacros=1|, whereupon \TeX\ will write something in
%your log file whenever it expands a macro, and whenever it has read a
%macro argument. For example, if\/ ^|\tracingmacros| is positive when
%\TeX\ processes the |\cs| example above, it will put the following
%four lines into the log: ^^{debugging macros}
%\begintt
%\cs AB#1#2C$#3\$ ->#3{ab#1}#1 c##\x #2
%#1<-\Look
%#2<-
%#3<-{And\$ }{look}
%\endtt
\ddanger \1当你第一次定义复杂的宏时,结果常常与你所预想的不同,即使 \TeX\ 的规则%
不太复杂。%
如果不知道为什么 |\def| 不听你的话,可以使用帮助:
你可以设置 |\tracingmacros=1|, 这样 \TeX\ 就在它展开宏和读入宏的参量时在你的%
~log 文件中写入一些东西。%
例如,如果在 \TeX\ 处理上面的宏 |\cs| 时 |\tracingmacros| 是正值,
它就把下列四行放到 log 文件中:
\begintt
\cs AB#1#2C$#3\$ ->#3{ab#1}#1 c##\x #2
#1<-\Look
#2<-
#3<-{And\$ }{look}
\endtt
%\ddanger In all of the rules stated above, `|{|' and `|}|' and `|#|' stand
%for any characters whose ^{category codes} are respectively 1, 2, and 6 in
%the token list when \TeX\ reads the macro definition; there's nothing
%sacred about the particular symbols that plain \TeX\ uses to denote
%grouping and parameters. You can even make use of several different
%characters with these category codes, all at the same time.
\ddanger 在上述所有规则中,`|{|', `|}|'和`|#|'表示 \TeX\ 读入宏定义时%
记号列中类代码分别为 1, 2 和 6 的任意字符;
~plain \TeX\ 表示编组和参数的这些特殊符号没有什么不能改变的。%
你甚至可以同时使用同类代码的几个不同字符。
%\ddangerexercise Suppose that `|[|', `|]|', and `|!|'\ have the respective
%catcodes 1,~2, and~6, as do `|{|',~`|}|', and~`|#|'. See if you can guess
%what the following definition means:
%\begintt
%\def\!!1#2![{!#]#!!2}
%\endtt
%What token list will result when `|\! x{[y]][z}|' is expanded?
%\answer Let's go slowly on this one, so that the answer will give enough
%background to answer all similar questions. The \<parameter text> of the
%definition consists of the three tokens |#1|, |#2|, |[|$_1$; the
%\<replacement text> consists of the six tokens |{|$_1$, |#|$_6$, |]|$_2$,
%|!|$_6$, |#2|, |[|$_1$. \ (When two tokens of category~6 occur in the
%replacement text, the character code of the second one survives; the
%character code of a category-6 character is otherwise irrelevant. Thus,
%`|\def\!#1!2#[{##]!!#2]|' would produce an essentially identical
%definition.) \ When expanding the given token list, argument~|#1| is
%|x|$_{11}$, since it is undelimited. Argument~|#2| is delimited by~|[|$_1$,
%which is different from~|{|$_1$, so it is set provisionally to |{[y]]|;
%but the outer ``braces'' are stripped off, so |#2|~reduces to the
%three tokens |[|$_1$, |y|$_{11}$,~|]|$_2$. The result of the expansion
%is therefore
%\begindisplay
%|{|$_1$ |#|$_6$ |]|$_2$ |!|$_6$ |[|$_1$ |y|$_{11}$ |]|$_2$
% |[|$_1$ |z|$_{11}$ |}|$_2$.
%\enddisplay
%Incidentally, if you display this with ^|\tracingmacros||=1|, \TeX\ says
%\begintt
%\!!1#2[->{##]!!#2[
%#1<-x
%#2<-[y]
%\endtt
%Category codes are not shown, but a character of category~6 always
%appears twice in succession. A parameter token in the replacement text
%uses the character code of the final parameter in the parameter text.
%^^{token lists, as displayed by TeX}
\ddangerexercise 假定 `|[|'、`|]|' 和 `|!|' 的类别码分别为 1、2 和 6,
就像 `|{|'、`|}|' 和 `|#|' 一样。看看下面定义的意思是什么:
\begintt
\def\!!1#2![{!#]#!!2}
\endtt
当展开`|\! x{[y]][z}|'时得到的记号列是什么?
\answer 我们将慢慢解说这个问题,给出足以回答所有类似问题的来龙去脉。
这个定义的 \<parameter text> 由三个记号 |#1|、|#2|、|[|$_1$ 组成;
而 \<replacement text> 由六个记号 |{|$_1$、|#|$_6$、|]|$_2$、|!|$_6$、
|#2|、|[|$_1$ 组成。(当两个类别 6 的记号出现在替换文本时,
只留下第二个的字符码;类别 6 字符的字符码是无关紧要的。
因此,用 `|\def\!#1!2#[{##]!!#2]|' 给出的是本质上完全相同的定义。)%
在展开给定的记号列时,参量 |#1| 是非定界的,因此它是 |x|$_{11}$。
参量 |#2| 被 |[|$_1$ 定界(此时 |[|$_1$ 和 |{|$_1$ 不同),因此它被临时设定为 |{[y]]|;
但外层的``花括号''将被剥离,因此 |#2| 减少为三个记号 |[|$_1$、|y|$_{11}$、|]|$_2$。
从而宏展开的结果为
\begindisplay
|{|$_1$ |#|$_6$ |]|$_2$ |!|$_6$ |[|$_1$ |y|$_{11}$ |]|$_2$
|[|$_1$ |z|$_{11}$ |}|$_2$.
\enddisplay
顺便说一下,如果你用 ^|\tracingmacros||=1| 显示这些,\TeX\ 将给出
\begintt
\!!1#2[->{##]!!#2[
#1<-x
#2<-[y]
\endtt
类别码不会显示出来,但类别 6 字符总是连续出现两次。
替换文本中的参数记号使用参数文本最后一个参数的字符码。
^^{token lists, as displayed by TeX}
%\ddanger In practice, we all make mistakes. And one of the most common
%typographic errors is to forget a~`|}|', or to insert an extra~`|{|',
%somewhere in an argument to a macro. If \TeX\ were to follow the rules
%blindly in such a case, it would have to keep absorbing more and
%more tokens in hopes of finding the end of the argument. But a mistyped
%argument is unending, like so many arguments in real life (sigh); so
%\TeX\ would have to go on until the end of the file, or (more likely)
%until tokens completely fill the computer's memory. In either case, a
%single typographical error would have ruined the run, and the user would
%be forced to start over. Therefore \TeX\ has another rule, intended
%to confine such errors to the paragraph in which they occur: {\sl The
%token `\thinspace^|\par|' is not allowed to occur as part of an argument},
%unless you explicitly tell \TeX\ that |\par| is OK. Whenever \TeX\ is
%about to include |\par| as part of an argument, it will abort the current
%macro expansion and report that a ``^{runaway} argument'' has been found.
\ddanger 在实践中,我们总是要犯错误的。%
而且最常见的排版错误就是在宏的参量中落掉一个`|}|'或者多插入一个`|{|'。%
如果在这种情况下 \TeX\ 盲目地遵循规则,就要因为要找到参量的结尾而不得不读入越来越%
多的记号。%
但是象实际使用中如此多参量,只要参量中有一个这样的笔误就无法结束(唉);
因此, \TeX\ 不得不一直读到文件结束,或者(更可能的是)直到记号把计算机内存都塞满为止。%
不论哪种情况,单个的排版失误将导致无法运行,并且用户被迫重新开始。%
因此 \TeX\ 还有另一个规则,用它把这样的错误限制在它所在的段落中:
{\KT{9}记号`\thinspace^|\par|'不允许作为参量的一部分而出现},
除非你明确告诉 \TeX\ 可以使用 |\par|。%
只要 \TeX\ 把 |\par| 作为参量的一部分而包括进来,它就终止当前宏的展开,
并且给出信息说,发现一个``失控的参量''。
%\ddanger If you actually want a control sequence to allow arguments with
%|\par| tokens, you can define it to be a ``long'' macro by saying
%`^|\long|' just before `|\def|'. For example, the |\bold| macro
%defined by
%\begintt
%\long\def\bold#1{{\bf#1}}
%\endtt
%is capable of setting several paragraphs in boldface type. \ (However,
%such a macro is not an especially good way to typeset bold text.
%It would be better to say, e.g.,
%\begintt
%\def\beginbold{\begingroup\bf}
%\def\endbold{\endgroup}
%\endtt
%because this doesn't fill \TeX's memory with a long argument.)
\ddanger 如果你真要定义一个控制系列,其参量允许出现记号 |\par|,
那么在`|\def|'紧前面加上`^|\long|'把它定义为一个``长''宏。%
例如,宏 |\bold| 的定义为
\begintt
\long\def\bold#1{{\bf#1}}
\endtt
它可以把几个段落都设置为 bold 字体。%
(但是,这样的宏并不是排版 bold 文本的特别好的方法。%
更好的是,比如
\begintt
\def\beginbold{\begingroup\bf}
\def\endbold{\endgroup}
\endtt
因为对长的参量,它不会把 \TeX\ 的内存塞满。)
%\ddanger The |\par|-forbidding mechanism doesn't catch all conceivable
%missing-brace errors, however; you might forget the |}| at the end of a
%|\def|, and the same problem would arise. In this case it's harder to
%confine the error, because |\par| is a useful thing in replacement
%texts; we wouldn't want to forbid |\par| there, so \TeX\ has another
%mechanism: When a macro definition is preceded by `^|\outer|', the
%corresponding control sequence will not be allowed to appear in any place
%where tokens are being absorbed at high speed. ^^{forbidden control sequence}
%An |\outer| macro cannot appear in an argument (not even when |\par| is
%allowed), nor can it appear in the parameter text or the replacement text
%of a definition, nor in the ^{preamble} to an alignment, nor in ^{conditional
%text} that is being skipped over. If an |\outer| macro does show up in
%such places, \TeX\ stops what it is doing and reports either a
%``runaway'' situation or an ``^{incomplete}'' conditional. The ^{end of an
%input file} or alignment template ^^{endtemplate}
%is also considered to be |\outer| in this sense; for example, a
%file shouldn't end in the middle of a definition. If you are designing a
%format for others to use, you can help them detect errors before too much
%harm is done, by using |\outer| with all control sequences that should
%appear only at ``quiet times'' within a document. For example, Appendix~B
%defines ^|\proclaim| to be |\outer|, since a user shouldn't be stating a
%theorem as part of a definition or argument or preamble.
\ddanger \1但是,禁用 |\par| 这个方法不能预防所有可能出现的落掉大括号的错误;
如果你在 |\def| 的结尾处落掉了 |}|,也要出同样的问题。%
在这种情况下,更难限制住错误,因为 |\par| 在替换文本中是一个有用的东西;
在这里我们不想禁用 |\par|, 因此, \TeX\ 提供了另一种方法:
当宏定义前面有`^|\outer|'时,相应的控制系列不允许出现在记号被高速读入的任何地方。%
|\outer| 宏不允许出现在参量中(即使允许出现 |\par| 它也不能出现),