Bagian IBagian IIBagian IIIPada artikel ini, kita akan menulis kompiler Brainfuck di TurboAssembler
Di sini Anda dapat men-debug program bf dalam mode langkah-demi-langkah.
Pertama, kita akan menulis penerjemah dalam beberapa bahasa tingkat tinggi, misalnya, dalam Pascal.
Array
data_arr akan mewakili memori data, string
str_arr akan berisi perintah-perintah.
Kami akan menulis sebuah program yang menampilkan karakter yang kode ascii-nya sesuai dengan angka
+ (jadi kita hanya perlu
+ dan
. Perintah)
var data_arr:array[1..10] of integer; // str_arr: string; // i, j: integer; // begin j:=1; // readln(str_arr); // for i:=1 to length(str_arr) do begin // if (str_arr[i]='+') then data_arr[j]:= data_arr[j]+1; if (str_arr[i]='.') then write(chr(data_arr[j])); end; end.
kode bf ++++++++++++++++++++++++++++++++++++. akan memberi
! (kode ascii karakter
! adalah 33).
Program ini dapat diperiksa di online ide
ideone.comSelanjutnya, ganti
for loop dengan
goto dan tambahkan perintah
Pada akhirnya, kita akan menampilkan array
data_arr LABEL prev,next; var data_arr:array[1..10] of integer; // str_arr: string; // i,j,k: integer; // begin i:=1; j:=1; readln(str_arr); // prev: if i>length(str_arr) then goto next; if (str_arr[i]='+') then data_arr[j]:= data_arr[j]+1; if (str_arr[i]='-') then data_arr[j]:= data_arr[j]-1; if (str_arr[i]='>') then j:=j+1; if (str_arr[i]='<') then j:=j-1; if (str_arr[i]='.') then write(chr(data_arr[j])); i:=i+1; goto prev; next: for k:=1 to 10 do begin write(data_arr[k]); write(' '); end; end.
Kode
akan memberikan 1 2 3 0 0 0 0 0 0 0
Kode
akan memberi 1 2 2 0 0 0 0 0 0 0
ideone.comSelanjutnya, tambahkan
[ dan
]Tambahkan variabel
i_stor lain.
Jika elemen saat ini lulus tes pada
[ , maka kami memeriksa elemen saat ini dari array
data_arr ke nol, dan jika elemen lebih besar dari nol, muat nilai dari variabel
i ke
i_stor .
Saat memproses braket penutup
] , jika
data_arr tidak nol,
kami memuat alamat braket pembuka di variabel
i dari variabel
i_stor [Selanjutnya, buka perintah
i: = i + 1;Jika sebelum itu nilai dari
i_stor dimuat ke
i (saat verifikasi
] ), maka setelah dump kita akan berada di
[ (kalau tidak kita akan berada di
] )
LABEL prev,next; var data_arr:array[1..10] of integer; // str_arr: string; // i,j,k: integer; // i_stor: integer; begin j:=1; i:=1; readln(str_arr); // prev: if i>length(str_arr) then goto next; if (str_arr[i]='+') then data_arr[j]:= data_arr[j]+1; if (str_arr[i]='-') then data_arr[j]:= data_arr[j]-1; if (str_arr[i]='>') then j:=j+1; if (str_arr[i]='<') then j:=j-1; if (str_arr[i]='.') then write(chr(data_arr[j])); if (str_arr[i]='[') then begin if data_arr[j]>0 then i_stor:=i; end; if (str_arr[i]=']') then begin if data_arr[j]>0 then begin i:=i_stor; end; end; i:=i+1; goto prev; next: for k:=1 to 10 do begin write(data_arr[k]); write(' '); end; end.
Kode
mentransfer angka 5 ke sel berikutnya 0 5 0 0 0 0 0 0 0 0
ideone.comKode HelloWorld terlihat seperti
ideone.comMari kita beralih ke assembler
Untuk mengatur satu loop (loop), Anda perlu memasukkan CX register jumlah siklus dari siklus dan memberi label yang transisi akan dibuat pada akhir siklus (dengan perintah loop).
mov CX, 28h ; - prev: ; ; ; ; loop prev ; prev
Buat array perintah
str_arr , taruh di sana
Buat data array
data_arr , (untuk kejelasan) letakkan di sana 1,1,1,1,1,1,1,1,1,1,1,1
Dalam satu lingkaran, bandingkan karakter saat ini dengan karakter
dan, jika karakternya sama, tambahkan nilainya dalam sel saat ini sebesar 1.
text segment ; bf1.asm assume cs:text, ds:data, ss:stk begin: ; mov AX,data ; mov DS,AX mov DL, str_arr ; DL 1 mov CX, 0Ah ; 10 prev: cmp DL, 2Bh ; + jne next ; , next mov BL, 00h ; BL inc data_arr[BX] ; , 1 next: inc i ; mov BL, i mov DL, str_arr [BX] loop prev mov AX, 4c00h ; int 21h text ends data segment str_arr DB 2Bh,2Bh,2Bh,'$' ; +++ data_arr DB 1,1,1,1,1,1,1,1,1,1,'$' ; i DB 0 ; data ends stk segment stack db 100h dup (0) ; 256 stk ends end begin
Perakitan (terjemahan) dilakukan oleh perintah
tasm.exe bf1.asmMenghubungkan dilakukan oleh
tlink.exe bf1.objSetelah menjalankan program di debugger TurboDebagger, Anda dapat melihat bahwa mulai dari alamat 0130, perintahnya berada
Berikutnya adalah array data di mana kita mengubah elemen pertama, lalu variabel
i , yang setelah eksekusi loop menjadi sama dengan 0Ah.

