Квин - программа, результатом работы которой является собственный исходный текст,
выводимый на экран или в файл (предполагается, что во время ее выполнения файл
с исходным текстом недоступен). Такие программы существуют, более того, они
многочисленны и могут быть написаны на очень многих языках (даже на Fortran'е).
Само название квин (от англ. quine) дано в честь американского математика и логика
Уилларда Квина (Willard van Orman Quine). В чем полезность квинов, сказать сказать
трудно, но факт интересный. Часто приводится следующий пример на языке C:
Всего три строки текста, но они опираются на достаточно сложную функцию printf
и содержат числовые коды символов (перевод строки и двойноая кавычка), т.е.
пример будет работать не на любой платформе. Работа программы основана на том,
что один раз определенная строка формата (f) печатается дважды (по-разному).
Текст программы не должен заканчиваться символами возврата каретки и перевода
строки. Нечто похожее можно сделать и без printf, но получится гораздо длиннее:
/* Author: Andrei V. Khokhlov Language: Context */
void putc(char Ch)
asm mov AH,2
asm mov DL,SS:[BP+4]
asm int 21H
end
void puts(char @S; word Flag)
word I=0;
while S[I]!=#0 do
if Flag!=0 & S[I]='~' & S[I+1]='~' then
putc('"');
inc I;
else
putc(S[I]);
end
inc I;
end
end
void line(word N)
char @Digits="0123456789";
if N>=10 then
putc(Digits[N/10]);
else
putc(' ');
end
putc(Digits[N%10]);
end
begin
char @Text[80];
@Text[ 0]="/* Author: Andrei V. Khokhlov Language: Context */";
@Text[ 1]="";
@Text[ 2]="void putc(char Ch)";
@Text[ 3]=" asm mov AH,2";
@Text[ 4]=" asm mov DL,SS:[BP+4]";
@Text[ 5]=" asm int 21H";
@Text[ 6]="end";
@Text[ 7]="";
@Text[ 8]="void puts(char @S; word Flag)";
@Text[ 9]=" word I=0;";
@Text[10]=" while S[I]!=#0 do";
@Text[11]=" if Flag!=0 & S[I]='~' & S[I+1]='~' then";
@Text[12]=" putc('~~');";
@Text[13]=" inc I;";
@Text[14]=" else";
@Text[15]=" putc(S[I]);";
@Text[16]=" end";
@Text[17]="";
@Text[18]=" inc I;";
@Text[19]=" end";
@Text[20]="end";
@Text[21]="";
@Text[22]="void line(word N)";
@Text[23]=" char @Digits=~~0123456789~~;";
@Text[24]="";
@Text[25]=" if N>=10 then";
@Text[26]=" putc(Digits[N/10]);";
@Text[27]=" else";
@Text[28]=" putc(' ');";
@Text[29]=" end";
@Text[30]="";
@Text[31]=" putc(Digits[N%10]);";
@Text[32]="end";
@Text[33]="";
@Text[34]="begin";
@Text[35]=" char @Text[80];";
@Text[36]="";
@Text[37]=" word I=0;";
@Text[38]=" while I<=36 do";
@Text[39]=" puts(@Text[I],1);";
@Text[40]=" putc(#13);";
@Text[41]=" putc(#10);";
@Text[42]="";
@Text[43]=" inc I;";
@Text[44]=" end";
@Text[45]="";
@Text[46]=" I=0;";
@Text[47]=" while I<=69 do";
@Text[48]=" puts(~~ @Text[~~,0);";
@Text[49]=" line(I);";
@Text[50]=" puts(~~]=~~,0);";
@Text[51]=" putc('~~');";
@Text[52]=" puts(@Text[I],0);";
@Text[53]=" putc('~~');";
@Text[54]=" putc(';');";
@Text[55]=" putc(#13);";
@Text[56]=" putc(#10);";
@Text[57]="";
@Text[58]=" inc I;";
@Text[59]=" end";
@Text[60]="";
@Text[61]=" I=36;";
@Text[62]=" while I<=69 do";
@Text[63]=" puts(@Text[I],1);";
@Text[64]=" putc(#13);";
@Text[65]=" putc(#10);";
@Text[66]="";
@Text[67]=" inc I;";
@Text[68]=" end";
@Text[69]="end";
word I=0;
while I<=36 do
puts(@Text[I],1);
putc(#13);
putc(#10);
inc I;
end
I=0;
while I<=69 do
puts(" @Text[",0);
line(I);
puts("]=",0);
putc('"');
puts(@Text[I],0);
putc('"');
putc(';');
putc(#13);
putc(#10);
inc I;
end
I=36;
while I<=69 do
puts(@Text[I],1);
putc(#13);
putc(#10);
inc I;
end
end
Определенный в программе массив строк с помощью функции puts распечатывается
дважды, один раз с преобразованием некоторых символов, другой раз - без него.
Этот текст также содержит коды символов перевода строки и возврата каретки,
но они есть только потому, что в текущей версии компилятора не реализована
возможность вставки этих символов в строки. В эквивалентной программе на C++
никаких кодов символов нет: