如何将宏 xii.tex 简化为更易读的形式

如何将宏 xii.tex 简化为更易读的形式

我正在阅读一些 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&&#1\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}~`F1F~\let\catcodeP~`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`L13L\def

{\catcode}
{\def}

(不幸的是,\tracingall没有提到有关\catcode和的执行的任何具体内容\def。)

让我们看看用法A''{w}。它扩展为\catcode`'13\def'{w},因此'成为活动字符,并赋予其定义,即'应扩展为w(换位密码之一)!再举一个例子:A??{i*Lm}使?活动并赋予其定义i*Lm,这反过来又扩展为,istRsam m因为*扩展为stRsamL到空格。最终结果是,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

相关内容