Tambahkan perintah
Untuk menghasilkan karakter tunggal menggunakan fungsi interupsi
02j ke 21j , perlu (sebelum memanggil interupsi) untuk menempatkan kode karakter dalam register
DL .
mov AH,2 mov DL, int 21h
Kami akan menulis seluruh program
text segment ; bf2.asm assume cs:text,ds:data, ss:stk begin: ; mov AX,data ; mov DS,AX mov DL, str_arr ; DL 1 mov CX, 0Ah ; 10 prev: cmp DL, 2Bh ; + jne next ; , next mov BL, j ; BL inc data_arr[BX] ; , 1 next: cmp DL, 2Dh ; - jne next1 ; , next1 mov BL, j dec data_arr[BX] next1: cmp DL, 3Eh ; > jne next2 ; , next2 inc j ; , data_arr next2: cmp DL, 3Ch ; < jne next3 ; , next3 dec j ; , data_arr next3: cmp DL, 2Eh ; . jne next4 ; , next4 mov AH,2 ; , mov BL, j mov DL, data_arr[BX] int 21h next4: inc i ; mov BL, i mov DL, str_arr [BX] loop prev mov AX, 4c00h ; int 21h text ends data segment str_arr DB 2Bh,3Eh,2Bh,2Bh,'$' ; +>++ data_arr DB 0,0,0,0,0,0,0,0,0,0,'$' ; i DB 0, '$' ; j DB 0, '$' ; data ends stk segment stack db 100h dup (0) ; 256 stk ends end begin

