Best use of parenthesis

カッコの最高の使い方

受賞者:Michael Ash

引用元:https://www.ioccc.org/2005/mikeash/mikeash.c

審査員・作者による説明:https://www.ioccc.org/2005/mikeash/hint.text

動作

Common Lispで書かれたQuine。

$ clisp mikeash.c | diff -s - mikeash.c
Files - and mikeash.c are identical

C言語としてコンパイルすると、ものすごく制限されたCommon Lispインタプリタ風に動くバイナリになる。 自分自身をCommon Lispとして実行するとQuineになる。

$ gcc -m32 mikeash.c -o mikeash

$ ./mikeash < mikeash.c | diff -s - mikeash.c
Files - and mikeash.c are identical

解説

ポインタを返すライブラリ関数が暗黙的にintを返すものと扱われることを避けるため、-m32が必要。

Common Lispのインタプリタとは言うが、作者自身が認めている通り、いろいろ不完全である。 変数はqの1つしか使えない、出力の最後に必ず"をつける、fで始まる関数はすべてformatになる、など。 チューリング完全かどうかもわからないとのこと。

一応、次のようなコードは動く。

$ echo '(format t "~s" (* (+ 2 2 ) (- 5 (/ 9 3 ))))' | ./mikeash
8"

コードの難読化は、そこまで難しくはないと思う。 Common Lispの変数定義の(defvar q=を、C99のfor文の初期化for(char* q="..."; ...)と重ねてあるのは面白い。

Common Lispで動かすためには#includeを書けなかったとのことだが、現代のCommon Lispでは複数行コメントを使って書けるので修正を添付する。 また、Common Lispの文字列リテラルで"\n"と書くと、当時は\nの2文字の文字列として扱われていたらしい。 現代ではnの1文字の文字列として扱われるように変わっていたので、この点も適当に修正した。

パッチ

パッチをダウンロード