上のコードができるまで

ゴルフったところこんな感じになった。ファイルは更新しておいた。

 #include/*
s='''*/<stdio.h>
main(){char*_;/*==;sub _:lvalue{$_}<<s;#';<<s#'''
def printf(a,*b):print a%b,
s
#*/
_=" #include/*%cs='''*/<stdio.h>%cmain(){char*_;/*==;sub _:lvalue{%c_}<<s;#';<<s#'''%cdef printf(a,*b):print a%%b,%cs%c#*/%c_=%c%s%c;printf(_,10,10,36,10,10,10,10,34,_,34,10,10,10,10);%c#/*%cs='''*/%c}//'''#==%c";printf(_,10,10,36,10,10,10,10,34,_,34,10,10,10,10);
#/*
s='''*/
}//'''#==

まぁ Quine 作る方法は色々あるわけですが、メインの処理の部分は全く同じ形にしとかんと Quine にするのは大変だよなーと思ったので、一本化しやすいし短い printf で。以下の形。 Quine 自体の説明は略。

_="...";
printf(_, ..., _, ...);

全ての言語がこの部分を通るわけですが、各言語問題があります。

C
int main(){char*_; って内容を入れないといけない。
Python
printf が存在しないので自分で定義しないといけない。
Perl
変数 _ は SIGIL が無いって怒られるので、代入可能な _ を用意しないといけない。
Ruby
このままで通る。

こういう下準備の部分とかは各言語別のパスに分けないといけません。順に。

 #include/*

とりあえず最初の空白は一応 PHP のため。

で、まず C++ は一番毛色が違う言語なので分離しないといけない。とはいえ複数行コメントがあるので分離しやすい。最初の行で #include として他の言語はコメントにしておきつつ /* で C++メントスタート。

s='''*/<stdio.h>

前半部。 PerlRubyPython で実行。これらの言語には複数行コメントはないので基本的に文字列リテラルで分離する。後で PerlRubyPython をバラす必要があるので、それぞれの言語で別の方法でリテラルに突入しないといけない。色々考えた結果上記の形に。 Python は ''' による複数行文字列リテラル (Python はこれ以外に複数行処理から外す方法無い気がする) で、 Ruby は '' と '*/... っていう文字列が定数文字列の結合でくっついている。 Perl は定数文字列の結合ができないので諦めかけてたんだけど、正規表現 s/// を使うことを思いついた。つまり / のかわりに = にして s=== って形で正規表現リテラルにしている。 s= は右辺値を用意してやれば RubyPython でも問題が無い。

後半部。 C++ がコメントから戻って #include の続き。

main(){char*_;/*==;sub _:lvalue{$_}<<s;#';<<s#'''

まず C++ が下準備を終えて /* でコメントに突入。

次は Perl をコメントから戻す。 ==; はさっきの s= とくっついて、 s=...==; となるので何も変化しない置換になる。 sub _:lvalue{$_} はなんか左辺値になれる関数を Perl は定義できるらしいと今日調べて知った。で、ヒアドキュメント << s; で s だけの行が出るまでコメントアウト。この行の以降の部分を無視するために # も。

次は Ruby が戻ってくる。本当は Python を戻したいんだけど、 ''' とかすると Ruby も戻ってくるので先に小細工しないといけない。で Ruby だけ戻すために ' を一個だけ入れて、特に Ruby はやることないので << s でそのままヒアドキュメント突入。 Perl 同様 # で以降を無視。

Python が ''' でコメントから戻ってきてこの行は終了。

def printf(a,*b):print a%b,
s

Python は printf が無いので適当に定義。ヒアドキュメントの終了を s にしたのは Python のため。 Python は既に s= で s は変数になってるので問題なく s 単体の行を抜けられる。

#*/

他の言語はコメントから出たので、 C++ もコメントから戻す。 # で一旦スクリプト言語達をコメントアウトして、 */ で C++ が戻る。これで次の行は全員集合。

後はまぁ、普通の Quine と C++ は } で閉じなきゃいけない、ってだけの話なので似たようなことをして終了。あえて言うなら # 単体の行は C++ で合法らしいと。

なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h