Brainfuck Tingkat Rendah

Bagian I
Bagian II
Bagian III

Pada 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.com

Selanjutnya, 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.com

Selanjutnya, 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.com
Kode HelloWorld terlihat seperti ideone.com

Mari 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.asm
Menghubungkan dilakukan oleh tlink.exe bf1.obj

Setelah 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.

Source: https://habr.com/ru/post/id423121/


All Articles