Создайте загрузчик, который выполняет данную программу Brainfuck. Это код-гольф , поэтому выигрывает программа с наименьшим количеством байтов. Будучи загрузчиком, размер программы считается в ненулевых байтах в скомпилированном коде.
Brainfuck
30000 8-битных переполненных ячеек. Указатель оборачивается.
Некоторые заметки об операциях:
- Входные данные должны быть прочитаны таким образом, чтобы все печатные символы ASCII были правильно поддержаны. Другие нажатия клавиш могут либо вставлять произвольный символ, либо вообще ничего не делать.
- Чтение пользовательского ввода должно быть символьным, а не линейным.
- Чтение пользовательского ввода должно отражать вставленный символ.
- Выходные данные должны соответствовать кодовой странице 437 или кодовой странице встроенных адаптеров VGA по умолчанию.
Загрузчик
Это загрузчик x86. Загрузчик заканчивается традиционной 55 AA
последовательностью. Ваш код должен работать либо на VirtualBox, Qemu, либо на другом известном эмуляторе x86.
диск
Исполняемый файл Brainfuck находится во втором секторе диска, сразу после вашего загрузчика, который, как обычно, размещается в разделе MBR, первом секторе на диске. Дополнительный код (любой код длиной более 510 байт) может быть расположен в других секторах диска. Ваше устройство хранения данных должно быть жестким диском или гибким диском.
STDIO
Конечно, загрузчик не может иметь доступ к возможностям ввода-вывода операционной системы. Поэтому вместо этого используются функции BIOS для печати текста и чтения пользовательского ввода.
шаблон
Для начала вот простой шаблон, написанный на сборке Nasm (intel syntax):
[BITS 16]
[ORG 0x7c00]
; first sector:
boot:
; initialize segment registers
xor ax, ax
mov ds, ax
mov es, ax
mov ss, ax
; initialize stack
mov sp, 0x7bfe
; load brainfuck code into 0x8000
; no error checking is used
mov ah, 2 ; read
mov al, 1 ; one sector
mov ch, 0 ; cylinder & 0xff
mov cl, 2 ; sector | ((cylinder >> 2) & 0xc0)
mov dh, 0 ; head
; dl is already the drive number
mov bx, 0x8000 ; read buffer (es:bx)
int 0x13 ; read sectors
; fill sector
times (0x200 - 2)-($-$$) db 0
; boot signature
db 0x55, 0xaa
; second sector:
db 'brainfuck code here'
times 0x400-($-$$) db 0
Компилировать это довольно просто:
nasm file.asm -f bin -o boot.raw
И запустить его. Например, с помощью Qemu:
qemu-system-i386 -fda boot.raw
Дополнительная информация: OsDev wiki , Wikipedia
источник
Input must be red
Я почти уверен, что большинство загрузчиков изначально не поддерживают цвет.Ответы:
171 байт 1
Wooohoooo! Прошло полдня, но было весело ...
Итак, вот оно. Я думаю, что это соответствует спецификации (обтекание указателя на ячейку, эхо символов на входе, чтение символа на символ, эхо ввода символов, ...), и, похоже, на самом деле работает (ну, я не пробовал много программ , но, учитывая простоту языка, освещение, я думаю, не так уж и плохо).
Ограничения
Одна важная вещь: если ваша программа содержит все символы, отличные от 8 инструкций, или если
[]
они не сбалансированы, то это может обрушиться на вас, ха-ха-ха!Кроме того, программа brainfuck не может превышать 512 байт (сектор). Но это кажется соответствующим, поскольку вы говорите, что «исполняемый файл Brainfuck находится во втором секторе диска» .
Последняя деталь: я явно не инициализировал ячейки в ноль. Qemu, кажется, делает это для меня, и я полагаюсь на это, но я не знаю, будет ли это делать настоящий BIOS на реальном компьютере (инициализация в любом случае займет всего несколько байтов).
Код
(основываясь на вашем шаблоне, и, кстати, спасибо за это, я бы никогда не попробовал без него):
Трюки, используемые
Хорошо, я немного обманул. Поскольку вы сказали «будучи загрузчиком, размер программы в скомпилированном коде считается ненулевыми байтами» , я уменьшил код, допустив «дыры» между реализацией восьми кодов операции brainfuck. Таким образом, мне не нужна большая последовательность тестов, таблица переходов или что-то еще: я просто прыгаю к «идентификатору кода операции» (от 0 до 8) умножения, умноженному на 32, чтобы выполнить инструкцию «возрождение мозгов» (стоит отметить, что это означает, что выполнение инструкций не может занимать более 32 байт).
Более того, чтобы получить этот «идентификатор кода операции» от выбранного персонажа программы «brainfuck», я заметил, что нужно немного потасовать. Действительно, если мы просто рассмотрим биты 0, 1 и 4 символа кода операции, мы получим 8 уникальных комбинаций:
И, к счастью для меня, на самом деле есть один код операции, для реализации которого требуется более 32 байтов, но это последний (переход вперед
[
). После того, как есть больше места, все в порядке.Другой трюк: я не знаю, как работает типичный интерпретатор brainfuck, но, чтобы сделать вещи намного меньше, я фактически не реализовал
]
как «Переход назад после соответствующего,[
если данные в указателе отличны от нуля» . Вместо этого я всегда возвращаюсь к соответствующей[
и, отсюда, повторно применяю типичную[
реализацию (которая затем, в конце концов, продвигается вперед после]
повторения, если это необходимо). Для этого каждый раз, когда я прошу a[
, я помещаю текущий «указатель инструкции brainfuck» в стек перед выполнением внутренних инструкций и когда я сталкиваюсь с]
Я выскакиваю обратно указатель инструкции. Как будто это был вызов функции. Таким образом, теоретически вы можете переполнить стек, создав много многозначных циклов, но, в любом случае, не с нынешним ограничением в коде brainfuck, равным 512 байтам.1. Включая нулевые байты, которые были частью самого кода, но не те, которые были частью некоторого заполнения
источник