Loopnya bekerja seperti ini:
jika elemen
str_arr saat ini tidak
lalu lompat ke label
berikutnya: (jika tidak, jalankan
)
jika elemen
str_arr saat ini tidak
lalu lompat ke label
next1:jika elemen
str_arr saat ini tidak
lalu lompat ke label
next2:jika elemen
str_arr saat ini tidak
lalu lompat ke label
next3:jika elemen
str_arr saat ini tidak
lalu lompat ke label
next4:Setelah label
next4: tingkatkan indeks string
str_arr dan lompat ke awal loop - ke label
prev:Selanjutnya, tambahkan
[ dan
]Tambahkan variabel
i_stor .
Jika elemen saat ini lulus tes pada
[ , maka kita memeriksa elemen saat ini dari array
data_arr ke nol, dan jika elemennya nol, kita melompat lebih jauh (ke label berikutnya), jika tidak kita memuat nilai dari variabel
i ke
i_stor .
next4: cmp DL, 5Bh ; [ jne next5 ; , next5 mov BL, j mov DL, data_arr[BX] cmp DL, 00 ; , data_arr jz next5 ; , mov DL, i ; mov i_stor, Dl ; i_stor i next5:
Saat memproses braket penutup
] , jika
data_arr tidak nol, maka muat alamat braket pembuka dalam variabel
i dari variabel
i_stor [ next5: cmp DL, 5Dh ; ] jne next6 ; , next6 mov BL, j mov DL, data_arr[BX] cmp DL, 00 ; , data_arr jz next6 ; , mov DL, i_stor ; mov i, Dl ; i_stor i next6:
Periksa kodenya
text segment ; bf4.asm assume cs:text, ds:data, ss:stk begin: ; mov AX,data ; mov DS,AX mov DL, str_arr ; DL 1 mov CX, 50h ; 80 prev: cmp DL, 2Bh ; + jne next ; , next mov BL, j ; BL inc data_arr[BX] ; , 1 next: cmp DL, 2Dh ; - jne next1 ; , next1 mov BL, j dec data_arr[BX] ;BX, Bl next1: cmp DL, 3Eh ; > jne next2 ; , next2 inc j ; , data_arr next2: cmp DL, 3Ch ; < jne next3 ; , next3 dec j ; , data_arr next3: cmp DL, 2Eh ; . jne next4 ; , next4 mov AH,2 ; , mov BL, j mov DL, data_arr[BX] int 21h next4: cmp DL, 5Bh ; [ jne next5 ; , next5 mov BL, j mov DL, data_arr[BX] cmp DL, 00 ; , data_arr jz next5 ; , mov DL, i ; mov i_stor, Dl ; i_stor i next5: cmp DL, 5Dh ; ] jne next6 ; , next6 mov BL, j mov DL, data_arr[BX] cmp DL, 00 ; , data_arr jz next6 ; , mov DL, i_stor ; mov i, Dl ; i_stor i next6: inc i ; mov BL, i mov DL, str_arr[BX] loop prev ; prev: mov AX, 4c00h ; int 21h text ends data segment str_arr DB 2Bh,2Bh,2Bh,2Bh,5Bh, 3Eh,2Bh,3Ch,2Dh ,5Dh, '$' ; ++++[>+<-] data_arr DB 0,0,0,0,0,0,0,0,0,0,'$' ; i DB 0,'$' ; j DB 0,'$' ; i_stor DB 0,'$' data ends stk segment stack db 100h dup (0) ; 256 stk ends end begin

Tambahkan fungsi ke baris input
3 jam interupsi
21 jam mov ah, 3fh ; mov cx, 100h ; 256 mov dx,OFFSET str_arr int 21h
Kami akan keluar dari loop setelah mencapai akhir string
'$' .
Untuk melakukan ini, kami akan membandingkan karakter saat ini dengan karakter
'$' cmp DL, 24h ; '$' je exit_loop
Ganti loop loop dengan perintah jmp.
text segment assume cs:text,ds:data, ss: stk begin: ; mov AX,data ; mov DS,AX ; mov ah, 3fh mov cx, 100h ; 256 mov dx,OFFSET str_arr int 21h ; mov DL, str_arr ; DL 1 ;mov CX, 100h ; 256 prev: cmp DL, 24h ; '$' je exit_loop cmp DL, 2Bh ; + jne next ; , next mov BL, j ; BL inc data_arr[BX] ; , 1 next: cmp DL, 2Dh ; - jne next1 ; , next1 mov BL, j dec data_arr[BX] ;BX, Bl next1: cmp DL, 3Eh ; > jne next2 ; , next2 inc j ; , data_arr next2: cmp DL, 3Ch ; < jne next3 ; , next3 dec j ; , data_arr next3: cmp DL, 2Eh ; . jne next4 ; , next4 mov AH,2 ; , mov BL, j mov DL, data_arr[BX] int 21h next4: cmp DL, 5Bh ; [ jne next5 ; , next5 mov BL, j mov DL, data_arr[BX] cmp DL, 00 ; , data_arr jz next5 ; , mov DL, i ; mov i_stor, Dl ; i_stor i next5: cmp DL, 5Dh ; ] jne next6 ; , next6 mov BL, j mov DL, data_arr[BX] cmp DL, 00 ; , data_arr jz next6 ; , mov DL, i_stor ; mov i, Dl ; i_stor i ; prev: next6: inc i ; mov BL, i mov DL, str_arr[BX] ; loop prev ; prev: jmp prev exit_loop: MOV AH,2 ; MOV DL,0Ah INT 21h mov AX, 4c00h ; int 21h text ends data segment str_arr DB 256h DUP('$') ; 256 data_arr DB 0,0,0,0,0,0,0,0,0,0,'$' ; i DB 0,'$' ; j DB 0,'$' ; i_stor DB 0,'$' data ends stk segment para stack db 100h dup (0) ; 256 stk ends end begin
Selama kompilasi, kami mendapatkan kesalahan
Lompatan relatif di luar kisaran oleh 0001j byte
Faktanya adalah bahwa perintah
je / jne hanya dapat melompat setelah beberapa baris program (setiap baris membutuhkan 1 hingga 5 byte dalam memori).

Lompat jauh ke akhir program
je / jne tidak dapat dilakukan.
Karena itu, kami mengganti ekspresi
cmp DL, 24h ; '$' je exit_loop ... exit_loop:
ekspresi
cmp DL, 24h ; '$' jne exit_ jmp exit_loop exit_ ... exit_loop:
Jadi, jika karakter saat ini cocok dengan
$ , maka pergi ke
exit_loop: label dengan perintah
jmp , kalau tidak kita melompati perintah
jmp .
Perintah
jmp dapat membuat transisi
pendek relatif intra segmen (transisi kurang dari 128 byte, mis. IP: = IP + i8) atau
transisi panjang relatif intra segmen (transisi kurang dari 327 byte, mis. IP: = IP + i16).
Secara default, perintah
jmp membuat lompatan yang relatif lama, yang kami butuhkan (secara umum, Anda bisa menambahkan arahan lompatan ke awal program sebagai gantinya).
;jumps text segment assume cs:text,ds:data, ss: stk begin: ; mov AX,data ; mov DS,AX ;;; mov ah, 3fh ; mov cx, 100h ; 256 mov dx,OFFSET str_arr int 21h ;;; mov DL, str_arr ; DL 1 ;mov CX, 100h ; 256 prev: cmp DL, 24h ; '$' ;je exit_loop jne l1 jmp SHORT exit_loop l1: cmp DL, 2Bh ; + jne next ; , next mov BL, j ; BL inc data_arr[BX] ; , 1 next: cmp DL, 2Dh ; - jne next1 ; , next1 mov BL, j dec data_arr[BX] ;BX, Bl next1: cmp DL, 3Eh ; > jne next2 ; , next2 inc j ; , data_arr next2: cmp DL, 3Ch ; < jne next3 ; , next3 dec j ; , data_arr next3: cmp DL, 2Eh ; . jne next4 ; , next4 mov AH,2 ; , mov BL, j mov DL, data_arr[BX] int 21h next4: cmp DL, 5Bh ; [ jne next5 ; , next5 mov BL, j mov DL, data_arr[BX] cmp DL, 00 ; , data_arr jz next5 ; , mov DL, i ; mov i_stor, Dl ; i_stor i next5: cmp DL, 5Dh ; ] jne next6 ; , next6 mov BL, j mov DL, data_arr[BX] cmp DL, 00 ; , data_arr jz next6 ; , mov DL, i_stor ; mov i, Dl ; i_stor i ; prev: next6: inc i ; mov BL, i mov DL, str_arr[BX] ; loop prev ; prev: jmp prev exit_loop: MOV AH,2 ; MOV DL,0Ah INT 21h mov AX, 4c00h ; int 21h text ends data segment str_arr DB 256h DUP('$') ; 256 data_arr DB 0,0,0,0,0,0,0,0,0,0,'$' ; i DB 0,'$' ; j DB 0,'$' ; i_stor DB 0,'$' data ends stk segment para stack db 100h dup (0) ; 256 stk ends end begin
Tautan ke github dengan daftar program.
PS Berikut adalah
artikel tentang cara membuat kalkulator notasi Polandia terbalik (RPN) x86.