Foda cerebral de baixo nível

Escrevendo um intérprete Brainfuck (compilador) no TurboAssembler.

Para começar, vamos construir o intérprete em um idioma de alto nível, por exemplo, no Pascal.

Para começar, escreva um programa que produzirá um caractere usando a soma de + como código ASCII próprio.

Então, precisamos apenas dos comandos bf + e .

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. 

código bf ++++++++++++++++++++++++++++++++++. vai emitir !
(o código ascii do símbolo ! é 33 ).

Você pode garantir que o programa esteja correto através do link .

Em seguida, substitua for operator por goto operator e adicione os comandos 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

Em seguida, vamos adicionar [ e ]

Adicione outra variável i_stor para o loop bracket [] .

Se o item atual tiver sido aprovado na verificação de [ , carregue i no i_stor (se o item atual for maior que zero).

Pelo processamento do colchete de fechamento ] (se o data_mem não for igual a zero ), carregue o endereço do colchete de abertura [ em i do 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. 

código bf +++++ [> + <-] transfere o número 5 para a célula vizinha 0 5 0 0 0 0 0 0 0 0 0

ideone.com

Um "Olá Mundo!" programa parece ideone.com

Passando para o TASM

Para organizar o loop, coloque o número dos estágios do loop no registro CX e, em seguida, coloque o rótulo prev: (no qual a transição será feita) no final do estágio - pelo loop de comando

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


Vamos criar a matriz de dados data_mem .
Vamos criar a matriz de comandos command_mem .
Conteúdo da matriz de dados com 1 para ilustrativo como os elementos se parecem.

No loop, compare o símbolo atual com o símbolo + e, se os caracteres forem iguais, aumente o valor da célula atual

 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 

A montagem (tradução) é realizada pelo comando tasm.exe bf1.asm .

A vinculação é feita com o comando tlink.exe bf1.obj .

À medida que a execução é concluída, existem comandos +++ a partir do endereço 0130, depois o array de dados data_mem , a variável i igual a 0Ah no TurboDebugger .



Em seguida, adicione os comandos bf - <>.
Use a função 02h da interrupção int 21h para gerar um único caractere.
Coloque o código do caractere no registrador DL ​​antes de chamar a interrupção.

  mov AH,2 mov DL, character_code int 21h 

Vamos escrever o programa inteiramente

 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 



O ciclo funciona assim:

se o elemento atual do comando-mem não for igual a +, então pule para o rótulo a seguir: (caso contrário, execute + )
se o elemento atual de command-mem não for igual - pule para o rótulo next1:
se o elemento atual de command-mem não for igual > , para o rótulo next2:
se o elemento atual do comando-mem não for igual < , para o rótulo next3:
se o elemento atual do comando-mem não for igual . então pule para o rótulo next4:
Após o rótulo next4: aumente o índice do command_mem e pule para o rótulo anterior: (o início do ciclo)

Em seguida, adicione [ e ]
Adicione a variável i_stor
Se o item atual tiver sido aprovado na verificação de [ , verifique o elemento data_mem atual como zero e, se o item atual for igual a zero, pule ainda mais (no próximo rótulo); caso contrário, carregue i no 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: 

Pelo processamento do colchete de fechamento ] (se o data_mem não for igual a zero ), carregue o endereço do colchete de abertura [ em i do 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: 

Verifique o código 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 



Adicione a função de entrada 3fh interrupção 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 

o loop termina quando o caractere / comando atual é '$'

 cmp DL, '$' je exit_loop 

Alterar loop para 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 

Adicione a diretiva JUMPS .
A diretiva JUMPS permite a extensão automática do salto condicional no TASM. Se o destino de um salto condicional estiver fora da faixa, o TASM converterá o salto em um par de salto local / JMP. Por exemplo:

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


Afinal

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


All Articles