Квины
Квин - программа, результатом работы которой является собственный исходный текст,
выводимый на экран или в файл (предполагается, что во время ее выполнения файл
с исходным текстом недоступен). Такие программы существуют, более того, они
многочисленны и могут быть написаны на очень многих языках (даже на Fortran'е).
Само название квин (от англ. quine) дано в честь американского математика и логика
Уилларда Квина (Willard van Orman Quine). В чем полезность квинов, сказать сказать
трудно, но факт интересный. Часто приводится следующий пример на языке C:
#include
char *f="#include%cchar *f=%c%s%c;%cmain(){printf(f,10,34,f,34,10);}";
main(){printf(f,10,34,f,34,10);}
Всего три строки текста, но они опираются на достаточно сложную функцию 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++
никаких кодов символов нет:
/* Author: Andrei V. Khokhlov Language: C++ */
#include
void putc(char C)
{
cout<=10)
{
putc(Digits[N/10]);
}
else
{
putc(' ');
}
putc(Digits[N%10]);
}
void main()
{
char *Text[80];
Text[ 0]="/* Author: Andrei V. Khokhlov Language: C++ */";
Text[ 1]="";
Text[ 2]="#include ";
Text[ 3]="";
Text[ 4]="void putc(char C)";
Text[ 5]="{";
Text[ 6]=" cout<=10)";
Text[36]=" {";
Text[37]=" putc(Digits[N/10]);";
Text[38]=" }";
Text[39]=" else";
Text[40]=" {";
Text[41]=" putc(' ');";
Text[42]=" }";
Text[43]="";
Text[44]=" putc(Digits[N%10]);";
Text[45]="}";
Text[46]="";
Text[47]="void main()";
Text[48]="{";
Text[49]=" char *Text[80];";
Text[50]="";
Text[51]=" int I=0;";
Text[52]=" while (I<=50)";
Text[53]=" {";
Text[54]=" puts(Text[I++],1);";
Text[55]=" putc('##n');";
Text[56]=" }";
Text[57]="";
Text[58]=" I=0;";
Text[59]=" while (I<=77)";
Text[60]=" {";
Text[61]=" puts(~~ Text[~~,0);";
Text[62]=" line(I);";
Text[63]=" puts(~~]=~~,0);";
Text[64]=" putc('~~');";
Text[65]=" puts(Text[I++],0);";
Text[66]=" putc('~~');";
Text[67]=" putc(';');";
Text[68]=" putc('##n');";
Text[69]=" }";
Text[70]="";
Text[71]=" I=50;";
Text[72]=" while (I<=77)";
Text[73]=" {";
Text[74]=" puts(Text[I++],1);";
Text[75]=" putc('##n');";
Text[76]=" }";
Text[77]="}";
int I=0;
while (I<=50)
{
puts(Text[I++],1);
putc('\n');
}
I=0;
while (I<=77)
{
puts(" Text[",0);
line(I);
puts("]=",0);
putc('"');
puts(Text[I++],0);
putc('"');
putc(';');
putc('\n');
}
I=50;
while (I<=77)
{
puts(Text[I++],1);
putc('\n');
}
}
Оба текста должны заканчиваться символами возврата каретки и перевода строки.
Сайт создан в системе
uCoz