Teil I.Teil IITeil IIIIn diesem Artikel schreiben wir einen Brainfuck-Compiler auf TurboAssembler
Hier können Sie bf-Programme schrittweise debuggen.
Zuerst werden wir den Interpreter in einer höheren Sprache schreiben, zum Beispiel in Pascal.
Das Array 
data_arr repräsentiert den Datenspeicher, die Zeichenfolge 
str_arr enthält die Befehle.
Wir werden ein Programm schreiben, das ein Zeichen anzeigt, dessen ASCII-Code der Zahl 
+ entspricht (daher benötigen wir nur die Befehle 
+ und 
. )
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. 
bf code ++++++++++++++++++++++++++++++++++++++. wird geben 
! (Der ASCII-Code des Zeichens 
! ist 33).
Das Programm kann unter online ide 
ideone.com überprüft werden
Ersetzen Sie als nächstes die 
for- Schleife durch 
goto und fügen Sie die Befehle hinzu 
Am Ende geben wir das Array 
data_arr aus 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. 
Code 
ergibt 1 2 3 0 0 0 0 0 0 0 0
Code 
ergibt 1 2 2 0 0 0 0 0 0 0 0
ideone.comAls nächstes fügen Sie 
[ und 
] hinzuFügen Sie eine weitere 
i_stor- Variable hinzu.
Wenn das aktuelle Element den Test am 
[bestanden hat , überprüfen wir das aktuelle Element des 
data_arr- Arrays auf Null. Wenn das Element größer als Null ist, laden Sie den Wert aus der Variablen 
i in 
i_stor .
Wenn 
data_arr bei der Verarbeitung der schließenden Klammer nicht Null ist, laden Sie die Adresse der öffnenden Klammer in Variable 
i aus der Variablen 
i_stor [Gehen Sie als nächstes zum Befehl 
i: = i + 1;Wenn zuvor ein Wert von 
i_stor in 
i geladen wurde (während der Überprüfung 
] ), befinden wir uns nach dem Dump in 
[ (andernfalls befinden wir uns in 
] ).
 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. 
Code 
überträgt die Nummer 5 in die nächste Zelle 0 5 0 0 0 0 0 0 0 0
ideone.comHelloWorld-Code sieht aus wie 
ideone.comFahren wir mit dem Assembler fort
Um eine Schleife (Schleife) zu organisieren, müssen Sie die Anzahl der Zyklen des Zyklus in das CX-Register eintragen und eine Bezeichnung einfügen, zu der der Übergang am Ende des Zyklus erfolgt (mit dem Befehl loop).
 mov CX, 28h ; -   prev: ;   ;  ;  ;   loop prev ;    prev 
Erstellen Sie dort ein Array von 
str_arr- Befehlen 
Erstellen Sie ein 
Datenarray data_arr (aus Gründen der Übersichtlichkeit)
Vergleichen Sie in einer Schleife das aktuelle Zeichen mit dem Zeichen 
und wenn die Zeichen gleich sind, erhöhen Sie den Wert in der aktuellen Zelle um 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 
Das Zusammenbauen (Übersetzen) wird mit dem 
Befehl tasm.exe bf1.asm durchgeführtDie Verknüpfung erfolgt über 
tlink.exe bf1.objNachdem Sie das Programm im TurboDebagger-Debugger ausgeführt haben, können Sie sehen, dass sich die Befehle ab Adresse 0130 befinden 
Als nächstes folgt das Datenarray, in dem wir das erste Element geändert haben, dann die Variable 
i , die nach der Ausführung der Schleife gleich 0Ah wird.

Befehle hinzufügen 
Um ein einzelnes Zeichen mit der 
02h- Interrupt-Funktion 
int 21h auszugeben , muss (vor dem Aufrufen des Interrupts) der Zeichencode in das 
DL- Register 
eingefügt werden .
  mov AH,2 mov DL,   int 21h 
Wir werden das ganze Programm schreiben
 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 

Die Schleife funktioniert folgendermaßen:
wenn das aktuelle Element von 
str_arr nicht ist 
dann zum 
nächsten Label springen 
: (andernfalls ausführen 
)
wenn das aktuelle Element von 
str_arr nicht ist 
Springe dann zum 
nächsten Label1:wenn das aktuelle Element von 
str_arr nicht ist 
dann springe zum 
next2 label 
:wenn das aktuelle Element von 
str_arr nicht ist 
dann springe zum 
next3 label 
:wenn das aktuelle Element von 
str_arr nicht ist 
dann springe zum 
next4 label 
:Nach dem Label 
next4: Erhöhen Sie den Index des Strings 
str_arr und springen Sie zum Anfang der Schleife - zum Label 
prev:Als nächstes fügen Sie 
[ und 
] hinzuFügen Sie die Variable 
i_stor hinzu .
Wenn das aktuelle Element den Test am 
[bestanden hat , überprüfen wir das aktuelle Element des 
data_arr- Arrays auf Null, und wenn das Element Null ist, springen wir weiter (zur nächsten Bezeichnung), andernfalls laden wir den Wert aus der Variablen 
i in 
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: 
Wenn 
data_arr bei der Verarbeitung der schließenden Klammer nicht Null ist, laden Sie die Adresse der öffnenden Klammer in Variable 
i aus der Variablen 
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: 
Überprüfen Sie den Code 
 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 

Funktion zur Eingabezeile 
3fh Interrupt 
21h hinzufügen  mov ah, 3fh ;   mov cx, 100h ; 256  mov dx,OFFSET str_arr int 21h 
Wir verlassen die Schleife, nachdem wir das Ende der Zeichenfolge 
'$' erreicht haben .
Dazu vergleichen wir das aktuelle Zeichen mit dem Zeichen 
'$'. cmp DL, 24h ;  '$' je exit_loop 
Ersetzen Sie die Schleifenschleife durch den Befehl 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 
Während der Kompilierung erhalten wir eine Fehlermeldung
Relativer Sprung außerhalb des Bereichs um 0001h Bytes
Tatsache ist, dass 
je / jne- Befehle nur nach wenigen Zeilen des Programms springen können (jede Zeile benötigt 1 bis 5 Bytes im Speicher).
 Weitsprünge
Weitsprünge bis zum Ende des 
je / jne- Programms sind nicht möglich.
Deshalb ersetzen wir den Ausdruck
  cmp DL, 24h ;  '$' je exit_loop ... exit_loop: 
Ausdruck
 cmp DL, 24h ;  '$' jne exit_ jmp exit_loop exit_ ... exit_loop: 
Wenn das aktuelle Zeichen mit 
$ übereinstimmt, gehen 
Sie mit dem Befehl 
jmp zur Bezeichnung 
exit_loop:: Andernfalls springen wir über den Befehl 
jmp .
Der Befehl 
jmp kann einen 
relativ kurzen Übergang 
innerhalb eines 
Segments (Übergang weniger als 128 Bytes, d. H. IP: = IP + i8) oder einen 
relativ langen Übergang innerhalb eines 
Segments (Übergang weniger als 327 Bytes, d. H. IP: = IP + i16) durchführen.
Standardmäßig macht der Befehl 
jmp einen relativen Weitsprung, was wir brauchen (im Allgemeinen können Sie stattdessen einfach die Direktive jumps am Anfang des Programms hinzufügen).
 ;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 
Link zu Github mit Programmlisten.
PS Hier ist 
ein Artikel zum Erstellen eines RPN-Rechners (x86 Reverse Polish Notation).