マクロツイーター

はてダから移行した記事の表示が崩れてますが、そのうちに直せればいいのに(えっ)

某ZR流パラメタトークン思考法

課題

次のTeXコードを実行したときのTeXの動作を、字句解析を中心にして述べよ。

LaTeXフォーマットで\makeatletterの状態のカテゴリコードを仮定する。

\toks@{\def\xx@#1}\the\toks@{!#1}

某ZR氏の解答

表記

  • 制御綴のトークンを“[def]”等で表す。
  • 文字トークンを“‹A›₁₁”等で表す。
  • パラメタトークンを“①”等で表す。

動作の解説

  • \toks@を読み [toks@] と解釈する。\toks@(0番のtoksレジスタ)に対する代入文を開始する。
  • {を読み ‹{›₁ と解釈する。これ以降は代入すべきトークン列の内容であり、展開抑止の状態に入る。
  • \def\xx@#1を読み、[def] [xx@] ‹#›₆ ‹1›₁₂ と解釈する。
  • }を読み ‹}›₂ と解釈する。代入すべきトークン列が確定し、展開抑止が終わる。\tokS@に“[def] [xx@] ‹#›₆ ‹1›₁₂”が代入される。
  • \theを読み、[the] と解釈する。プリミティブ\theの引数を待つ状態になる。
  • \toks@を読み [toks@] と解釈する。\theの展開を行う。\theプリミティブの引数がtoksレジスタなので、そのレジスタの内容の“[def] [xx@] ‹#›₆ ‹1›₁₂”をバッファに吐き出し、以降はここからトークンを読み出す。
  • [def] を読む。\def文を開始し、展開抑止の状態に入る。以降に続く「代入先トークン」「パラメタテキスト」「置換テキスト」を待つ。
  • [xx@] を読む。これが「代入先トークン」である。
  • ‹#›₆ ‹1›₁₂ を読む。パラメタテキストの読取の途中に“‹#›₆ ‹1›₁₂”が現れたので、パラメタトークン“①”に置き換える。
  • (バッファのトークンが尽きたので再びソース文字列から読む。)
  • {を読み ‹{›₁ と解釈する。ここでパラメタテキストが終わり、“①”と確定する。
  • !#1を読み、‹!›₁₂ ‹#›₆ ‹1›₁₂ と解釈する。置換テキストの読取の途中に“‹#›₆ ‹1›₁₂”が現れたので、パラメタトークン“①”に置き換える。
  • }を読み ‹}›₂ と解釈する。ここで置換テキストが終わり、“‹!›₁₂ ①”と確定する。
  • すなわち、以下の引数を以て、\def文が実行される。展開抑止が終わる。`
    • 代入先=[xx@]
    • パラメタテキスト=①
    • 置換テキスト=‹!›₁₂ ①

補足

つまり、某ZRのモデルでは、パラメタトークン(① など)は「パラメタテキスト」や「置換テキスト」のトークン列の内容には現れるが、入力バッファの中には決して現れない。

もしこの後、\xx@?を実行したとすると、[xx@] ‹?›₁₂ の展開結果として、置換テキストの ① を ‹?›₁₂ に置き換えたトークン列である“‹!›₁₂ ‹?›₁₂”がバッファに吐き出される。この場合もパラメタトークン自体はバッファには現れない。

2021年のパズル年賀状

今年の年賀状。

f:id:zrbabbler:20210101105711j:plain

以前に述べたとおり、年賀状にはその年の数に関連した数学パズルを載せるのが通例である1。しかし去年はパズルを作っている時間が8時間しかなかったので2、割と普通の(ある意味で)虫食い算で済ませた。

肝心のパズル問題の部分の文字が小さくで読みづらいが、以下のように書かれている。

以下の条件に従って、割り算の虫食い算を解きなさい。

  • 横に並ぶ一連の数字を全体で一つの整数と考えたとき、それが3の倍数または3のつく数である場合は赤色のマス、そうでない場合は緑色のマスに入れなければならない。

※例えば、□□には3524は入るが、25は入らない。

(問題の図)
f:id:zrbabbler:20210101105808p:plain

一番上にある新年の挨拶はトク・ピシンではない。(何の言語でしょう?)

* * *
(パズル問題についての補足)

この問題は、TeX芸人にとってはお馴染みの「ナベアツ」(3の倍数と3のつく数字でアホになる)が元ネタになっている。条件が少しわかりにくいが、以下のような意味である。

f:id:zrbabbler:20210111021239p:plain
* * *

新年の挨拶の言語はビスラマ語でした。
(※ちなみに、トク・ピシンでの新年の挨拶は“Hepi Nu Yia!”です。)


  1. LaTeXカーネルの仕様・動作変更に自作の文書クラス・パッケージを対応させるのに時間を取られている人が多いためか、年を追うごとに年賀状で数学パズルを見ることが少なくなっているようで感じる。

  2. そのうち本腰を入れて数学パズルを作りたいですね……。

例によって、暮れのご挨拶的な何か

2020年はイロイロとアレな年でしたが、「自分にとっての2020年」を振り返ってみました。

今年は

f:id:zrbabbler:20201231165007g:plain

ゆきだるま☃がいっぱい回る年でした(素敵🙂)

来年は

f:id:zrbabbler:20201231165058g:plain

ゆきだるま☃がもっといっぱい回る年になってほしいですね(素敵🙂)

* * *

ZR「いやー、やっぱり、半日でネタを仕上げるのは無理でしたねー」
*「だったら無理にブログ記事を書く必要ないじゃん!」
ZR「というわけで、来年も当(くだらない)ブログをよろしくお願いします!」

今年も Merry TeXmas! ― \end{texadvent2020}

f:id:zrbabbler:20201122184755g:plain
TeX & LaTeX アドベントカレンダー 2020
*  *  *

アドベントカレンダー完走!

^^`^^;^^`\^^$^^%^^&\!^^;\^^$^^%^^&^^=^^`\!\^^:#1^^;^^=^^`%^^'^^`1~^^`^^"
\!\[{^^2}\!\<{%% --:--:--:--:--:--:--:-- 2 @ 2 @ --:--:--:--:--:--:--:--
\^^#^^3^^.^^!^^-^^%}\!\]{^^3}\^^:?\!\>{\^^%^^.^^$^^#^^3^^.^^!^^-^^%}%**%
\!\={\^^,^^%^^4}\=\?\^^#^^!^^4^^#^^/^^$^^%\=\#\^^:\?`*\?`\^\?`.\?`\*%[#\
\?`/\?`\^\!\|{^^5}\=\@\^^%^^$**%**&\?`\@\?`//*\=\+%+5.//)=\?..{**!};@^^:
\..!^^$//6..!^^.//#..%\=\&\..'//,^^/.."^^!//,\#6\=\%\^^,**#..#///..$**%%
\@\_{\<..,**/..7^^%\[^^#..!\]..%\>}\!\^^!{\?\(\?`+\%\(\)\+\(\@^^.//%%7;)
\+\)\@**.^^%}\=\^^"\**!\=\^^#\..!\!\..${\^^!\**"\..#}\=\..%\..$%.:8:*:8:
\@\({\**$//!**9}\@\){\<//9..%**!\[\>}\!\**'{{\)`/\+\)\@...**%\(\)\+\(\)%
\//$\..%\^^!\..$\+\)\?`\^\//$\^^%\_{\&\!\..:@^^:{%%.(.**$!\\;//:%@>./++.
^^%**,//&..$**&^^/^^&^^#//'..%//&//-**&^^%..&**.//'//$//&//#..&**,**&**!
//'..#..'..#**'//+^^'^^#..'**$//&//!..&**.//&^^$^^&**!//&**,**&**/..&...
**&**%**'//-^^%^^,..'^^%..'**#..&**%^^'`//&**!..&//#**&^^+..&**!^^&^^'%^
**&^^%//'^^+**'//(**&//#//&///**&//,..&../**'//"**"..,**'^^$//&..)..&//+
..'..*.."^^,..'**#..&//#..'^^#..&...^^&/////'//'^^&..-//&..!//&^^...'//-
**%//,^^'..%**'..#..&..%**'^^$**&..)**&**+**'***//&..,**&^^)**&.."..'^^"
^^&^^!^^'**"**'**)^^'^^+**&..$//&//%//&**#..&/////'**"//&..!**'^^$^^&//)
//&..///&...^^'**#^^"**.//'^^$..&//%..'..(**'**$**'..-//%^^,..'`**&//!%/
//&//'^^&**%^^&..#//&../^^&**,//&../..'^^"^^'..+^^&//'**'^^"..&^^%..&^^%
//&//.//"..!**#**)^^#^^%^^"**!**'//"^^&..%..&//$//"**!**#//#..#`**"..!%*
//&^^"//&^^,..&//!//&^^#..&//+^^'..-..%//,^^&..#**&^^///&^^,//&/////'**"
..&//,^^&..%//'..$**'//+//&**&**&^^!**&..#..&**%..'**-**'..+//'//"^^&..%
**&..$//"..!//#**#..#`//"..!**'..)**&^^%**&**,^^&**,..&../..'^^'//"//!%.
..#//'..#`**'**-..%**,**&^^#^^&**/**&^^,..&^^/**'^^"//&//,..&..%..'//$%^
**'**+..&**)..&**...&..+//'**-..'//+**&^^&//&**!//&**#^^&**%**"..!^^#..#
..#`//"..!//&**"^^&**,^^&//!**&^^#..&**+//'..-//%//,**&...//&//%//'^^'%/
^^&^^#//&**/**&..-^^&..-^^&..!**&**.**&..$.."..*//'//+//%**,^^&^^&^^%..$
..'**-**'//+..%^^,^^&^^&..&^^/**&^^.**'//$**'//#//&^^)//'^^*..&//%^^'**+
**#^^!**#..$..'**-^^'**+**#`^^'..-**%**,//&..&..&///..&^^.//'^^$//&**&%*
**&^^!**&**-..&//)^^&**,**'..)//'..+**'`**&//(**'**&^^'//-**%//,//&^^&%/
^^&../**&**.**'//$**'^^#..&..%..'**"..&**)**&..%**'..#//'^^+//&**"..&..#
^^'^^-//%..,..'**#..&//%..&//,//&//%..&..#**'..$**&..&//&../..&**.//'//$
**'//-^^%^^,^^&**"^^&//%**&^^'**&^^)^^&^^.^^'**+//&**$//&../..&//#**'^^%
^^&//-^^&..%//&//.//'..$**'//-..%//,^^&**"^^&^^%..&//'**&..)^^&^^.^^'//+
..'//$..&//)..&**+//'*****'`//&..)^^&**#^^'**$//'..%**'^^"//&**%..'^^-%.
..%**,^^'**%**'**#//&**%//&**!**'..#..&//"^^&^^/**'**%**&//.//&..$**&..)
**&^^.^^&//'//&//"..&**/..'..(**"..(//#`.."..,^^#`//"^^)//'.."**&//%%^^)
**&^^#**'^^$**&..!//&^^.**&..'//&..,..&^^%//"^^(**#^^!..#`**"^^,^^#**!%.
**#`//"^^)//#..+^^%**,..&..&^^&..)//&..,//&^^,**%..+**&**&..&^^!//&//#%*
//&//%..%..-.."**(**#^^%.."//,^^#..%^^"**)**&//#^^&//)**'.."**&//#..&//,
^^&^^%//%..+//'.."..&^^!**&..$//&**)..'//%..'//#//#//-//#^^#.."...//#..%
..%..-**#**+**%^^,**'`..&..!//'^^$**&**(^^%^^+..&//)^^&//.^^&//+//"^^,%.
^^&../**'//%..'//$..#**-^^#..$^^#`**"**,..&**)//&//.**#**-//#**!//#^^$%^
^^#`.."^^,**&..$//&**%^^&//#**&///**'^^"^^&**!//'**$**&//%.."..,//&^^$%^
..&^^%**&^^#..&..///'**"**&..!..'**$**&**)^^&**/**&//...#..-//'**+..'..$
..&^^%..'..(**'^^$//"`..&//!**&..,^^&..///&^^...&**'**"`//'`//&**!%//(**
^^'^^$**&..(//"..,//'**$..&..%..'//(//'..$..#..-..'**+//'**,//%**,^^&**&
^^%^^$//'**,..%**#..$//%^^$..%**"`//%//)^^$..///%..%^^"`..$^^...$^^%%//-
//%^^(//%^^$.."`**%//)//$//%//$^^!..%..".."//!..'..-^^'..-**%**-^^"//(%*
^^#^^#**"//,//#^^&.."//)//'//$^^&**///"//(..#..'^^"//,..#//&//"^^)//#**+
//%^^,^^&**&^^&///**'**"//&**%^^&//!//&..#^^&..(^^%//,^^'**(**"`//&..)%/
**&//...'..+^^#^^#//"**.//#..'**"**,**#//&..".....#..#..'..-//'..+^^%//,
^^&^^.//&^^/**&..$**&^^%//%//+..'**$..&^^%//'^^(**'^^$..#..-^^&**)^^&^^.
//&//+..%^^-**&//!//'^^$**"**(..%//,^^'//(**"^^,//#..$.."^^.//#^^%^^"^^)
..'..+**%**,//'**#^^&^^#**'//#//&**.//&^^/..'^^'**&^^-**&//!**&.....%//+
//'//#..&**#..&^^!..&**,//&**%..#..-^^#//&**"//,**&.."**&**///&//$**'//)
^^"//,^^&//"..'..%..'..$^^'//$^^&..///&**.^^'**#**#..-^^&^^)//&//...&//+
//"^^,//&..-^^'//%^^&**&..&**&//&**,^^&//%**'^^"**#**-^^&**)**&^^.^^&..+
^^%//-..'^^-^^#..+**'..-..#^^+//%//,..&..%//&...**&..$**'^^+**'^^$..&**)
//&**+..'^^*//'`^^&**)..&//#..'//$..'**%^^'^^"^^&^^%..'//-**%//,//&**%%/
..&...^^&**$^^'**+..&**$//&../..&^^#//'^^%..&..-..&**%..&//.^^'..$**'//-
}}\//:*}\^^:$}\..'\(`../\+\(\?`\{\%`,=\(\+\(\?`\&\%`.=\(\+\(\?`\&\%`;=\(
\_{\@\^^!{,..$//&\|...**%\]^^#**!,..%**(^^%;}\@\^^"{\]**#**!^^..**/..+%)
//%^^.\]}\@\..%{**%;,..!^^.^^$//!**&.^^%\[}}{\<\**%\>\=\<\+\=\%%% __ __ 
\+\&\@\^^:@^^!{\&\=\%\<}}\**:@..!\<\^^%\>\=\%\.."\>\+\&\@%.^../%%  / |_>
\..:..:..$../{\<\.."\>{\<\..!\>{\..:@..:}}\#?}\#;}\^^:^^:^^$^^/%% /_ | \

(↑pdflatexでコンパイル)

というわけで、9回目の開催となる TeX & LaTeX Advent Calendar 2020 も、素敵なTeXネタを途絶えさせることなく例によって無事にクリスマスの日を迎えられました。今年の参加者は全部で19名、うち5名が初参加でした。参加者の皆様に心からの感謝を例によって捧げたいと思います。

今年の重点テーマは「このパッケージもスゴイ!」でした。改めて見返すと、テーマに沿った記事が割と多く、たくさんのパッケージが紹介されました。その一覧をあげておきます。

  • bxpdfver
  • fewerfloatpages
  • hmtrump
  • jlreq-deluxe
  • manfnt
  • mathabx
  • mleftright
  • pdfx
  • pxchfon
  • pxjodel
  • qrcode
  • scsnowman
  • scsnowman+
  • tcsushihead
  • tegaki
  • tikzducks

TeX & LaTeX Advent Calendar 2020 を楽しんでくれた皆さんに、

例によってありがとう!

そして

*  *  *

*「やっぱり……」
ZR「例によって……」
*「………………」

徹底検証! SATySFiはLaTeXの代わりになるか

これは「SATySFi Advent Caleandar 2020」の22日目の記事です。
(21日目は bd_gfngfn さん、23日目は amutake さん です。)

時の経つのは早いもので、SATySFiもその正式公開1からもう2年以上も経っています。この間にSATySFiを取り巻くエコシステム(例えばパッケージマネージャであるSatyrographosなど)も徐々にではありますが整えられつつある状況です。

今の状況に至ったところで、改めて「SATySFiの元来の目的」について思い返してみましょう。

そう、SATySFiは「LaTeXを置き換える」ことを目的にして開発されたのでした。

現状のSATySFiは「LaTeXを置き換える存在」になっているのでしょうか?

そもそもLaTeXとは何だったのか

この疑問に答えるには、まずLaTeXの存在意義」という究極の問いについて考察する必要があります。LaTeX(拡張エンジンを含む)を使うと数式や日本語や英語などを高い組版品質をもって出力できるわけですが、LaTeXは究極的に何のためにあるのでしょうか?

極めて本質的な答えですね。しかし最近は状況が少し変わっています。

このように、最近では単に☃を出力するだけでは不十分で、☃を回転させることまで要求されるようになっています。

まとめると、LaTeXの目的は究極的には「☃を回すこと」であると結論づけて間違いないでしょう2

SATySFiで☃を回せそうにない話

LaTeXの目的についての本質的な理解が得られたところで、いよいよSATySFiについて考えてみます。果たしてSATySFiで「☃を回すこと」は可能でしょうか。

LaTeXでは「PDF上でのアニメーション」を実現するためのanimateというパッケージがあり、また、この機能を利用して「テキストを回転させる」ためのtcfaspinというパッケージが作られています。tcfaspinを使うことで簡単に☃を回転できます。

一方で、SATySFiには現状で「PDF上でのアニメーション」を実現するための機能が欠けています。このためSATySFi上でfcfaspinに相当するパッケージを実装することは、残念ながら現状では不可能です。やはり、SATySFiはLaTeXを置き換える存在にはなりえないのでしょうか。

それでもSATySFiで☃を回したい話

一見して絶望的な状況ですが、ここでまた最近のLaTeXのトレンドを見てみると、希望が見えてきます。

すなわち、LaTeXの主戦場が最近ではPDF文書からGIFアニメ画像に移行しつつあるといっても過言ではないでしょう3

とはいっても、LaTeXエンジンにGIFアニメ画像を出力する機能はありません。「LaTeXでGIF画像をつくる」にはtcspingifという補助のスクリプトを利用する必要があります。

このtcspingifは「普通の(静止した)複数のPDF画像からGIFアニメ画像に変換する」という処理を行うものです。そのことを考えると、SATySFiについても可能性が見えてきます。tcspingifをSATySFiに対応させればよさそうです。

tcspingifで「TeX以外」する話

というわけで、tcspingifを少し改修してみました。

今まで、エンジン(-eオプション)にはLaTeXのコマンドを指定することのみを想定していましたが、ここで任意のコマンドを指定することにします。この場合、オプションの指定の方式がLaTeX用のものだと不便なので、もう少し汎用的な呼出形式を--interface=envで選択できるようにしました。

従来(既定値の--interface=latexを指定した時)は「nフレーム中のmフレーム目」のPDF画像を生成するのに特定の呼出形式でLaTeXのコマンドを起動していた(参考)のですが、--interface=envを指定すると代わりに以下のコマンド行が実行されるようになります。

<コマンド名> <入力ファイル> <一時出力ファイル>
  • <コマンド名>-eオプションの値。
  • <入力ファイル>はtcspingifに与えた入力ファイル名。
  • <一時出力ファイル>はこのコマンドが出力すべきPDF画像のファイル名。(実際のtcspingifの実行中には自動生成のファイル名が指定される。)
  • 以下の環境変数の値が設定される:
    • FASTOPTICKS:上の説明中の「m」の値。
    • FAALLTICKS:上の説明中の「n」の値。

すなわち、上記の規約を満たすプログラムを作成して、そのコマンド名を-eに指定すればいいわけです。

tcspingifでSATySFiする話

tcspingifの新機能に基づいて、「SATySFIでフレーム画像を生成する」仕組をつくってみます。次のような仕様にします。

  • 入力ファイルは「SATySFiのパッケージファイル(*.satyh)」とする。
  • パッケージの中で以下の函数frameを定義する必要がある。
    • frame: int → int → document
      framem n は出力したいGIFアニメ画像の「​n フレーム中の m フレーム目」の画像を表す文書。

この仕様とtcspingifの仕様を繋ぐためのシェルスクリプトを用意します。

[tcsg-satysfi]
#!/bin/bash
set -eu

if [[ ! ( $# == 2 && -f $1 ) ]]; then
  exit 1
fi
stop=$((${FASTOPTICKS}))
all=$((${FAALLTICKS}))
ibase=${1%.satyh}
obase=${2%.pdf}
if [[ ! ( 0 -le $stop && $stop -lt $all &&\
    $1 != $ibase && $2 != $obase ) ]]; then
  exit 1
fi

cat <<EOT >$obase.saty
@import: $ibase
frame $stop $all
EOT
${SATYSFI:-satysfi} $obase.saty

if [[ ! -f $2 ]]; then
  exit 1
fi
rm $obase.saty
  • tcsg-satysfi(Gist/zr-tex8r)
    ※ファイル名をtcsg-satysfi.shtcsg-satysfiに変更すべき。

SATySFiでとにかく☃を回す話

これで準備は整ったので、いよいよ☃を回すことにしましょう。必要なのは、「☃を回す」ためのパッケージファイルを作ることです。そこで、次のようなframe函数を定義するscframeパッケージを実装します。

  • framem n」は時計回りに (​m​/​n​) 回転分だけ傾いた☃の絵を中央に配置した文書を作る。

この仕様は現在のSATySFiで十分に実装可能です。

新版のtcspingifとtcsg-satysfiを実行可能にした上で、scframe.satyhを置いたディレクトリで以下のコマンドを実行しましょう!

tcspingif -e tcsg-satysfi --interface=env -t 32 -b 2 scframe.satyh

次のように端末に表示された上で、結果のGIFアニメ画像ファイルscframe.gifが出力されました。

$ tcspingif -e tcsg-satysfi --interface=env -t 32 -b 2 scframe.satyh
tcspingif: convert: scframe.satyh -> scframe.gif
tcspingif: parameters: density=72; ticks=32
tcspingif: generate frame: 0
tcspingif: generate frame: 1
tcspingif: generate frame: 2
……(略)……
tcspingif: generate frame: 31
tcspingif: generate gif: scframe.gif

scframe.gifを表示させてみると……。

f:id:zrbabbler:20201220013805g:plain
回転する☃(素敵😊)

SATySFiで☃を回せました!

まとめ

やっぱり「回転する☃」はトッテモ素敵😊


  1. 2017年度の未踏事業成果報告会があった2018年2月11日を正式公開の日と見なすことにする。

  2. 異論については地中深くに10万年くらい埋めておくことにしましょう。

  3. 異論については地中深くに10万年くらい埋めておくことにしましょう。

例によってアドベントがはじまった ― \begin{texadvent2020}

f:id:zrbabbler:20201122184755g:plain
TeX & LaTeX アドベントカレンダー 2020

TeX界における年末の恒例イベントとなったような気もするアドベントカレンダーが今年も始まりました。

重点テーマ

今年の重点テーマはコレです。

このパッケージもスゴイ!

スゴイLaTeXパッケージ、いっぱいありますね。その中には、スゴイけどあまり知られていないものもあるでしょう。「このパッケージはもっと普及すべきだ」と思うパッケージを紹介してしまいましょう!

※例によって、重点テーマは「必須」ではありません。あらゆるTeXネタを歓迎しております。

で、初日のネタは

こちらになります。

まだ参加できます!

TeX & LaTeX Advent Calendar 2020(#texadvent2020)は

まだまだ参加者募集中です。

LaTeXなネタ、TeX言語なネタ、アレなネタ、アレレなネタ、アレアレなネタ、ア~レ~なネタ、アレッアレなネタ、超絶アレなネタ、その他ナントカカントカ、お持ちの方はぜひぜひ、

ご参加おねがいします!

いつの間にかもう空きが残りわずかとなっています。登録はお早めに!