Вопрос по – Как написать самовоспроизводящийся код (печатает исходный код на exec)?

31

Я видел множество решений этой проблемы на основе C / C ++, где мы должны написать программу, которая при выполнении печатает свой собственный источник.

некоторые решения -

http://www.cprogramming.com/challenges/solutions/self_print.html

Решение Quine Page на многих языках

В сети есть еще много решений, каждое из которых отличается от другого. Интересно, как мы подходим к такой проблеме, что идет в голову тому, кто ее решает. Дайте мне некоторое представление об этой проблеме ... Хотя решения в интерпретируемых языках, таких как perl, php, ruby и т. Д., Могут быть простыми ... я хотел бы знать, как можно разработать его на скомпилированных языках ...

Ваш Ответ

11   ответов
53

нет разницы между компилируемыми и интерпретируемыми языками.

Общий подход к кваи довольно прост. Во-первых, как бы ни выглядела программа, в какой-то момент она должна что-то напечатать:

print ...

Однако, что это должно напечатать? Сам. Таким образом, он должен напечатать & quot; печать & quot; команда:

print "print ..."

Что должно быть напечатано дальше? Ну, в то время как программа росла, поэтому ей нужно напечатать строку, начинающуюся с & quot; print & quot;

print "print \"print ...\""

Теперь программа снова выросла, так что снова можно печатать:

print "print \"print \\\"...\\\"\""

И так далее. С каждым добавленным кодом появляется все больше кода для печати. Такой подход ни к чему не приведет, но это показывает интересную закономерность: Строка & quot; печать \ & quot; & quot; повторяется снова и снова. Было бы неплохо поставить повторяющуюся часть в переменную:

a = "print \""
print a

Тем не менее, программа просто изменилась, поэтому нам нужно настроить:

a = "a = ...\nprint a"
print a

Когда мы сейчас попробуем заполнить поле "...", мы сталкиваемся с теми же проблемами, что и раньше. В конечном итоге мы хотим написать что-то вроде этого:

a = "a = " + (quoted contents of a) + "\nprint a"
print a

Но это невозможно, потому что даже если бы у нас была такая функцияquoted() для цитирования, остается проблема, которую мы определяемa с точки зрения себя:

a = "a = " + quoted(a) + "\nprint a"
print a

Таким образом, единственное, что мы можем сделать, это поместить заполнитель вa:

a = "a = @\nprint a"
print a

И в этом весь трюк! Все остальное теперь понятно. Просто замените держатель с указанным содержаниемa:

a = "a = @\nprint a"
print a.replace("@", quoted(a))

Так как мы изменили код, нам нужно настроить строку:

a = "a = @\nprint a.replace(\"@\", quoted(a))"
print a.replace("@", quoted(a))

И это все! Все quines на всех языках работают таким образом (кроме читерских).

Ну, вы должны убедиться, что вы заменяете только первый случай заполнителя. И если вы используете второй место, Вы можете избежать необходимости заключать в кавычки строку.

Но это мелкие проблемы и легко решить. Если факт, реализацияquoted() а такжеreplace() являются единственными деталями, в которых различные цитрусовые действительно отличаются.

& # XB9; заставляя программу читать исходный файл

Но как избежать замены @ на заменяющую (\ & quot; @ \ & quot ;, quoted (a)) часть? Насколько я понимаю, замена должна происходить только при первом появлении @, а именно @ \ nprint. Я прав? То есть заменить следует заменить только первое вхождение символа?
0

var program = "var program = @; function main(){trace(program.replace('@', 

String.fromCharCode(34) + program + String.fromCharCode(34)))} main()"; 
function main(){
   trace(program.replace('@', String.fromCharCode(34) + program + String.fromCharCode(34)))
}
main()
1

которым я очень гордился около 5 минут, пока не обнаружил, что он был обнаружен ранее. В любом случае, есть небольшое изменение к «правилам». игры, чтобы лучше учитывать двойственность данных и кода на Лиспе: вместо распечатки исходного кода программы это S-выражение, которое возвращает себя:

((lambda (x) (list x `',x)) '(lambda (x) (list x `',x)))

один в Википедии имеет ту же концепцию, но с немного другим (более подробным) механизмом цитирования. Мне больше нравится мой, хотя.

Не считается, потому что в REPL вы можете написать только строку, например,"a" в рубине, и он вернется сам.
Я всегда считал, что это подсчитано с тех пор, как вошел в REPL, вы на самом делеdo увидеть программу выйти снова.
9

осто написать код, который открывает код и печатает его. Но более интересные из них включают языковые функции, которые допускают самостоятельное встраивание, такие как функция% s в стиле printf во многих языках. Вы должны выяснить, как встраивать что-то, чтобы оно в конечном итоге разрешалось встраивать запрос. Я подозреваю, как палиндромы, много проб и ошибок.

0

s='c=chr(39);print"s="+c+s+c+";"+s';c=chr(39);print"s="+c+s+c+";"+s

вдохновлен этим псевдокодом самопечати:

Print the following line twice, the second time with quotes.
"Print the following line twice, the second time with quotes."
0

! Вот один в php:

<?php
{
header("Content-Type: text/plain");
    $f=fopen("5.php","r");
    while(!feof($f))
    {
        echo fgetc($f);
    } 
    fclose($f);
}
?>
имя файла должно быть 5.php, чтобы этот код работал
2

как работает игра Core Wars. Я думаю, это был бы хороший пример.

0

как придать что-то двойное значение, чтобы его можно было использовать для вывода чего-либо в нескольких формах. Есть также кавет, что этот тип проблемы идет с ограничениями, чтобы усложнить его, поскольку без каких-либо правил, кроме самого вывода программы, пустая программа является решением.

1

чтобы написать что-то, что кодирует его источник в строковой константе, а затем распечатывает эту константу дважды: один раз как строковый литерал и один раз как код. Это обходит «каждый раз, когда я пишу строку кода, я должен написать еще одну, чтобы распечатать ее!» проблема.

& APOS; Обман & APOS; включает в себя: - Использование интерпретированного языка и просто загрузка источника и его печать - файлы длиной 0 байт, которые допустимы в некоторых языках, таких как C.

На самом деле, самый маленький файл C, который вы можете иметь: main; dsm $ echo main \; & GT; test.c dsm $ gcc -o test test.c test.c: 1: предупреждение: определение данных не имеет типа или класса хранения dsm $ ./test Ошибка сегментации dsm $ dsm $
Многие компиляторы Си компилируют 0-байтовый файл в исполняемый файл, который ничего не выводит и завершает работу.
0
-2

помещает File.read (_ _ FILE _ _)

это "читин" то есть
Жулик! Я называю махинации!
В Ruby многие вещи довольно просты, хотя обычно из-за их динамической природы :-)
Ого ... это так просто в ruby ...: P все потому, что это интерпретируемый язык! Abhishek Mishra
Фактически, почти во всех языках есть компилятор (опции), который может вводить исходный код в двоичный файл. Но чтение информации, которую ваш компилятор / интерпретатор дает вам бесплатно, на самом деле вовсе не является целью этого вопроса.

Похожие вопросы