這幾個iffalse和fi是什麼意思?
我在學習.dtx文件的寫法,看了doc.pdf還有dtxtut這兩個文檔,但是還是有點暈。我在網上找到了一個示例,但是不是很能理解其中的iffalse和fi的用法,所以請教大家。
代碼在這裡
% iffalse meta-comment
%&<*internal&>
iffalse
%&
%&<*readme&>
Readme
%&
%&<*internal&>
fi
egingroup
def
ameoflatexe{LaTeX2e}
expandafterendgroupifx
ameoflatexefmtnameelse
csname fiendcsname
%&
%&<*install&>
input docstrip.tex
keepsilent
generate{
usedir{tex/latex/jobname}
file{jobname.cls}{from{jobname.dtx}{class}}opreamble
opostamble
file{README}{from{jobname.dtx}{readme}}}
Msg{* Happy TeXing!}
endbatchfile
%&
%&<*internal&>
fi
%&
%&<*driver&>
ProvidesFile{skeleton.dtx}[2015/01/20 v1.0 A Skeleton File]
documentclass{ltxdoc}
egin{document}
DocInput{jobname.dtx}
end{document}
%&
% fi
% CheckSum{0}
% GetFileInfo{jobname.dtx}
% DoNotIndex{ est}
% StopEventually{}
% section{Implementation}
%&<*class&>
% egin{macrocode}
NeedsTeXFormat{LaTeX2e}[1999/12/01]
ProvidesClass{skeleton}[2015/01/20 v1.0 A Skeleton File]
% end{macrocode}
%&
%&endinput
% Finale
endinput
我的理解和疑惑是:
首先第一行的% iffalse與第三十六行的% fi配對;第三行的iffalse與第九行的fi配對。第十二行的ifx我不知道和誰配對,是第十三行的csname fiendcsname嗎?如果是的話,第二十七行的fi怎麼辦?如果不是的話,那第十三行的csname fiendcsname是什麼意思?這個dtx文件會用於釋放文件,也會用於編譯成文檔,所以這些iffalse和fi肯定是在控制某一部分的代碼在某一個過程中不起作用。因為在釋放文件的過程中,% 開頭的行都被砍掉了,所以第一行和第三十六行的配對只能在編譯生成文檔的過程中起作用。但是具體起什麼作用我沒有看懂。第三行的iffalse被%&<*internal&>和%&包著,配對的fi也是一樣。所以在釋放過程中,他們不會被輸出到任何文件中。但是這樣做會不會影響到後續釋放文件的過程呢?我沒有想明白。如果他們也會影響生成文檔的過程,那就和第一行的% iffalse重複了。因此我不知道為什麼要加上這個iffalse。
第十二行的ifx似乎是在判斷編譯使用的方式。
ameoflatexe儲存了LaTeX的名字,egingroup和endgroup與expandafter聯用使得這個宏在進行完ifx判斷之後就失效。但是看這個代碼的意思,好像不管是不是用LaTeX編譯,都什麼也不做。ifx
ameoflatexefmtname與else之間什麼也沒有,else與csname fiendcsname之間也什麼都沒有。而且還有二十七行多出來的fi。完全就暈倒了。請教,這些if的配對情況是什麼樣的呢?以及他們具體起到什麼效果呢?
0
這涉及到 Doc 和 DocStrip 兩個工具。你這份代碼,使用 TeX 編譯的時候,啟動的是 DocStrip 工具,剝離注釋行,生成文件;使用 LaTeX 編譯的時候,DocStrip 工具被抑制,啟動的是 Doc 工具,生成文檔。
這時候需要我們化身「人肉編譯器」,分別來看。
1
使用 TeX 編譯的時候,第一行和第二行都是注釋,忽略。第三行是 iffalse,因此直到第九行的 fi 為止,所有的內容都被忽略。接下來遇到這段代碼。egingroup
def
ameoflatexe{LaTeX2e}
expandafterendgroupifx
ameoflatexefmtnameelse
csname fiendcsname
這裡首先定義了
ameoflatexe 這個宏,儲存了 LaTeX2e。然後使用 expandafter 來在 endgroup 之前展開 ifx。注意因為 endgroup 還沒有展開,所以
ameoflatexe 依然有定義。ifx 比較
ameoflatexe 和 fmtname 的內容是否相同。這裡 fmtname 是當前引擎載入的格式的名字,比如使用 (pdf/Xe)LaTeX 編譯的時候,fmtname 就是 LaTeX2e。
我們現在使用 TeX 編譯,所以 ifx 判斷失敗,else 展開後面的 csname fiendcsname,得到 ifx 結束。然後展開 endgroup,封住
ameoflatexe 的作用範圍。
這樣程序得以繼續運行直到 24 行。16 -- 24 行是安裝處理部分,載入了 DocStrip 工具,開始按照代碼記錄的方式生成文件。遇到 endbatchfile 之後,退出。因此不會遇到第 27 行的 fi,避免了 extra fi 的錯誤。
在執行 DocStrip 的過程中,又要從頭開始讀取 dtx 文件。
第一行的 iffalse 被行首的 % 保護起來,不起作用。第三行的 iffalse 被 %&<*internal&> 和 %& 限定住,不輸出到任何文件。第六行在 %&<*readme&> 和 %& 之間,按照安裝處理的指示,輸出到 README 這個文件。由於沒有指定後綴名,默認輸出到 README.tex 文件里
同理 9 -- 13 行的部分還有第 27 行的 fi 被 %&<*internal&> 和 %& 限定住,不輸出到任何文件。後續部分也有類似分析,不表。
可以看到,在執行 TeX 的時候,27 行的 fi 第一次被 endbatchfile 擋住,第二次被 %&<*internal&> 和 %& 限定,均不起作用,因此不會造成 fi 不匹配的問題。
2
使用 LaTeX 編譯的時候,相同的分析執行到第 12 行。此時我們使用 LaTeX 編譯,因此 ifx 判斷成功。於是從 else 到下一個顯式的 fi 中間的內容全部被忽略,然後展開 endgroup,封住
ameoflatexe 的作用範圍。
documentclass{article}
egin{document}
egingroupdef
ameoflatexe{LaTeX2e}
expandafterendgroupifx
ameoflatexefmtnameelse
csname fiendcsname
csname fiendcsname
csname fiendcsname
csname fiendcsname
csname fiendcsname
fi
end{document}
這段代碼,不管你使用多少次 csname fiendcsname,都不會報錯。
接下來,分析跳到第 31 行,載入了 ltxdoc 這個文檔類。然後到了 33 行的DocInput{jobname.dtx}
DocInput 這個命令實際上是先將 % 忽略,然後載入文件,接著再恢復 % 的定義。相關代碼是:
defMakePercentIgnore{catcode`\%9
elax}
defMakePercentComment{catcode`\%14
elax}
defDocInput#1{MakePercentIgnoreinput{#1}MakePercentComment}
這裡 catcode 9 是可忽略字元;catcode 14 是注釋符號。
於是整個 dtx 文件里的 % 被抹掉,然後插入到 egin{document} 和 end{document} 之間。
這時候第一行的 iffalse 起作用,一直匹配 fi 到第 27 行,恰好跳過了 end{document}。因此實際插入的內容是從 end{document} 之後開始的——去掉了 % 的版本。
之後就是正常的編譯了,只不過有一些命令和環境定義在 Doc 里,會有一些特別的效果。就不詳說了。不過你這裡 42, 47, 48 三行應該是有問題的。他們在這個步驟中會被直接輸出,想來是不對的。
遇到第 50 行的 endinput 之後,DocInput 的讀入工作結束,恢復 % 的定義。然後遇到了 end{document} 後續的內容被全部忽略,輸出文檔。推薦閱讀:
※lyx不能處理中文?
※LaTeX -> dvips -> ps2pdf 編譯不成功是為什麼?
※你在 TeX Stack Exchange 看到過哪些令人驚嘆的回答?
※在為知筆記本(wiz)里用 Latex 打黎曼曲率張量的那個R右下腳為什麼是扭曲的呢?
※有沒有辦法在onenote (Mac)中使用latex命令輸入公式?
TAG:LaTeX |