Low-Level-Brainfuck

Schreiben eines Brainfuck-Interpreters (Compilers) in TurboAssembler.

Lassen Sie uns zunächst den Interpreter in einer höheren Sprache erstellen, z. B. in Pascal.

Schreiben Sie zum Auftakt ein Programm, das ein Zeichen mit der Summe + als eigenen ASCII-Code ausgibt.

Wir brauchen also nur die bf-Befehle + und .

var data_mem: array[1..10] of integer; // data array command_mem: string; // command array i: integer; // index of command array j: integer; // index of data array begin j:=1; readln(command_mem); for i:=1 to length(command_mem) do begin // in the cycle we process the string if (command_mem[i]='+') then data_mem[j]:= data_mem[j]+1; if (command_mem[i]='.') then write(chr(data_mem[j])); end; end. 

bf-code ++++++++++++++++++++++++++++++++++++++. wird ausgeben !
(Der ASCII-Code des Symbols ! ist 33 ).

Sie können über den Link sicherstellen, dass das Programm korrekt ist.

Ersetzen Sie als Nächstes den Operator durch den Operator goto und fügen Sie die bf-Befehle - <> hinzu .

  LABEL prev,next; var data_mem: array[1..10] of integer; command_mem: string; i,j,k: integer; begin j:=1; i:=1; readln(command_mem); prev: if i>length(command_mem) then goto next; if (command_mem[i]='+') then data_mem[j]:= data_mem[j]+1; if (command_mem[i]='-') then data_mem[j]:= data_mem[j]-1; if (command_mem[i]='>') then j:=j+1; if (command_mem[i]='<') then j:=j-1; if (command_mem[i]='.') then write(chr(data_mem[j])); i:=i+1; goto prev; next: for k:=1 to 10 do begin write(data_mem[k]); write(' '); end; end. 

ideone.com

Als nächstes fügen wir [ und ] hinzu

Fügen Sie eine weitere Variable i_stor für die Klammer [] hinzu .

