BrainfuckインタプリタをAssemblyで書き直してみた。
先日の池袋バイナリ勉強会に行ったときの記事を覚えてますでしょうか?
ここにあるようにC++でBrainfuckのインタプリタを書いたのですが、このコードをコンパイルした実行ファイルの大きさがゆうに100kBいってしまっていて、もっと軽くならないものかと思ってたんですよね・・・
そこで、今回はBrainfuckのインタプリタをAssembly言語で最初から書き直してみました。
それではどうぞ!
[c]
;Brainfuck.asm bits 16 org 100h
;メモリ初期化 mov cx,799h set: mov bx,cx mov byte [mem+bx],0 loop set
;コード変換 mov ah,09h mov dx,msg0 int 21h mov ah,01h int 21h sub al,30h mov byte [cvt],al
;Inputメッセージ mov ah,09h mov dx,crlf int 21h mov dx,msg1 int 21h mov dx,crlf int 21h
;Brainfuckコード入力 mov ah,01h input: int 21h cmp al,0dh jz domsg inc word [len] mov bx,[len] mov byte [cmd+bx],al jmp input
;コード実行 domsg: mov ah,09h mov dx,crlf int 21h mov dx,msg2 int 21h mov dx,crlf int 21h
main: inc word [cps] mov bx,[cps]
cmp byte [cmd+bx],'-' jz decr
cmp byte [cmd+bx],'>' jz next
cmp byte [cmd+bx],'<' jz back
cmp byte [cmd+bx],',' jz getc
cmp byte [cmd+bx],'.' jz putc
;変換分岐 cmp byte [cvt],1 jz cnvrt
;変換不必要 cmp byte [cmd+bx],'+' jz incr
cmp byte [cmd+bx],'[' jz lin
cmp byte [cmd+bx],']' jz lout
;変換必要 cnvrt: cmp byte [cmd+bx],':' jz incr
cmp byte [cmd+bx],']' jz lin
cmp byte [cmd+bx],'\' jz lout
done: mov bx,[mps] cmp byte [mem+bx],0 js err cmp word [mps],0 js err mov dx,[len] cmp [cps],dx js main mov ax,4c00h int 21h
;エラー処理 err: mov ah,09h mov dx,msg3 int 21h mov ax,4c00h int 21h
;+ incr: mov bx,[mps] inc byte [mem+bx] jmp done
;- decr: mov bx,[mps] dec byte [mem+bx] jmp done
;> next: inc word [mps] jmp done
;< back: dec word [mps] jmp done
;. putc: mov bx,[mps] mov dl,[mem+bx] mov ah,02h int 21h jmp done
;, getc: mov ah,08h int 21h mov bx,[mps] mov byte [mem+bx],al jmp done
;[ lin: mov bx,[mps] cmp byte [mem+bx],0 jz skip mov bx,[cps] push bx jmp done
skip: inc word [cps] mov bx,[cps] ;変換分岐 cmp byte [cvt],1 jz scnvrt ;変換不要 cmp byte [cmd+bx],'[' jz li cmp byte [cmd+bx],']' jz ld ;変換必要 scnvrt: cmp byte [cmd+bx],']' jz li cmp byte [cmd+bx],'\' jz ld jmp skip
li: inc byte [lev] jmp skip
ld: cmp byte [lev],0 jz done dec byte [lev] jmp skip
;] lout: pop bx mov word [cps],bx dec word [cps] jmp done
msg0 db "Do you need convert code? (Y:1,N:other)>>$" msg1 db "Input Brainfuck code!$" msg2 db "Output$" msg3 db "Error!!$" crlf db 0dh,0ah,"$" cvt db 0 cmd resb 800h cps dw 0 mem resb 800h mps dw 0 len dw 0 lev db 0
[/c]
ソースコードは多少長く長くなりましたが、実行ファイルの大きさはなんと4.5kB!びっくりするほど小さくなりました~
あ、でもここでは命令用・実行用メモリをそれぞれ0x800個、つまり十進数で2048個取っているのですが、Brainfuckの仕様通りに実行用メモリの数を30000個取るようにすると30kBほどに膨れ上がってしまうんです。その代わり、やはり演算は相変わらずめちゃくちゃ早いですw
ダウンロードは先日と同様こちらからどうぞ。Brainfuckインタプリタ
また来週くらいに同様の勉強会があるようなので、続きをやりに行こうと思います!!