Blog. Just Blog

Интерпретатор Brainfuck на Ассемблере

Версия для печати Добавить в Избранное Отправить на E-Mail | Категория: Образ мышления: Assembler | Автор: ManHunter
Интерпретатор Brainfuck на Ассемблере
Интерпретатор Brainfuck на Ассемблере

Если вы увлекаетесь программированием, то скорее всего слышали об эзотерическом языке программирования Brainfuck. Дословно его название переводится на русский язык как "мозгоёбка", но в приличном обществе его обычно сглаживают до "вынос мозга". Язык имеет всего восемь команд, каждая из которых записывается одним символом. В полном соответствии с названием, программы на Brainfuck трудно не только читать, но и писать, поскольку они представляют собой последовательность символов-команд без какого-либо дополнительного синтаксиса. Несмотря на это, Brainfuck является полноценной машиной Тьюринга, и поэтому может выполнять любые вычислительные задачи. Ветераны реверса наверняка помнят KeygenMe от легендарного Ms-Rem, в котором алгоритм проверки ключа был спрятан внутри виртуальной машины на Brainfuck.

Дело было вечером, делать было нечего, после чайничка пуэра захотелось написать что-нибудь этакое. И решил я написать интерпретатор языка Brainfuck на Ассемблере. Я прекрасно знаю, что на сегодняшний день уже написано немало как интерпретаторов, так и компиляторов Brainfuck почти на всех языках программирования, но всегда приятнее создавать что-нибудь свое. Через пару часов у меня получилась вот такая функция-интерпретатор.
  1. ;------------------------------------------------------------------
  2. ; Интерпретатор языка Brainfuck
  3. ; Автор: ManHunter / PCL (www.manhunter.ru)
  4. ;------------------------------------------------------------------
  5. ; Параметры:
  6. ;   lpSource - текст программы на Brainfuck
  7. ;   lpInput  - строка для посимвольной передачи ее программе
  8. ;   lpOutput - буфер для записи результатов работы программы
  9. ;------------------------------------------------------------------
  10. ; На выходе:
  11. ;   EAX = 0  - программа выполнена успешно
  12. ;   EAX = -1 - ошибка синтаксиса,
  13. ;              EDX -> позиция ошибочной команды в строке
  14. ;   EAX = -2 - ошибка выполнения,
  15. ;              EDX -> позиция ошибочной команды в строке
  16. ;------------------------------------------------------------------
  17. proc Brainfuck lpSource:DWORD, lpInput:DWORD, lpOutput:DWORD
  18.         BRAINFUCK_MEM_LENGTH=30000
  19.  
  20.         locals
  21.                 hHeap dd ?
  22.                 mem   dd ?
  23.         endl
  24.  
  25.         ; Выделить память
  26.         invoke  GetProcessHeap
  27.         mov     [hHeap],eax
  28.         invoke  HeapAlloc,eax,HEAP_ZERO_MEMORY,BRAINFUCK_MEM_LENGTH
  29.         mov     [mem],eax
  30.  
  31.         ; Проверить правильность расстановки циклов
  32.         mov     esi,[lpSource]
  33.         cld
  34.         xor     ecx,ecx
  35. .scan_loop:
  36.         lodsb
  37.         or      al,al
  38.         jz      .scan_loop_done
  39.  
  40.         cmp     al,'['
  41.         jne     @f
  42.         inc     ecx
  43.         jmp     .scan_loop
  44. @@:
  45.         cmp     al,']'
  46.         jne     .scan_loop
  47.         or      ecx,ecx
  48.         je      .loc_syntax_error
  49.         dec     ecx
  50.         jmp     .scan_loop
  51. .scan_loop_done:
  52.         or      ecx,ecx
  53.         jnz     .loc_syntax_error
  54.  
  55.         ; Выполнить код
  56.         mov     esi,[lpInput]
  57.         mov     edi,[lpOutput]
  58.         ; Указатель на текущую команду
  59.         mov     edx,[lpSource]
  60.         ; Указатель на текущую ячейку памяти
  61.         xor     ebx,ebx
  62. .loc_loop:
  63.         mov     al,[edx]
  64.         or      al,al
  65.         jz      .loc_success
  66.  
  67.         ; Перейти к следующей ячейке
  68.         cmp     al,'>'
  69.         jne     .loc_1
  70.         inc     ebx
  71.         ; Выход за пределы памяти
  72.         cmp     ebx,BRAINFUCK_MEM_LENGTH
  73.         je      .loc_runtime_error
  74.         inc     edx
  75.         jmp     .loc_loop
  76. .loc_1:
  77.         ; Перейти к предыдущей ячейке
  78.         cmp     al,'<'
  79.         jne     .loc_2
  80.         ; Выход за пределы памяти
  81.         cmp     ebx,0
  82.         je      .loc_runtime_error
  83.         dec     ebx
  84.         inc     edx
  85.         jmp     .loc_loop
  86. .loc_2:
  87.         ; Увеличить значение в текущей ячейке на 1
  88.         cmp     al,'+'
  89.         jne     .loc_3
  90.         mov     eax,[mem]
  91.         inc     byte [eax+ebx]
  92.         inc     edx
  93.         jmp     .loc_loop
  94. .loc_3:
  95.         ; Уменьшить значение в текущей ячейке на 1
  96.         cmp     al,'-'
  97.         jne     .loc_4
  98.         mov     eax,[mem]
  99.         dec     byte [eax+ebx]
  100.         inc     edx
  101.         jmp     .loc_loop
  102. .loc_4:
  103.         ; Напечатать значение из текущей ячейки
  104.         cmp     al,'.'
  105.         jne     .loc_5
  106.         mov     eax,[mem]
  107.         mov     al,[eax+ebx]
  108.         stosb
  109.         inc     edx
  110.         jmp     .loc_loop
  111. .loc_5:
  112.         ; Ввести извне значение и сохранить в текущей ячейке
  113.         cmp     al,','
  114.         jne     .loc_6
  115.         mov     al,byte [esi]
  116.         or      al,al
  117.         jz      @f
  118.         inc     esi
  119. @@:
  120.         mov     ecx,[mem]
  121.         mov     [ecx+ebx],al
  122.         inc     edx
  123.         jmp     .loc_loop
  124. .loc_6:
  125.         ; Если значение текущей ячейки ноль, перейти вперед по тексту
  126.         ; программы на ячейку, следующую за соответствующей ] (с учетом
  127.         ; вложенности)
  128.         cmp     al,'['
  129.         jne     .loc_7
  130.         xor     ecx,ecx
  131.         inc     ecx
  132.         mov     eax,[mem]
  133.         cmp     byte [eax+ebx],0
  134.         je      .loc_6_1
  135.         inc     edx
  136.         jmp     .loc_loop
  137. .loc_6_1:
  138.         inc     edx
  139.         mov     al,[edx]
  140.         cmp     al,'['
  141.         jne     @f
  142.         inc     ecx
  143. @@:
  144.         cmp     al,']'
  145.         jne     .loc_6_1
  146.         dec     ecx
  147.         or      ecx,ecx
  148.         jnz     .loc_6_1
  149.         inc     edx
  150.         jmp     .loc_loop
  151. .loc_7:
  152.         ; Если значение текущей ячейки не нуль, перейти назад по тексту
  153.         ; программы на символ [ (с учетом вложенности)
  154.         cmp     al,']'
  155.         jne     .loc_8
  156.         xor     ecx,ecx
  157.         inc     ecx
  158.         mov     eax,[mem]
  159.         cmp     byte [eax+ebx],0
  160.         jne     .loc_7_1
  161.         inc     edx
  162.         jmp     .loc_loop
  163. .loc_7_1:
  164.         dec     edx
  165.         mov     al,[edx]
  166.         cmp     al,']'
  167.         jne     @f
  168.         inc     ecx
  169. @@:
  170.         cmp     al,'['
  171.         jne     .loc_7_1
  172.         dec     ecx
  173.         or      ecx,ecx
  174.         jnz     .loc_7_1
  175.         jmp     .loc_loop
  176. .loc_8:
  177.         ; Команда не опознана, пропустить
  178.         inc     edx
  179.         jmp     .loc_loop
  180.  
  181. .loc_syntax_error:
  182.         sub     esi,[lpSource]
  183.         mov     edx,esi
  184.         mov     eax,-2
  185.         jmp     .loc_ret
  186.  
  187. .loc_runtime_error:
  188.         sub     edx,[lpSource]
  189.         inc     edx
  190.         mov     eax,-1
  191.         jmp     .loc_ret
  192.  
  193. .loc_success:
  194.         xor     eax,eax
  195.  
  196. .loc_ret:
  197.         ; Очистить выделенную память
  198.         push    eax edx
  199.         invoke  HeapFree,[hHeap],NULL,[mem]
  200.         pop     edx eax
  201.         ret
  202. endp
За основу алгоритма работы взято авторское описание языка Урбана Мюллера, в котором используется память на 30000 ячеек с размером ячейки в 1 байт. От себя я добавил предварительную проверку синтаксиса программы на предмет правильности расстановки команд начала и окончания циклов. Также в процессе выполнения проверяется выход указателя за пределы отведенной памяти. Все остальные ошибки типа бесконечных циклов остаются уже на совести авторов программ. Функция самодостаточная и не требует дополнительного выделения каких-либо ресурсов.

Параметры вызова: lpSource - указатель на строку, содержащую текст программы на Brainfuck. В программе кроме команд Brainfuck могут быть любые символы, при обработке они просто будут игнорироваться. lpInput - указатель на строку, которая будет посимвольно передаваться программе по команде ",". При достижении конца строки на запрос программы будет передаваться нулевой символ. lpOutput - указатель на буфер, в который будут записываться все символы, выводимые командой "." из программы. Размеры буфера в интерпретаторе не проверяются, об этом вы должны позаботиться сами.

В приложении пример программы-оболочки с исходным текстом, использующей интерпретатор Brainfuck.

Пример программы с исходным текстом (FASM)Пример программы с исходным текстом (FASM)

Brainfuck.Interpreter.zip (4,344 bytes)


Поделиться ссылкой ВКонтакте Поделиться ссылкой на Facebook Поделиться ссылкой на LiveJournal Поделиться ссылкой в Мой Круг Добавить в Мой мир Добавить на ЛиРу (Liveinternet) Добавить в закладки Memori Добавить в закладки Google
Просмотров: 1179 | Комментариев: 3

Метки: Assembler
Внимание! Статья опубликована больше года назад, информация могла устареть!

Комментарии

Отзывы посетителей сайта о статье
Vnv (25.07.2017 в 18:45):
Dimka, есть отладчик онлайн, там все видно: https://fatiherikli.github.io/...-visualizer/
ManHunter (25.07.2017 в 14:16):
Не Syntax error, а Runtime error at: 46
Выход указателя за границы памяти [0..30000]
Dimka (25.07.2017 в 14:08):
Привет ) Вот это некропост с краклаба ты откопал ))
Пишу вот так:
>--[+++++++<---->>-->+>+>+<<<<]
<.>++++[-<++++<++>>>->--<<]>>-.> ;--..>+.<<<.<<-.>>+>->>.+++[.<]< ;<++.

Выдаёт Syntax error at: 46 - что не так ?

Добавить комментарий

Заполните форму для добавления комментария
Имя*:
Текст комментария (не более 2000 символов)*:

*Все поля обязательны для заполнения.
Комментарии, содержащие рекламу, ненормативную лексику, оскорбления и т.п., а также флуд и сообщения не по теме, будут удаляться. Нарушителям может быть заблокирован доступ к сайту.
Наверх
Powered by PCL's Speckled Band Engine 0.2 RC3
© ManHunter / PCL, 2008-2018
При использовании материалов ссылка на сайт обязательна
Время генерации: 0.1 сек. / MySQL: 2 (0.0059 сек.) / Память: 4.75 Mb
Наверх