![如何将宏 xii.tex 简化为更易读的形式](https://linux22.com/image/265392/%E5%A6%82%E4%BD%95%E5%B0%86%E5%AE%8F%20xii.tex%20%E7%AE%80%E5%8C%96%E4%B8%BA%E6%9B%B4%E6%98%93%E8%AF%BB%E7%9A%84%E5%BD%A2%E5%BC%8F.png)
我正在阅读一些 TeX 指南,从中找到了以下来源:
\let~\catcode~`76~`A13~`F1~`j00~`P2jdefA71F~`7113jdefPALLF
PA''FwPA;;FPAZZFLaLPA//71F71iPAHHFLPAzzFenPASSFthP;A$$FevP
A@@FfPARR717273F737271P;ADDFRgniPAWW71FPATTFvePA**FstRsamP
AGGFRruoPAqq71.72.F717271PAYY7172F727171PA??Fi*LmPA&&71jfi
Fjfi71PAVVFjbigskipRPWGAUU71727374 75,76Fjpar71727375Djifx
:76jelse&U76jfiPLAKK7172F71l7271PAXX71FVLnOSeL71SLRyadR@oL
RrhC?yLRurtKFeLPFovPgaTLtReRomL;PABB71 72,73:Fjif.73.jelse
B73:jfiXF71PU71 72,73:PWs;AMM71F71diPAJJFRdriPAQQFRsreLPAI
I71Fo71dPA!!FRgiePBt'el@ lTLqdrYmu.Q.,Ke;vz vzLqpip.Q.,tz;
;Lql.IrsZ.eap,qn.i. i.eLlMaesLdRcna,;!;h htLqm.MRasZ.ilk,%
s$;z zLqs'.ansZ.Ymi,/sx ;LYegseZRyal,@i;@ TLRlogdLrDsW,@;G
LcYlaDLbJsW,SWXJW ree @rzchLhzsW,;WERcesInW qt.'oL.Rtrul;e
doTsW,Wk;Rri@stW aHAHHFndZPpqar.tridgeLinZpe.LtYer.W,:jbye
代码前面的文本如下:
TeX 是一种宏语言,现有命令的含义可以随时更改,也可以随时定义新命令 [Knu84]。也许最极端的例子是 David Carlisle 的 xii.tex TeX 代码,可从以下网址获取http://mirrors.ctan.org/macros/plain/contrib/xii/xii.tex:
现在我的问题是,如何简化这个所谓的宏的极端示例,以便 TeX/LaTeX 初学者能够阅读?
我已经通过 TeX 运行了代码,我非常惊讶地看到结果!
我还有一个基本问题:
所有TeX
命令都可以从任何文件使用吗LaTeX
?
编辑
随着回答从亨德里克-沃格特和相关答案从约瑟夫·赖特,我正在尝试理解混淆的代码。
在开头添加代码后对其进行 TeXifying\traceall
也许会提供有用的信息,但对我来说仍然是一个很大的障碍,例如:
A71->~`7113\def
71<-L
{\catcode}
{\def}
我觉得这有点像高炉。不太清楚,但我仍然能从中得到一些线索,了解幕后发生了什么。有人能帮我解释一下前面的代码块是什么意思吗?
答案1
简短的回答
该代码中实际上有三个层次的混淆:首先,使用一些巧妙的递归宏将文本压缩为几行。其次,某种代换和转置密码是通过相当简单的宏来实现的,例如\defR#1#2#3{#3#2#1}
(其中R
是活动字符)。第三级是使用类别代码来避免可理解的 TeX 特定字符,例如{
、}
和。#
\
更多解释
十多年前我看到过这个 TeX 文件,当时我想嗯?所以我试着一步一步地把它拆开。在这个过程中,我学到了很多关于 TeX 宏语言的知识,也学到了类别代码。首先,我只会发布我采取的最初步骤。(我的电脑上还有这些文件,这个文件名为hae.1
,“hae”是德语,意思是“嗯?”)
\let~\catcode ~`76 ~`A13 ~`F1 ~`j00 ~`P2
\defA#1{~`#113\def}
ALL{
}
A''{w} A;;{} AZZ{LaL} A//#1{#1i} AHH{L}
Azz{en} ASS{th}; A$${ev} A@@{f}
ARR#1#2#3{#3#2#1};
ADD{Rgni} AWW#1{} ATT{ve} A**{stRsam} AGG{Rruo}
Aqq#1.#2.{#1#2#1} AYY#1#2{#2#1#1}
A??{i*Lm} A&\fi{\fi#1} AVV{\bigskipR}WG
AUU#1#2#3#4 #5,#6{\par#1#2#3#5D\ifx:#6\else&U#6\fi}L
AKK#1#2{#1l#2#1}
AXX#1{VLnOSeL#1SLRyadR@oL RrhC?yLRurtK{eL}{ov}gaTLtReRomL;}
ABB#1 #2,#3:{\if.#3.\else B#3:\fiX{#1}U#1 #2,#3:}Ws;
AMM#1{#1di} AJJ{Rdri} AQQ{RsreL} AII#1{o#1d} A!!{Rgie}
Bt'el@ lTLqdrYmu.Q.,Ke;vz vzLqpip.Q.,tz;
;Lql.IrsZ.eap,qn.i. i.eLlMaesLdRcna,;!;h htLqm.MRasZ.ilk,%
s$;z zLqs'.ansZ.Ymi,/sx ;LYegseZRyal,@i;@ TLRlogdLrDsW,@;G
LcYlaDLbJsW,SWXJW ree @rzchLhzsW,;WERcesInW qt.'oL.Rtrul;e
doTsW,Wk;Rri@stW aHAHH{ndZ}pqar.tridgeLinZpe.LtYer.W,:\bye
你看,我在整个过程中都用 替换了 和。F
为什么?给出字符 类别代码 1(因为活动字符是),而 TeX 会将此类字符理解为左括号。同样,给出的类别代码为 2 ,因此它充当右括号。{
P
}
~`F1
F
~
\let
\catcode
P
~`P2
接下来要理解的是~`76
和~`j00
。 第一个 使其7
表现得像宏参数字符#
(类别代码 6),第二个 使其j
表现得像控制序列字符\
(类别代码 0),因此我在整个过程中都7
用#
和j
替换了\
。 这已经大大增强了可读性。 此外,我添加了一些空格和换行符,这更有帮助。
现在的关键是要理解它的A
作用。由于~`A13
,这是一个“活动字符”(类别代码 13),因此它的行为类似于控制序列。那么定义是什么\defA#1{~`#113\def}
意思呢?A
接受一个参数#1
。然后~
充当\catcode
,因此A
给出它的参数类别代码 13,然后它发出一个额外的\def
。
那么这与你得到的输出如何匹配\tracingall
?第一行
A71->~`7113\def
表示以下内容:在左边,->
您会看到活动字符A
接受一个参数#1
(回想一下7
充当#
);在右边,->
您会看到相应的扩展。现在第二行
71<-L
表示#1
应该用 替换L
,因此扩展为~`L13\def
。现在~
变成\let
了,因此接下来执行\catcode
类别代码分配(生成活动字符);然后执行 。这是您在接下来的两行中看到的内容:\catcode`L13
L
\def
{\catcode}
{\def}
(不幸的是,\tracingall
没有提到有关\catcode
和的执行的任何具体内容\def
。)
让我们看看用法A''{w}
。它扩展为\catcode`'13\def'{w}
,因此'
成为活动字符,并赋予其定义,即'
应扩展为w
(换位密码之一)!再举一个例子:A??{i*Lm}
使?
活动并赋予其定义i*Lm
,这反过来又扩展为,istRsam m
因为*
扩展为stRsam
和L
到空格。最终结果是,istmas m
因为R
充当换位密码,如一开始提到的。现在我们能够理解RrhC?y
代码中的小片段——它扩展为Christmas my
!
一个挑战
如果您删除所有密码和 catcode 业务,那么您只需要一些递归宏就可以相当有效地表示文本。有人能用少于 479 个字符做到这一点吗?
\let~\def~\U#1,#2:{\par#1ing \if.#2.\else\U#2:\fi}~\,{\def\,{and
}}~\;#1~#2 #3,#4:{\if.#4.\else\;#4:\fi\bigskip On the #1#2th day of
Christmas my true love gave to me\U#1#3,#4:}~~#1 {}\;twel~f ve drummers
drumm,eleven~ \ pipers pip,ten~ \ lords a leap,nin~ e ladies danc,eigh~
t maids a milk,seven~ \ swans a swimm,six~ \ geese a lay,fi~f ve gold
rings~,four~ \ calling birds~,th~ird\ ~ ree french hens~,~second\ ~ two
turtle doves~,~first\ ~ \,a partridge in a pear tree.~,:\bye
答案2
我认为它实际上已经尽可能简单了。它有两个\
,我承认,这相当复杂。我确实尝试过简化它,以便只有一个反斜杠,或者更好的是没有反斜杠,但我认为这是不可能的。
答案3
以下是我发现的一个简化方法https://bitbucket.org/ambrevar/xii.tex/overview作者:Pierre Neidhardt:
\def\endverse{}
\def\verse#1 #2,#3:{\if.#3.\par #2{}\else\par#2\verse#3:\fi}
\def\day#1{\bigskip On the #1 day of Christmas my true love gave to me}
\def\gen#1 #2,#3:{\if.#3.\else \gen#3:\fi\day{#1}\verse#1 #2,#3:}
\gen
twelfth twelve drummers drumming,%
eleven eleven pipers piping,%
tenth ten lords a leaping,%
ninth nine ladies dancing,%
eighth eight maids a milk,%
seventh seven swans a swimm,%
sixth six geese a lay,%
fifth five gold rings,%
fourth fourr calling birds,%
third three french hens,%
second two turtle doves,%
first \endverse\def\endverse{and }a partridge in a pear tree.,:
\bye