クワイン、多言語クワイン、マルチクワインには特別なものは何もありません。それらはすべてほとんど自動的に書き込むことができます。
これは、例として、C ++の標準的で、冗長で、エレガントでなく、非効率的なクワインです。ただし、すべての欠点があるため、必要な操作を行うために変更するのは非常に簡単です。
#include <iostream>
#include <string>
#include <cstdlib>
std::string show (const std::string& in) {
std::string res = "\"";
for (std::string::const_iterator it = in.begin(); it < in.end(); ++it) {
switch (*it) {
case '"':
case '\\':
res += '\\';
default:
res += *it;
}
}
res += "\"";
return res;
}
int main (int argc, char* argv[])
{
std::string arr[] = { // beginning ends here
"#include <iostream>",
"#include <string>",
"#include <cstdlib>",
"",
"std::string show (const std::string& in) {",
" std::string res = \"\\\"\";",
" for (std::string::const_iterator it = in.begin(); it < in.end(); ++it) {",
" switch (*it) {",
" case '\"':",
" case '\\\\':",
" res += '\\\\';",
" default:",
" res += *it;",
" }",
" }",
" res += \"\\\"\";",
" return res;",
"}",
"",
"int main (int argc, char* argv[])",
"{",
" std::string arr[] = { // beginning ends here",
"======",
" };",
" int n = argc == 1 ? 0 : std::atoi(argv[1]);",
" if (n == 0) {",
" int i, j;",
" for (i = 0; arr[i] != \"======\"; ++i) std::cout << arr[i] << std::endl;",
" for (j = 0; j < sizeof(arr)/sizeof(arr[0]); ++j) std::cout << show(arr[j]) << ',' << std::endl;",
" for (++i; i < sizeof(arr)/sizeof(arr[0]); ++i) std::cout << arr[i] << std::endl;",
" } else {",
" }",
"}",
};
int n = argc == 1 ? 0 : std::atoi(argv[1]);
if (n == 0) {
int i, j;
for (i = 0; arr[i] != "======"; ++i) std::cout << arr[i] << std::endl;
for (j = 0; j < sizeof(arr)/sizeof(arr[0]); ++j) std::cout << show(arr[j]) << ',' << std::endl;
for (++i; i < sizeof(arr)/sizeof(arr[0]); ++i) std::cout << arr[i] << std::endl;
} else {
}
}
ご覧のとおり、プログラムの中心は、と呼ばれる小さな関数です。この関数show
は、文字列を受け取り、その表現をC++リテラルとして返します。全体的な構造は次のとおりです。文字列配列の開始部分を出力します。パイプされた配列全体を印刷しshow
ます; 配列の最後の部分を印刷します。文字列配列はプログラムのコピーであり、プログラムの途中に挿入されます。"====="
最初の部分は、プログラムからコピーされない特別な文字列によって最後の部分から分離されます(これは、を介して1回だけ印刷されますshow
)。
別のクインを別の言語で印刷するなど、追加のアクションを簡単に挿入できます。そのようなアクションのプレースホルダーを挿入しました。
今では、これを任意のプログラミング言語(たとえば、FORTRAN)に翻訳することは絶対に簡単です。これを実行し、行L1、L2、...、LNで構成されているとします。これらのステートメントをプレースホルダーに挿入します。
std::cout << "L1" << std::endl;
std::cout << "L2" << std::endl;
...
std::cout << "LN" << std::endl;
それに応じて文字列配列を変更します。Voilà、コマンドライン引数に応じて、それ自体を印刷できるクインと、FORTRANのクインがあります。
OK、FORTRANクワインはどうですか?C ++クワインではなく、それ自体を印刷することしかできません。問題ありません。C++クインをFORTRANクインにコピーして戻しましょう。
しかし、C ++クワインには、すでにFORTRANクワイン全体が2回含まれていますか?
FORTRANクワインはすでにそれ自体を印刷できるので、問題ありません。したがって、元のC++行をFORTRANにコピーして戻すだけで済みます。FORTRANをそれ自体の中でもう一度(または2回)複製する必要はありません。
FORTRANを少し変更するだけです。FORTRANクインにC++クインを印刷するように依頼すると、C ++クインと同じように、すべてのC++行とすべてのFORTRAN行を2回印刷する必要があります。次に、C ++クワイン(FORTRANクワインを含む)を元に戻します。Li
std::cout << "Li" << std::endl;
また、これらのFORTRANの変更をC ++に戻す必要があります(つまり、std::cout << "Li" << std::endl;
行を変更します)。そして、変更の波はここで止まります。
これで、コマンドライン引数に応じて、それ自体または相互に出力できる2つのプログラムがあります。
実際にこれをすべて行うことをお勧めします。