Прочитал тут статейку на хабре про квайны: http://habrahabr.ru/post/188378/
Решил размяться — написать свой квайн.
Для тех, кто не в курсе. Квайн — это программа, которая пишет саму себя. Ну или более сложный случай: пишет другую программу на другом языке, которая тоже запускается и пишет ещё какую-то программу. И так далее. В итоге можно когда-то вернуться к исходному коду.
Первым делом я осилил свой квайн на C++. Он простой.
#include <stdio.h>
int main() {
char data [] = "#include <stdio.h> %c int main() { char data [] = %c%s%c; printf(data, 10, 34, data, 34); return 0;}";
printf(data, 10, 34, data, 34);
return 0;
}
Символы 10 и 34 — это перевод строки и двойная кавычка соответственно. Понадобилось вставить в прямом виде, чтобы при многократных запусках экранирование не сползало.
Затем я решил добавить немного питона. Пользуясь статьёй на хабре.
#include <stdio.h>
void p(char * pdata, char * s) {
printf(pdata, 34, s, 34);
}
int main() {
char pdata [] = "print(%c%s%c)";
char data [] = "#include <stdio.h> %c void p(char * pdata, char *s) { printf(pdata, 34, s, 34); } int main() { char pdata [] = %c%s%c; char data [] = %c%s%c; printf(data, 10, 34, pdata, 34, 34, data, 34); return 0;}";
printf(data, 10, 34, pdata, 34, 34, data, 34);
return 0;
}
Как я понял после запуска, я совсем забыл про питон %) И это тоже оказался просто C++→C++-квайнчик.
После долгих и мучительных десятиминутных размышлений я выкинул метод p()
, который генерирует питонокод, и влепил кусочки кода прямо в main.
Получилось так:
#include <stdio.h>
int main() {
char ps [] = {92, 110, 0}; // %s
char pc [] = {92, 99, 0}; // %c
char k [] = {34, 0}; // "
char pdata [] = "print(%c%s%c)";
char data [] = "#include <stdio.h> %s int main() { char ps [] = {92, 110, 0}; char pc [] = {92, 99, 0}; char k [] = {34, 0}; char pdata [] = %s%s%s; char data [] = %s%s%s; char ndata[1000]; sprintf(ndata, data, ps, k, pdata, k, k, data, k); printf(pdata, 39, ndata, 39); return 0;}";
char ndata [1000];
sprintf(ndata, data, ps, k, pdata, k, k, data, k);
printf(pdata, 39, ndata, 39);
return 0;
}
Быдлокод, ага) Но работает.
Генерируемый этим кодом питонокод выглядит наипростейшим образом — печатает эту самую программу.
print('#include <stdio.h> \n int main() { char ps [] = {92, 110, 0}; char pc [] = {92, 99, 0}; char k [] = {34, 0}; char pdata [] = "print(%c%s%c)"; char data [] = "#include <stdio.h> %s int main() { char ps [] = {92, 110, 0}; char pc [] = {92, 99, 0}; char k [] = {34, 0}; char pdata [] = %s%s%s; char data [] = %s%s%s; char ndata[1000]; sprintf(ndata, data, ps, k, pdata, k, k, data, k); printf(pdata, 39, ndata, 39); return 0;}"; char ndata[1000]; sprintf(ndata, data, ps, k, pdata, k, k, data, k); printf(pdata, 39, ndata, 39); return 0;}')
P.S. Не обращайте внимания на комментарии в коде и переносы строк. Они после первых же компиляций исчезнут, а нужны просто для удобства чтения и кодинга.
P.P.S. Люто рекомендую книжку Д. Хофштадтера (того, в честь которого назвали Леонарда в ТБВ) “Гёдель, Эшер, Бах: эта бесконечная гирлянда”. Там есть немного про квайны и вообще автореференцию, но книжка интересна не квайнами))