Вот тот, который я написал, который использует putchar
вместо printf
; таким образом, он должен обрабатывать все свои собственные escape-коды. Но он переносим на 100% во всех наборах символов исполнения C.
Вы должны увидеть, что в текстовом представлении есть шов , который отражает шов в самом тексте программы, где он меняется с работы в начале на работу в конце. Хитрость при написании Quine заключается в преодолении этого «горба», когда вы переключаетесь на копание своего пути из дыры! Ваши параметры ограничены текстовым представлением и выводом языка объекты.
#include <stdio.h>
void with(char *s) {
for (; *s; s++) switch (*s) {
case '\n': putchar('\\'); putchar('n'); break;
case '\\': putchar('\\'); putchar('\\'); break;
case '\"': putchar('\\'); putchar('\"'); break;
default: putchar(*s);
}
}
void out(char *s) { for (; *s; s++) putchar(*s); }
int main() {
char *a[] = {
"#include <stdio.h>\n\n",
"void with(char *s) {\n",
" for (; *s; s++) switch (*s) {\n",
" case '\\",
"n': putchar('\\\\'); putchar('n'); break;\n",
" case '\\\\': putchar('\\\\'); putchar('\\\\'); break;\n",
" case '\\\"': putchar('\\\\'); putchar('\\\"'); break;\n",
" default: putchar(*s);\n",
" }\n}\n",
"void out(char *s) { for (; *s; s++) putchar(*s); }\n",
"int main() {\n",
" char *a[] = {\n",
NULL }, *b[] = {
"NULL }, **p;\n",
" for (p = a; *p; p++) out(*p);\n",
" for (p = a; *p; p++) {\n",
" putchar('\\\"');\n",
" with(*p);\n",
" putchar('\\\"'); putchar(','); putchar('\\",
"n');\n",
" }\n",
" out(\"NULL }, *b[] = {\\",
"n\");\n",
" for (p = b; *p; p++) {\n",
" putchar('\\\"');\n",
" with(*p);\n",
" putchar('\\\"'); putchar(','); putchar('\\",
"n');\n",
" }\n",
" for (p = b; *p; p++) out(*p);\n",
" return 0;\n",
"}\n",
NULL }, **p;
for (p = a; *p; p++) out(*p);
for (p = a; *p; p++) {
putchar('\"');
with(*p);
putchar('\"'); putchar(','); putchar('\n');
}
out("NULL }, *b[] = {\n");
for (p = b; *p; p++) {
putchar('\"');
with(*p);
putchar('\"'); putchar(','); putchar('\n');
}
for (p = b; *p; p++) out(*p);
return 0;
}
Обычный трюк заключается в том, чтобы запустить квинну, написав программу для чтения текстового файла и вывода массива чисел. Затем вы модифицируете его для использования статического массива и запускаете первую программу для новой программы (статический массив), создавая массив чисел, который представляет программу. Вставьте это в статический массив, запустите его снова, пока он не успокоится, и вы получите квиню. Но , он привязан к определенному набору символов (== не на 100% переносимо). Подобная выше программа (а не классический printf hack) будет работать одинаково на ASCII или EBCDIC (классический printf hack не выполняется в EBCDIC, поскольку содержит жестко закодированный ASCII).
редактирование:
Читая вопрос снова, внимательно (наконец), кажется, что вы на самом деле ищете больше философии, а не техники. Хитрость, которая позволяет вам выйти из бесконечного регресса, - это двухполосный . Вы должны получить и закодированную программу, и расширенную программу из одних и тех же данных: используя одни и те же данные двумя способами. Таким образом, эти данные описывают только часть программы, окружающую ее будущее проявление, frame . Изображение в этом кадре является прямой копией оригинала.
Вот так вы бы естественным образом создавали рекурсивный рисунок вручную: телевизор из телевизора. В какой-то момент вы устаете и просто рисуете блики на экране, потому что рекурсия уже достаточно установлена.
редактирование:
Я ищу отличное объяснение того, почему Куайны возможны.
«Возможность» Куайна уходит в глубины математических революций 19 и 20 веков. «Классическая» куина В. В. Куайна - это последовательность слов (IIRC)
возвращает ложь при добавлении к себе
, что является парадоксом, сродни просьбе Давида о чем-то, что «делает меня счастливым, когда грустно, и делает меня грустным, когда счастлив», на что отвечает медальон с надписью с обеих сторон: «это тоже пройдет».
Тот же самый узел был исследован пионерами современной математической логики, такими как Фреге, Рассел и Уайтхед, Лукасевич, и, конечно, наши ребята Тьюринг, Черч и Тью. Уловка, которая позволяет транспонировать Quine из области игры слов в программную демонстрацию (раскручивая часть paradox по пути), была методом Гёделя для кодирования самих арифметических операций. что касается чисел, то все математическое выражение может быть закодировано в одно (огромное) целое число. В частности, математическая функция, которая выполняет декодирование этого представления, может быть выражена в той же (числовой) форме. Это число (функция, закодированная по Гёделю) равно и коду, и к данным.
Это степенное трио (код, представление, данные) может быть перенесено в различные представления. Выбирая другое представление (или цепочку , например: bytes-> ASCII-> hexadecimal-> integer), изменяет поведение кода, которое изменяет внешний вид данных.