Цель состоит в том, чтобы написать полную программу, эмулирующую Universal Machine из ICFP 2006, с самым коротким кодом. Универсальная машина имеет очень простой набор инструкций, описанный здесь . Эмулятор должен прочитать имя файла из аргумента командной строки и запустить файл как программу, поэтому ваш язык должен каким-то образом поддерживать аргументы командной строки и stdin / out. Эмулятор должен завершить песчаную марку за разумное время (не десятилетия). Вот краткое объяснение набора инструкций:
Машина имеет восемь регистров, каждый из которых содержит 32-разрядное целое число без знака.
Машина содержит индексированный набор массивов из 32-разрядных целочисленных ячеек без знака.
Вкратце, инструкция выделения возвращает непрозрачный 32-битный uint, который является дескриптором созданного массива, который имеет статический размер и содержит 32-битные элементы uint.
0-й массив обозначает программу. Он загружается из файла с прямым порядком байтов при запуске.
Существует также указатель инструкций, который указывает на ячейку в массиве 0.
На каждом шаге инструкция читается из ячейки, на которую указывает указатель, и указатель увеличивается до того, как что-либо будет сделано.
4 старших разряда представляют код операции.
Если код операции равен 13, то следующие 3 бита представляют регистр, а остальные 25 представляют число, которое записывается в указанный регистр.
В противном случае 9 младших битов представляют три регистра, скажем, A, B и C, где C представлен 3 младшими битами.
Затем в зависимости от кода операции происходит следующее:
0. A = B, если только C == 0
1. A = B [C]
2. A [B] = C
3. A = B + C
4. A = B * C
5. A = B / C
6. A = ~ (B & C)
7. Выход из эмулятора
8. B = allocate (C)
9. освобождение (C)
10. вывод символа из C в стандартный вывод
11. ввод символа из стандартного в C
12. скопируйте массив B в массив 0 и установите указатель на C
Я написал излишне сложную, но полностью быструю реализацию (ab) с использованием jited сборки x86_64 (самое интересное начинается с emit ()) , которая наверняка поможет вам, если вы неправильно поймете некоторые аспекты машины.
источник
Ответы:
PHP:
443 416384 байта* Обновлен снова *. Это так мало, как я могу получить сейчас. Я держал некоторые переменные в дальнем конце алфавита, чтобы регулярное выражение, которое вставляет знаки $, не искажало константу STDIN, поэтому вот небольшой глоссарий:
unpack()
возвращает массивы)Беззнаковое деление - это небольшая неприятность (
*1
это необходимо для обеспечения возврата больших чисел к правильному int), но оставшуюся часть арифметики легко сохранить 32-разрядной, если использовать арифметический регистр с 0 (A|=0
) после каждой инструкции.Я нашел этот проект действительно интересным, но стремление минимизировать количество символов сделало его медленным и не элегантным, поэтому я также сделал простую (не в гольф) Java-версию, которая может завершить тест за несколько минут, а не весь день:
источник
Perl, 407
Похоже, вопрос может показаться слишком сложным, на самом деле это очень просто.
Я все еще очень плохо знаком с Perl, хотя, в любом случае здесь это
Он работает очень медленно, вероятно, в 800 раз медленнее, чем JITed x86_64.
Кроме того, мой друг сделал ссылку на реализацию C
источник
if(((Memory[++PC]>>28)&15) == 13) { Registers[(Memory[PC]>>25)&7] = (Memory[PC]&0x01ffffff);
инструкция не кэшируется, поэтому любые коды операций не 13 будут предварительно выполнять следующую инструкцию, нет?C,
+924+838825+696646623Я сохраняю «указатель» (байтовое смещение) в регистре, указанном
b
в инструкции, и использую любой регистр, обозначающий массив в псевдокоде таким же образом (или, наоборот, наоборот, чтобы воссоздать указатель) для доступа к этому массиву позже. Еще нужно попробовать тестовую программу ...Редактировать: добавлены комментарии.
Редактировать: исправлена инструкция 12. изменить указатель, а не инструкцию в памяти. Счетчик со всеми комментариями, отступами и новыми строками.
Изменить: похоже, работает сейчас, если я правильно интерпретировать результаты. :) Окончательная реализация состояла в том, что на массив 0 действительно ссылается дескриптор 0, который можно найти в неинициализированном регистре. Очень скрученная машинка! :)
Изменить: переписать аппарат отладки, чтобы использовать
write
вместоprintf
.... Идея здесь состоит в том, чтобы удалить ошибки. :) Редактировать:putchar()
иgetchar()
также нет сsbrk
. Теперь он работает и выглядит довольно быстро.Только для байтов с прямым порядком байтов, есть версия с 611 символами.
С отступом и комментариями, с (расширенным) закомментированным аппаратом отладки.
источник
lbreak
и как вы можете unary-*
вint
d000108f c0000030
и затем завершается