Квины

Квин - программа, результатом работы которой является собственный исходный текст, выводимый на экран или в файл (предполагается, что во время ее выполнения файл с исходным текстом недоступен). Такие программы существуют, более того, они многочисленны и могут быть написаны на очень многих языках (даже на Fortran'е). Само название квин (от англ. quine) дано в честь американского математика и логика Уилларда Квина (Willard van Orman Quine). В чем полезность квинов, сказать сказать трудно, но факт интересный. Часто приводится следующий пример на языке C:

#include<stdio.h> char *f="#include<stdio.h>%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 <iostream.h> void putc(char C) { cout<<C; } void puts(char *S, int Flag) { int I=0; while (S[I]) { if ((Flag!=0) && (S[I]=='~') && (S[I+1]=='~')) { putc('"'); I++; } else if ((Flag!=0) && (S[I]=='#') && (S[I+1]=='#')) { putc('\\'); I++; } else { putc(S[I]); } I++; } } void line(int N) { char *Digits="0123456789"; if (N>=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 <iostream.h>"; Text[ 3]=""; Text[ 4]="void putc(char C)"; Text[ 5]="{"; Text[ 6]=" cout<<C;"; Text[ 7]="}"; Text[ 8]=""; Text[ 9]="void puts(char *S, int Flag)"; Text[10]="{"; Text[11]=" int I=0;"; Text[12]=" while (S[I])"; Text[13]=" {"; Text[14]=" if ((Flag!=0) && (S[I]=='~') && (S[I+1]=='~'))"; Text[15]=" {"; Text[16]=" putc('~~'); I++;"; Text[17]=" }"; Text[18]=" else if ((Flag!=0) && (S[I]=='#') && (S[I+1]=='#'))"; Text[19]=" {"; Text[20]=" putc('####'); I++;"; Text[21]=" }"; Text[22]=" else"; Text[23]=" {"; Text[24]=" putc(S[I]);"; Text[25]=" }"; Text[26]=""; Text[27]=" I++;"; Text[28]=" }"; Text[29]="}"; Text[30]=""; Text[31]="void line(int N)"; Text[32]="{"; Text[33]=" char *Digits=~~0123456789~~;"; Text[34]=""; Text[35]=" if (N>=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