Partie IPartie IIPartie IIIDans cet article, nous allons écrire un compilateur Brainfuck sur TurboAssembler
Ici, vous pouvez déboguer les programmes bf dans un mode pas à pas.
Tout d'abord, nous allons écrire l'interpréteur dans un langage de haut niveau, par exemple, en Pascal.
Le tableau 
data_arr représentera la mémoire de données, la chaîne 
str_arr contiendra les commandes.
Nous allons écrire un programme qui affiche un caractère dont le code ascii correspond au nombre 
+ (donc nous n'avons besoin que des commandes 
+ et 
. )
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. 
code bf ++++++++++++++++++++++++++++++++++++. va donner 
! (le code ascii du caractère 
! est 33).
Le programme peut être vérifié en ligne ide 
ideone.comEnsuite, remplacez la boucle 
for par 
goto et ajoutez les commandes 
À la fin, nous afficherons le tableau 
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. 
Code 
donnera 1 2 3 0 0 0 0 0 0 0
Code 
donnera 1 2 2 0 0 0 0 0 0 0
ideone.comEnsuite, ajoutez 
[ et 
]Ajoutez une autre variable 
i_stor .
Si l'élément actuel a réussi le test sur 
[ , alors nous vérifions l'élément actuel du tableau 
data_arr à zéro, et si l'élément est supérieur à zéro, chargez la valeur de la variable 
i dans 
i_stor .
Lors du traitement de la parenthèse fermante 
] , si 
data_arr n'est pas nul, 
nous chargeons l'adresse de la parenthèse ouvrante dans la variable 
i à partir de la variable 
i_stor [Ensuite, passez à la commande 
i: = i + 1;Si avant cela une valeur de 
i_stor était chargée dans 
i (pendant la vérification 
] ), alors après le vidage, nous serons dans 
[ (sinon nous serons dans 
] )
 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 
transfère le nombre 5 à la cellule suivante 0 5 0 0 0 0 0 0 0 0
ideone.comLe code HelloWorld ressemble à 
ideone.comPassons à l'assembleur
Pour organiser une boucle (boucle), il est nécessaire de mettre le nombre de cycles d'horloge dans le registre CX et de mettre une étiquette sur laquelle la transition sera effectuée à la fin du cycle (par la commande de boucle).
 mov CX, 28h ; -   prev: ;   ;  ;  ;   loop prev ;    prev 
Créez un tableau de commandes 
str_arr , placez-le 
Créer un tableau de données 
data_arr , (pour plus de clarté) y mettre 1,1,1,1,1,1,1,1,1,1,1
En boucle, comparez le caractère actuel avec le caractère 
et, si les caractères sont égaux, augmentez la valeur dans la cellule actuelle de 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 
L'assemblage (traduction) est effectué par la 
commande tasm.exe bf1.asmLa liaison est effectuée par 
tlink.exe bf1.objAprès avoir exécuté le programme dans le débogueur TurboDebagger, vous pouvez voir qu'à partir de l'adresse 0130, les commandes se trouvent 
Vient ensuite le tableau de données dans lequel nous avons changé le premier élément, puis la variable 
i , qui après l'exécution de la boucle devient égale à 0Ah.

Ajouter des commandes 
Pour sortir un seul caractère en utilisant la fonction d'interruption 
02h int 21h , il est nécessaire (avant d'appeler l'interruption) de placer le code de caractère dans le registre 
DL .
  mov AH,2 mov DL,   int 21h 
Nous écrirons tout le programme
 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 

La boucle fonctionne comme ceci:
si l'élément courant de 
str_arr n'est pas 
puis passez à l'étiquette 
suivante: (sinon, exécutez 
)
si l'élément courant de 
str_arr n'est pas 
puis 
passez à l' étiquette 
next1:si l'élément courant de 
str_arr n'est pas 
puis 
passez à l' étiquette 
next2:si l'élément courant de 
str_arr n'est pas 
puis 
passez à l' étiquette 
next3:si l'élément courant de 
str_arr n'est pas 
puis 
passez à l' étiquette 
next4:Après le label 
next4: augmentez l'index de la chaîne 
str_arr et 
passez au début de la boucle - au label 
prev:Ensuite, ajoutez 
[ et 
]Ajoutez la variable 
i_stor .
Si l'élément actuel a réussi le test sur 
[ , alors nous vérifions l'élément actuel du tableau 
data_arr à zéro, et si l'élément est nul, nous sautons plus loin (jusqu'à l'étiquette suivante), sinon, chargez la valeur de la variable 
i dans 
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: 
Lors du traitement de la parenthèse fermante 
] , si 
data_arr n'est pas nul, chargez l'adresse de la parenthèse ouvrante dans la variable 
i à partir de la variable 
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: 
Vérifiez le 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 

Ajouter une fonction à la ligne d'entrée 
3fh interruption 
21h  mov ah, 3fh ;   mov cx, 100h ; 256  mov dx,OFFSET str_arr int 21h 
Nous quitterons la boucle après avoir atteint la fin de la chaîne 
'$' .
Pour ce faire, nous comparerons le caractère courant avec le caractère 
'$' cmp DL, 24h ;  '$' je exit_loop 
Remplacez la boucle loop par la commande 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 
Lors de la compilation, nous obtenons une erreur
Saut relatif hors de portée de 0001h octets
Le fait est que les commandes 
je / jne ne peuvent sauter qu'après quelques lignes du programme (chaque ligne prend de 1 à 5 octets en mémoire).

Les sauts longs à la fin du programme 
je / jne ne peuvent pas être effectués.
Par conséquent, nous remplaçons l'expression
  cmp DL, 24h ;  '$' je exit_loop ... exit_loop: 
expression
 cmp DL, 24h ;  '$' jne exit_ jmp exit_loop exit_ ... exit_loop: 
Donc, si le caractère courant correspond à 
$ , alors allez dans 
exit_loop: label avec la commande 
jmp , sinon nous sautons par-dessus la commande 
jmp .
La commande 
jmp peut effectuer une transition 
courte relative intra-segment (transition inférieure à 128 octets, c'est-à-dire IP: = IP + i8) ou une 
transition longue relative intra-segment (transition inférieure à 327 octets, c'est-à-dire IP: = IP + i16).
Par défaut, la commande 
jmp effectue un saut en longueur relatif, ce dont nous avons besoin (en général, au lieu de cela, vous pouvez simplement ajouter la directive jumps au début du programme).
 ;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 
Lien vers github avec des listes de programmes.
PS Voici 
un article sur la création d'une calculatrice de notation polonaise inversée x86 (RPN).