マクロツイーター

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

それでも TeX でプログラミングしたい人のための何か (12)

あるいは 〜私の TeX プログラム変換環境〜

前回までの説明で、ようやく「えるたそ」の Lua プログラム(元は (2)の eltaso.luaLua 内変換後は (9)の eltaso4.lua)を TeX のプログラムに変換する準備が整った。ここからは部分に分けて、元の Lua のコードを TeX のコードに変換した結果を示し、必要に応じて説明を行うことにする。(ただし前言の通り、詳細な変換の規則については敢えて省略する。)

1〜4行目: 変数一覧

冒頭の変数の一覧が記してある部分。Lua では単なるコメントだが、言語によっては変数宣言であるかも知れない。

[BEFORE]
-- [変数一覧]
-- 整数: max, j, ires(戻り値)
-- 文字列: dm, dc, dx, di, km, kc, kx, x, sres(戻り値)
-- 配列: alpha_name, digit
[AFTER]
% tceltaso.sty
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{tceltaso}

%% 変数定義
%(整数型)
\newcount\tclt@max
\newcount\tclt@j
\newcount\tclt@ires % 戻り値
%(文字列型)
%\tclt@dm / \tclt@dc / \tclt@dx / \tclt@di
%\tclt@km / \tclt@kc / \tclt@kx
%\tclt@x
%\tclt@sres % 戻り値
%(配列型)
%\tclt@alpha@name/*
%\tclt@digit/*

%% \tclt@nameedef
\def\tclt@nameedef#1{\expandafter\edef\csname#1\endcsname}

一番最初に書いてあるのはパッケージ宣言である。これは無くても特に動作には影響がないのであるが、一種の作法だと思って書いておこう。もしかしたら「パッケージがマトモに見える」というご利益があるかも ;-) ((その昔、現在の LaTeX2e と 旧版の LaTeX2.09 が並存していた頃には、この宣言は「LaTeX2e 専用である」ことを明示する意味を持っていた。(2.09 では \NeedsTeXFormat は未定義なのでエラーになる。)))

なお、pLaTeX(系)専用のパッケージである場合は、\NeedsTeXFormat{pLaTeX2e} という指定にする。こうしておくと、pLaTeX 以外の LaTeX で読み込もうとしたときは「pLaTeX じゃない」というエラーを出してくれる。*1

続いて、整数型の変数(整数レジスタとして表される)を \newcount で定義する。文字列型と配列型の変数はマクロとして表されるので特に宣言の文は要らないが、情報を記しておいた方がいいだろう。大規模なパッケージの場合は、私は敢えて(本当は不要な)初期化文を入れることがある。

%(文字列型)
\let\tclt@dm\@empty  %空文字列で初期化
\let\tclt@dc\@empty
%……

名前空間識別子を tclt としたので、Lua での xxx_yyy という識別子(配列変数や関数名も含む)は TeX では \tclt@xxx@yyy という制御綴になる。

最後に、前回説明した \tclt@nameedef のオマジナイを定義している。

6〜21行目: 配列宣言の初期化
[BEFORE]
j = 0
for _, x in ipairs({
  "ぜっと",
  "えー", "びー", "しー", "でー", "いー", "えふ", "じー",
  "えいち", "あい", "じぇー", "けー", "える", "えむ", "えぬ",
  "おー", "ぴー", "きゅー", "あーる", "えす", "てぃー", "ゆー",
  "ぶい", "だぶりゅー", "えっくす", "わい" }) do
  _G["alpha_name/"..tostring(j)] = x
  j = j + 1
end
j = 0
for _, x in ipairs({
  "", "一", "二", "三", "四", "五", "六", "七", "八", "九" }) do
  _G["digit/"..tostring(j)] = x
  j = j + 1
end
[AFTER]
%% \tclt@alpha@name/* : アルファベットの日本語読みの仮名表記
\tclt@j=0
\@for\tclt@x:=%
  ぜっと,%
  えー,びー,しー,でー,いー,えふ,じー,%
  えいち,あい,じぇー,けー,える,えむ,えぬ,%
  おー,ぴー,きゅー,あーる,えす,てぃー,ゆー,%
  ぶい,だぶりゅー,えっくす,わい%
\do{%
  \tclt@nameedef{tclt@alpha@name/\the\tclt@j}{\tclt@x}%
  \advance\tclt@j 1
}
%% \tclt@digit/* : 漢数字(1〜9)
\tclt@j=0
\@for\tclt@x:=,一,二,三,四,五,六,七,八,九\do{%
  \tclt@nameedef{tclt@digit/\the\tclt@j}{\tclt@x}%
  \advance\tclt@j 1
}

名前参照の変数を用いた式の TeX への変換の方法についてはシリーズ(9)で説明した。ここの場合、右辺が文字列変数 x(→\tclt@x)なので、早速 \tclt@nameedef を用いて展開させることになる。

元のコードの for-each 構文は素直に \@for に置き換えればよい。

23〜39行目: 手続き knumeral()
[BEFORE]
function knumeral(_1)
  split_digit(_1)
  knum_pos(dm, "千"); km = sres
  knum_pos(dc, "百"); kc = sres
  knum_pos(dx, "十"); kx = sres
  sres = km .. kc .. kx .. _G["digit/"..di]
end
function split_digit(_1) -- TeXでは再実装が必要
  dm, dc, dx, di =
  ("%04d"):format(_1):match("^(.)(.)(.)(.)$")
end
function knum_pos(_1, _2)
  if tonumber(_1) == 0 then sres = ""
  elseif tonumber(_1) == 1 then sres = _2
  else sres = _G["digit/".._1] .. _2
  end
end
[AFTER]
%% \tclt@knumeral{<整数n>}
% 整数n(1〜9999)の漢数字表記.
\def\tclt@knumeral#1{%
  \tclt@split@digit{#1}%
  \tclt@knum@pos{\tclt@dm}{千}\let\tclt@km\tclt@sres
  \tclt@knum@pos{\tclt@dc}{百}\let\tclt@kc\tclt@sres
  \tclt@knum@pos{\tclt@dx}{十}\let\tclt@kx\tclt@sres
  \edef\tclt@sres{\tclt@km\tclt@kc\tclt@kx\@nameuse{tclt@digit/\tclt@di}}%
}
\def\tclt@split@digit#1{% TODO:実装しろ
%  dm, dc, dx, di =
%  ("%04d"):format(_1):match("^(.)(.)(.)(.)$")
}
\def\tclt@knum@pos#1#2{%
  \ifnum#1=0 \def\tclt@sres{}%
  \else\ifnum#1=1 \def\tclt@sres{#2}% 
  \else \edef\tclt@sres{\@nameuse{tclt@digit/#1}#2}%
  \fi\fi
}

非常に単純に、手続きの定義をマクロの定義に、手続きの呼出をマクロの実行に置き換える。\tclt@split@digit の実装については後で考えることにしよう。

文字列の代入文の右辺に配列要素がある場合は、単純に \edef 中で \@nameuse を使えばよい。

km = sres のような文字列のコピーの代入文は、定式通りに \edef\tclt@km{\tclt@sres} としてもよいが、上掲のように \let での定義コピーに置き換えることができる。ただし \let が使えるのは文字列の場合に限り、整数変数の k = m のような代入文は \tclt@k=\tclt@m でなければならない。((ここで \let を使うと \tclt@k\tclt@m と同じレジスタを指すことになってしまい失敗する。))

41〜48行目: 手続き eltaso_name()
[BEFORE]
function eltaso_name(_1)
  knumeral(_1)
  remainder(_1, 26)
  sres = sres .. "反田" .. _G["alpha_name/"..tostring(ires)]
end
function remainder(_1, _2) -- TeXでは再実装が必要
  ires = _1 % _2
end
[AFTER]
%% \tclt@eltaso@name{<整数n>}
% 整数n(1〜9999)に対する「えるたそ名」.
\def\tclt@eltaso@name#1{%
  \tclt@knumeral{#1}%
  \tclt@remainder{#1}{26}%
  \edef\tclt@sres{\tclt@sres 反田\@nameuse{tclt@alpha@name/\the\tclt@ires}}%
}
\def\tclt@remainder#1#2{% TODO:実装しろ
%  ires = _1 % _2
}

ここでも \tclt@remainder の実装は後回し。

*1:tceltaso は日本語の文字の出力を含んでいるので pLaTeX 用に該当するのではと思うかも知れないが、単に出力文字に日本語があるだけの場合は、(ファイルの文字コードUTF-8 にしておけば)XeLaTeX や LuaLaTeX でも使える。