Оу май квайн

Jul 30, 2013   #без категории 

Прочитал тут статейку на хабре про квайны: 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. Люто рекомендую книжку Д. Хофштадтера (того, в честь которого назвали Леонарда в ТБВ) “Гёдель, Эшер, Бах: эта бесконечная гирлянда”. Там есть немного про квайны и вообще автореференцию, но книжка интересна не квайнами))

comments powered by Disqus