Wenn das aktuelle Element die Prüfung für [ erfolgreich bestanden hat, laden Sie i in i_stor (wenn das aktuelle Element größer als Null ist).

Laden Sie durch die Verarbeitung der schließenden Klammer ] (wenn das data_mem nicht gleich Null ist ) die Adresse der öffnenden Klammer [ von i_stor in i

  LABEL prev,next; var data_mem: array[1..10] of integer; command_mem: string; i,j,k: integer; i_stor: integer; begin j:=1; i:=1; readln(command_mem); prev: if i>length(command_mem) then goto next; if (command_mem[i]='+') then data_mem[j]:= data_mem[j]+1; if (command_mem[i]='-') then data_mem[j]:= data_mem[j]-1; if (command_mem[i]='>') then j:=j+1; if (command_mem[i]='<') then j:=j-1; if (command_mem[i]='.') then write(chr(data_mem[j])); if (command_mem[i]='[') then begin if data_mem[j]>0 then i_stor:=i; end; if (command_mem[i]=']') then begin if data_mem[j]>0 then begin i:=i_stor; end; end; i:=i+1; goto prev; next: for k:=1 to 10 do begin write(data_mem[k]); write(' '); end; end. 

bf-code +++++ [> + <-] überträgt die Nummer 5 in die Nachbarzelle 0 5 0 0 0 0 0 0 0 0

ideone.com

Eine "Hallo Welt!" Programm sieht aus wie ideone.com

Weiter zu TASM

Um die Schleife zu organisieren, geben Sie die Anzahl der Schleifenstufen in das CX-Register ein und setzen Sie dann die Bezeichnung prev: (auf der der Übergang erfolgen soll) am Ende der Stufe - durch die Befehlsschleife

 mov CX, 28h ; count of the stages of the loop prev: ; label ; do stuff loop prev ; go back to label prev 


Lassen Sie uns das Datenarray data_mem erstellen .
Erstellen wir das Befehlsarray command_mem .
Geben Sie dem Datenarray 1 zur Veranschaulichung, wie die Elemente aussehen.

Vergleichen Sie in der Schleife das aktuelle Symbol mit dem Symbol + und erhöhen Sie bei gleichen Zeichen den Wert der aktuellen Zelle

 text segment ; bf1.asm assume cs:text, ds:data, ss:stk begin: mov AX,data ; set the data segment mov DS,AX mov DL, command_mem ; load the 1st command in the DL mov CX, 0Ah ; 10 stages prev: cmp DL, '+' ; the cell contains + jne next ; no, go to the label next: mov BL, 00h ; load into BL the index of data_mem inc data_mem[BX] ; yes, we increase the value in the cell by 1 (inc means increment) next: inc i ; go to the next character in the array of commands mov BL, i mov DL, command_mem [BX] loop prev mov AX, 4c00h ; terminate the program int 21h text ends data segment command_mem DB '+', '+', '+', '$' data_mem DB 1,1,1,1,1,1,1,1,1,1,'$' i DB 0 ; command_mem index data ends stk segment stack db 100h dup (0) ; reserve 256 cells stk ends end begin 

Das Zusammenbauen (Übersetzen) erfolgt mit dem Befehl tasm.exe bf1.asm .

Die Verknüpfung erfolgt mit dem Befehl tlink.exe bf1.obj .

Während der Ausführung gibt es Befehle +++ ab der Adresse 0130, dann kommt das Datenarray data_mem , dann kommt die Variable i gleich 0Ah im TurboDebugger .



Fügen Sie als nächstes die bf-Befehle hinzu - <>.
Verwenden Sie die Funktion 02h des Interrupts int 21h, um ein einzelnes Zeichen auszugeben.
Geben Sie den Zeichencode in das Register DL ein, bevor Sie den Interrupt aufrufen.

  mov AH,2 mov DL, character_code int 21h 

Lassen Sie uns das Programm vollständig schreiben

 text segment ; bf2.asm assume cs:text, ds:data, ss:stk begin: mov AX,data ; set the data segment mov DS,AX mov DL, command_mem mov CX, 0Ah prev: cmp DL, '+' jne next mov BL, j inc data_mem[BX] next: cmp DL, '-' jne next1 mov BL, j dec data_mem[BX] next1: cmp DL, '>' jne next2 inc j next2: cmp DL, '<' jne next3 dec j next3: cmp DL, '.' jne next4 mov AH,2 mov BL, j mov DL, data_mem[BX] int 21h next4: inc i mov BL, i mov DL, command_mem [BX] loop prev mov AX, 4c00h ; terminate the program int 21h text ends data segment command_mem DB '+', '>', '+', '+', '$' ; data_mem DB 0,0,0,0,0,0,0,0,0,0,'$' i DB 0 ; command_mem index j DB 0 ; data_mem index data ends stk segment stack db 100h dup (0) ; reserve 256 cells stk ends end begin 



Der Zyklus funktioniert folgendermaßen:

Wenn das aktuelle Element von command-mem nicht gleich + ist, springen Sie zum nächsten Label : (Andernfalls führen Sie + aus. )
Wenn das aktuelle Element von command-mem nicht gleich ist, springen Sie zur Bezeichnung next1:
Wenn das aktuelle Element von command-mem nicht gleich > ist, springen Sie zur Bezeichnung next2:
Wenn das aktuelle Element von command-mem nicht gleich < ist, springen Sie zur Bezeichnung next3:
wenn das aktuelle Element von command-mem nicht gleich ist . dann springe zum Label next4:
Nach dem Label next4: Erhöhen Sie den Index des Befehls_mem und springen Sie zum Label prev: (Beginn des Zyklus)

Als nächstes fügen Sie [ und ] hinzu
Fügen Sie die Variable i_stor hinzu
Wenn das aktuelle Element die Prüfung für [ erfolgreich bestanden hat, überprüfen Sie das aktuelle Element data_mem auf Null, und springen Sie weiter (auf dem nächsten Etikett), wenn das aktuelle Element gleich Null ist. Andernfalls laden Sie i in i_stor

 next4: cmp DL, '[' ; the cell contains [ jne next5 ; no, go to the label next5 mov BL, j mov DL, data_mem[BX] cmp DL, 00h ; yes, check current data_mem element for zero jz next5 ; if zero, jump further mov DL, i ; otherwise load i to i_stor mov i_stor, DL next5: 

Laden Sie durch die Verarbeitung der schließenden Klammer ] (wenn das data_mem nicht gleich Null ist ) die Adresse der öffnenden Klammer [ von i_stor in i

 next5: cmp DL, ']' ; the cell contains ] jne next6 ; no, go to the label next6 mov BL, j mov DL, data_arr[BX] cmp DL, 00h ; yes, check current data_mem element for zero jz next6 ; if zero, jump further mov DL, i_stor ; otherwise load i_stor to i mov i, DL next6: 

Überprüfen Sie den bf-Code ++++ [> + <-]

 text segment ; bf3.asm assume cs:text, ds:data, ss:stk begin: mov AX,data ; set the data segment mov DS,AX mov DL, command_mem mov CX, 50h prev: cmp DL, '+' jne next mov BL, j inc data_mem[BX] next: cmp DL, '-' jne next1 mov BL, j dec data_mem[BX] next1: cmp DL, '>' jne next2 inc j next2: cmp DL, '<' jne next3 dec j next3: cmp DL, '.' jne next4 mov AH,2 mov BL, j mov DL, data_mem[BX] int 21h next4: cmp DL, '[' ; the cell contains [ jne next5 ; no, go to the label next5 mov BL, j mov DL, data_mem[BX] cmp DL, 00 ; yes, check the current data_mem element for zero jz next5 ; if zero, jump further mov DL, i ; otherwise load i to i_stor mov i_stor, DL next5: cmp DL, ']' ; the cell contains ] jne next6 ; no, go to the label next6 mov BL, j mov DL, data_mem[BX] cmp DL, 00 ; yes, check current data_mem element for zero jz next6 ; if zero, jump further mov DL, i_stor ; otherwise load i_stor to i mov i, DL next6: inc i mov BL, i mov DL, command_mem[BX] loop prev mov AX, 4c00h ; terminate the program int 21h text ends data segment command_mem DB '+','+','+','+','[','>','+','<','-',']', '$' data_mem DB 0,0,0,0,0,0,0,0,0,0,'$' i DB 0 ; command_mem index j DB 0 ; data_mem index i_stor DB 0 data ends stk segment stack db 100h dup (0) ; reserve 256 cells stk ends end begin 



Fügen Sie die Eingabefunktion 3fh Interrupt 21h hinzu

 mov ah, 3fh ; input function mov cx, 100h ; the number of bytes you want to read from the input mov dx,OFFSET command_mem int 21h 

Die Schleife ist beendet, wenn das aktuelle Zeichen / der aktuelle Befehl '$' ist.

 cmp DL, '$' je exit_loop 

Ändern Sie die Schleife in jmp

 mov ah, 3fh ; input function mov cx, 100h ; the number of bytes you want to read from input mov dx,OFFSET command_mem int 21h mov DL, command_mem ; load the 1st command in the DL ;mov CX, 100h prev: cmp DL, '$' ; check the current command for '$' je exit_loop ; jump if the check has successfully passed 

Fügen Sie die JUMPS- Direktive hinzu.
Die JUMPS-Direktive ermöglicht den automatischen bedingten Sprung, der in TASM erweitert wird. Wenn das Ziel eines bedingten Sprungs außerhalb des Bereichs liegt, wandelt TASM den Sprung in ein lokales Sprung / JMP-Paar um. Zum Beispiel:

  JE EQUAL_PLACE becomes: JNE @@A JMP EQUAL_PLACE @@A: 


Immerhin

 JUMPS ; bf4.asm text segment assume cs:text,ds:data, ss: stk begin: mov AX,data mov DS,AX ;;; mov ah, 3fh mov cx, 100h mov dx,OFFSET command_mem int 21h ;;; mov DL, command_mem ;mov CX, 100h prev: cmp DL, '$' je exit_loop cmp DL, '+' jne next mov BL, j inc data_mem[BX] next: cmp DL, '-' jne next1 mov BL, j dec data_mem[BX] next1: cmp DL, '>' jne next2 inc j next2: cmp DL, '<' jne next3 dec j next3: cmp DL, '.' jne next4 mov AH,2 mov BL, j mov DL, data_mem[BX] int 21h next4: cmp DL, '[' jne next5 mov BL, j mov DL, data_mem[BX] cmp DL, 00 jz next5 mov DL, i mov i_stor, DL next5: cmp DL, ']' jne next6 mov BL, j mov DL, data_mem[BX] cmp DL, 00 jz next6 mov DL, i_stor mov i, DL next6: inc i mov BL, i mov DL, command_mem[BX] jmp prev exit_loop: MOV AH,2 MOV DL,0Ah INT 21h mov AX, 4c00h int 21h text ends data segment command_mem DB 256h DUP('$') data_mem 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) stk ends end begin 

github.com

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


All Articles