Brainfuck de bas niveau

Écriture d'un interpréteur Brainfuck (compilateur) dans TurboAssembler.

Pour commencer, construisons l'interpréteur dans un langage de haut niveau, par exemple en Pascal.

Pour commencer, écrivez un programme qui produira un caractère en utilisant la somme de + comme propre code ascii.

Nous n'avons donc besoin que des commandes bf + et .

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 ++++++++++++++++++++++++++++++++++++. émettra !
(le code ascii du symbole ! est 33 ).

Vous pouvez vous assurer que le programme est correct via le lien .

Ensuite, remplacez l'opérateur par l'opérateur goto et ajoutez les commandes bf - <> .

  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

Ensuite, ajoutons [ et ]

Ajoutez une autre variable i_stor pour la boucle crochet [] .

Si l'élément actuel a réussi la vérification de [ , chargez i dans i_stor (si l'élément actuel est supérieur à zéro).

Par le traitement de la parenthèse fermante ] (si le data_mem n'est pas égal à zéro ) charger l'adresse de la parenthèse ouvrante [ dans i depuis i_stor

  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. 

code bf +++++ [> + <-] transfère le nombre 5 à la cellule voisine 0 5 0 0 0 0 0 0 0 0

ideone.com

Un «Bonjour tout le monde!» le programme ressemble à ideone.com

Passer à TASM

Pour organiser la boucle, mettez le nombre d'étages de boucle dans le registre CX, puis mettez l'étiquette prev: (sur laquelle la transition sera effectuée) à la fin de l'étape - par la boucle de commande

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


Créons le tableau de données data_mem .
Créons le tableau de commandes command_mem .
Contenu du tableau de données avec 1 à illustratif à mesure que les éléments ressemblent.

Dans la boucle, comparez le symbole actuel avec le symbole + et, si les caractères sont égaux, incrémentez la valeur de la cellule actuelle

 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 

L'assemblage (traduction) est effectué par la commande tasm.exe bf1.asm .

La liaison est effectuée avec la commande tlink.exe bf1.obj .

Au fur et à mesure de l'exécution, il y a des commandes +++ à partir de l'adresse 0130, puis vient le tableau de données data_mem , puis vient la variable i égale à 0Ah dans le TurboDebugger .



Ensuite, ajoutez les commandes bf - <>.
Utilisez la fonction 02h de l'interruption int 21h pour sortir un seul caractère.
Mettez le code de caractère dans le registre DL avant d'appeler l'interruption.

  mov AH,2 mov DL, character_code int 21h 

Écrivons le programme entièrement

 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 



Le cycle fonctionne comme ceci:

si l'élément courant de la commande-mem n'est pas égal à +, passez à l'étiquette suivante: (sinon, effectuez + )
si l'élément courant de la commande-mem n'est pas égal - alors passez à l'étiquette suivante1:
si l'élément courant de la commande-mem n'est pas égal > alors passez à l'étiquette next2:
si l'élément courant de la commande-mem n'est pas égal à < alors passez à l'étiquette suivante3:
si l'élément actuel de command-mem n'est pas égal . puis passez à l'étiquette next4:
Après le label next4: incrémentez l'index du command_mem et passez au label prev: (le début du cycle)

Ensuite, ajoutez [ et ]
Ajoutez la variable i_stor
Si l'élément actuel a réussi la vérification [ , vérifiez l'élément data_mem actuel pour zéro, et, si l'élément actuel est égal à zéro, sautez plus loin (sur l'étiquette suivante); sinon chargez i dans 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: 

Par le traitement de la parenthèse fermante ] (si le data_mem n'est pas égal à zéro ) charger l'adresse de la parenthèse ouvrante [ dans i depuis i_stor

 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: 

Vérifiez le code bf ++++ [> + <-]

 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 



Ajouter la fonction d'entrée 3fh interruption 21h

 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 

la boucle est terminée lorsque le caractère / la commande en cours est '$'

 cmp DL, '$' je exit_loop 

Changer la boucle en 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 

Ajoutez la directive JUMPS .
La directive JUMPS permet l'extension automatique de saut conditionnel dans TASM. Si la cible d'un saut conditionnel est hors de portée, TASM convertit le saut en une paire saut local / JMP. Par exemple:

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


Après tout

 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/fr428644/


All Articles