大阪大学医学部 Python会

Now is better than never.

LaTeX の展開

2021-03-30(Tue) - Posted by 河村 in 技術ブログ    tag:その他言語

Contents

    TeXの処理動作

    TeXは前からソースコードを認識し、\textbackslash(英字)というカタマリ1 を一つの制御綴(コントロールシークエンス)として処理します。

    \csone\cstwo            \csthree
    

    この場合の制御綴は\csone, \cstwo, \csthreeです(空白は制御綴に使われない)。

    TeXは制御綴を認識した後、前から順番に展開(定義の代入)を行います。 例えば、次の制御綴を用意します。

    • \csoneの定義:one;
    • \cstwoの定義:two;
    • \csthreeの定義:three;

    この場合は、

    \csone\cstwo            \csthree
    \csone\cstwo\csthree
    one;\cstwo\csthree
    one;two;\csthree
    one;two;three;
    

    と展開されます(複数の空白は1個の空白として処理され、制御綴の直後の空白は無視される)。

    展開の制御

    先程の例の通り、TeXは基本的に前から展開を行いますが、時には展開の順序を入れ替えたりしたい場合があります。 そのために、いくつかの命令が存在します:

    • \expandafter。直後の制御綴の展開を一回遅らせる、
    • \edef。制御綴の中身を全て展開して定義、
    • \noexpand\edef中で使用すると、定義の際に展開されない(実行時は展開される)。

    例として、次の制御綴を用意します。

    \def\A#1#2{#1 is #2}
    \def\B{\BB\BB}
    \def\BB{foo}
    \def\C{bar}
    

    それぞれの制御綴の意味は、

    • \A:引数は2個(#1, #2)で、展開すると「#1 is #2」(#1, #2が制御綴なら展開される)
    • \B:展開すると「\BB``\BB」(\BBは展開される)
    • \BB:展開すると「foo」(それ以上展開されない)
    • \C:展開すると「bar」(それ以上展開されない)

    例1

    \A\B\C

    \A\B\C
    % -> \B is \C
    % -> \BB\BB is \C
    % -> foo\BB is \C
    % -> foofoo is \C
    % -> foofoo is bar
    

    1行目で\Aを展開する際の、\Aの引数は\B, \Cです。

    例2

    \expandafter\A\B\C

    \expandafter\A\B\C
    % -> \A\BB\BB\C
    % -> \BB is \BB\C
    % -> foo is \BB\C
    % -> foo is foo\C
    % -> foo is foobar
    

    先ず、\expandafter\Aによって、\Aの展開は抑制され、先に\Bが展開されます。

    例3

    \expandafter\expandafter\A\B\C

    \expandafter\expandafter\A\B\C
    % -> \expandafter\B is \C
    % -> \B is \C
    % -> \BB\BB is \C
    % -> foo\BB is \C
    % -> foofoo is \C
    % -> foofoo is bar
    

    1行目で、先頭の\expandafterは直後の\expandafterを抑制するため、先に\Aが展開されます。 2行目で、\expandafter\B直後は制御綴でないため、特に効果はありません。

    例4

    \expandafter\expandafter\expandafter\A\B\C\expandafterが3連続の場合は次のように、2つ後の制御綴が先ず展開されます。

    \expandafter\expandafter\expandafter\A\B\C
    % -> \expandafter\A\BB\BB\C
    % -> \Afoo\BB\C
    % -> f is oo\BB\C
    % -> f is oofoo\C
    % -> f is oofoobar
    

    3行目で\Aの第1引数はf、第2引数はoです。

    例5

    さらに命令を追加してみます。

    \def\hoge{\B\C}
    \A\hoge % -> error
    \expandafter\A\hoge % -> \A\B\C -> foofoo is bar
    

    \A\hoge\Aの第2引数が存在しないので、エラーとなります。

    例6

    \defの代わりに\edef\hogeを定義します。

    \edef\hoge{\B\C} % -> \def\hoge{foofoobar}
    \A\hoge % -> error
    \expandafter\A\hoge % -> \Afoofoobar -> f is oofoobar
    

    例7

    \edef中で\noexpandをつければ、その直後の制御綴は(定義の際には)展開されません。

    \edef\hoge{\noexpand\B\C} % -> \def\hoge{\Bbar}
    \A\hoge % -> error
    \expandafter\A\hoge % -> \A\Bbar -> \B is bar -> \BB\BB is bar -> foofoo is bar
    

    \A\Bbarで、第1引数は\B、第1引数はbです。

    例8

    別の例。

    \def\twice#1{#1#1}
    \twice\twice hoge % -> error
    \expandafter\twice\twice{ho}ge % -> \twicehohoge -> hhohoge
    \expandafter\twice\twice{{ho}}ge % -> \twice{ho}hoge -> hohohoge
    

    1つ目は無限ループになります。

    脚注

    1. 制御綴に使える文字はcatcodeが11の文字(英字・日本語)。 従って、日本語の混ざった制御綴も作れる。 \relax␣あの場合は、\relaxという制御綴と「あ」という文字として認識されるが、\relaxあの場合は、\relaxあという制御綴として認識され(定義しない限り)エラーを吐く。