Low Level Brainfuck. Continuing ...

  • Tutorial
Part I
Part II
Part III

We write a brainfuck on TurboAssembler.

Add the output of the data_arr array (“tape” of the Turing machine) to the screen.

Write a program that displays the elements of an arbitrary array through the function 09h interrupt 21h

.model tiny                 ; ascii-decoder.asm
jumps
.data
 data_arr DB 1,0,2,0,3,0,4,0,5,0,6,0,7,'$' ; данные
.code
ORG    100h
start:
;Подготовим все необходимое
  mov AX, @data          ; настраиваем сегмент данных                                       
  mov DS,AX
;;;;;;;;;;;;;;;;
 MOV    AH,2              ; переходим на новую строку
 MOV    DL,0Ah     
 INT21h 
mov dx,offset data_arr     ; указатель на массив символов
mov ah,09h		            ; вывести строку
int21h        
;;;;;;;;;;
 MOV    AH,2       ; переходим на новую строку
 MOV    DL,0Ah     
 INT21h        
 mov AX, 4c00h      ; завершение программы  
 int21h 
end start

On the screen we will see the ascii codes of the elements of the data_arr DB array 1,0,2,0,3,0,4,0,0,0,0,0,0,7, '$'



In order to represent the elements of an array as numbers, we will use the div operator .

The command div NUMBER divides the register AX into NUMBER and places the integer part of the division in AL , and the remainder of the division in AH ( NUMBER can be either a memory area or a general purpose register). We

derive the 1st and 2nd elements of the array

.model tiny                 ; ascii-decoder.asm
jumps
.data
 data_arr DB 10,12,0,0,0,0,0,0,0,0,'$' ; данные
.code
ORG    100h
start:
;Подготовим все необходимое
  mov AX, @data          ; настраиваем сегмент данных                                       
  mov DS,AX
;;;;;;;;;;;;;;;;
 MOV    AH,2              ; переходим на новую строку
 MOV    DL,0Ah     
 INT    21h 
;mov dx,offset data_arr  	; указатель на массив символов
;mov ah,09h		            ; вывести строку
;int21h        
;;выводим перое число
subAH, AH; обнуляем AH
mov AL, data_arr    ; делимое
mov BL, 10          ; делитель
div BL              ; теперь в AL=десятки, в AH=единицы
mov BX,AX
add BX,3030h
mov AH,2            ; функция вывода символа прерывания 21h 
mov DL,BL           ; выводим старший разряд 
int21h 
mov DL, BH          ; выводим младший разряд
int21h
;выводим второе число
subAH, AH; обнуляем AH
mov AL, data_arr+1   ; делимое
mov BL, 10           ; делитель
div BL               ; теперь в AL=десятки, в AH=единицы
mov BX,AX
add BX,3030h
mov AH,2            ; функция вывода символа прерывания 21h 
mov DL,BL           ; выводим старший разряд 
int21h 
mov DL, BH          ; выводим младший разряд
int21h
;;;;;;;;;;
 MOV    AH,2       ; переходим на новую строку
 MOV    DL,0Ah     
 INT    21h        
 mov AX, 4c00h      ; завершение программы  
 int21h 
end start

In order to display all the elements of the array, we will use the loop command .
Put in the register CX the number of ticks equal to the number of elements in the array and at each tick we add one to the index of the array i .

.model tiny                 ; ascii-decoder1.asm
jumps
.data
 data_arr DB 3,5,6,7,0,11,12,13,0,20,'$' ; данные
 i DB 0,'$' 
.code
ORG    100h
start:
;Подготовим все необходимое
  mov AX, @data               ; настраиваем сегмент данных                                       
  mov DS,AX
;;;;;;;;;;;;;;;;
 MOV    AH,2                  ; переходим на новую строку
 MOV    DL,0Ah     
 INT    21h 
;mov dx,offset data_arr       ; указатель на массив символов
;mov ah,09h		      ; вывести строку
;int21h                    
mov CX, 0Ah
_prev:
;;выводим число
; mov BL,i
 subAH, AH; обнуляем AH
 mov AL, data_arr[BX]    ; делимое
 mov BL, 10             ; делитель
 div BL                 ; теперь в AL=десятки, в AH=единицы
 mov BX,AX
 add BX,3030h
 mov AH,2            ; функция вывода символа прерывания 21h 
 mov DL,BL           ; выводим старший разряд 
 int21h 
 mov DL, BH          ; выводим младший разряд
 int21h
; выводим пустой символ
subDL, DLint 21h;;;
subBX,BXinci; увеличиваем счётчик          
mov BL, i
loop _prev
;;;;;;;;;;
 MOV    AH,2       ; переходим на новую строку
 MOV    DL,0Ah     
 INT    21h        
 mov AX, 4c00h      ; завершение программы  
 int21h 
end start

Next, add a loop that displays the elements of the array as numbers in the main program.

.model tiny
jumps
.data
 str_arr DB 256h DUP('$')	       
  data_arr DB 0,0,0,0,0,0,0,0,0,0,'$'   
 i DB 0,'$'                           
 j DB 0,'$'                           
 i_stor DB 0,'$'
.code
ORG    100h
start:
  mov AX, @data                                              
  mov DS,AX
  ;;;
  mov ah, 3fh          
  mov cx, 100h	       
  mov dx,OFFSET str_arr
  int21h
  ;;;             
  mov DL, str_arr      
prev:
 cmp DL, 24h          
 je  exit_loop
 cmp DL, 2Bh                                
 jne next             
 mov BL, j                        
 inc data_arr[BX]     
next: 
 cmp DL, 2Dh                                
 jne next1             
 mov BL, j 
 dec data_arr[BX]     
next1: 
 cmp DL, 3Eh         
 jne next2            
 inc j               
next2: 
 cmp DL, 3Ch         
 jne next3            
 dec j               
next3: 
 cmp DL, 2Eh         
 jne next4           
 mov AH,2            
 mov BL, j
 mov DL, data_arr[BX]
 int21h
next4:
 cmp DL, 5Bh         
 jne next5           
 ;mov BL, j
 ;mov DL, data_arr[BX]
 ;cmp DL, 00            
 ;jz next5            
 mov DL, i            
 mov i_stor, Dl      
next5:
 cmp DL, 5Dh         
 jne next6           
 mov BL, j
 mov DL, data_arr[BX]
 cmp DL, 00            
 jz next6            
 mov DL, i_stor       
 mov i, DL            
next6:
 inc i               
 mov BL, i
 mov DL, str_arr[BX] 
; loop prev          
 jmp prev
 exit_loop: 
 ;;;;;;;;;;;;;;;;
 MOV    AH,2         ; новая строка
 MOV    DL,0Ah       ; новая строка
 INT    21h          ; новая строка
; output data_arr    
mov CX, 0Ah          ; 10 тактов
subAL,AL; обнуляем AL
mov i, AL            ; обнуляем счётчик
subBX,BX; обнуляем BX
_prev:
; incorrect 1st element
 subAH, AH; обнуляем AH
 mov AL, data_arr[BX]   ; делимое
 ;mov AL, data_arr+1 
 mov BL, 10             ; делитель
 div BL                 ; частное  AL=десятки и AH=единицы
 mov BX,AX
 add BX,3030h
 mov AH,2            ; функция вывода 2 прерывания 21h 
 mov DL,BL           ; выводим десятки  
 int21h 
 mov DL, BH          ; выводим единицы
 int21h
               ; выводим пробел (пустой символ)
subDL, DLint 21h;;;
subBX,BXinci; увеличиваем индекс массива
mov BL, i
loop _prev
;;;;;;;;;;
 MOV    AH,2       ; новая строка
 MOV    DL,0Ah     ; новая строка
 INT    21h        ; новая строка 
 mov AX, 4c00h     ; завершение программы
 int21h 
end start

Now HelloWorld looks like this.



Since we do not process numbers greater than 99 , the number 100 is displayed incorrectly, the remaining numbers are displayed correctly.

Nested brackets


To handle nested brackets, we will place the opening brackets on the stack, and the closing brackets will be removed from the stack.

Let's write a simple program for working with a stack in Pascal.

var
 a : array[1..10] of integer;
 size : integer;
procedurepush(c : integer);begin
  size := size + 1;
  a[size] := c; 
 end;
 procedurepop;begin
  size := size - 1;
 end;
 begin
  size := 0; 
  Push(1);
  writeln(a[size]);
  Push(2);
  writeln(a[size]);
  Push(3);
  writeln(a[size]);
  Pop();
  writeln(a[size]);
  Pop();
  writeln(a[size]);
end.

Took from here .

You can check here or here .

Modify the push procedure so that when size equals zero, we get a reference to the first element.

procedurepush(c : integer);begin
  a[size+1] := c; 
  size := size + 1;
 end;

Add a "stack" to the main program.

Program bf5_stack;
 LABEL prev,next;
var
 a : array[1..10] of integer;
 size : integer;
 data_arr:array[1..10] of integer;    // массив данных
 str_arr: string;                     // команды  
 i,j,k: integer;                      // индексы строки и массива
 i_stor: integer; 
//Stackprocedurepush(c : integer);begin
  a[size+1] := c; 
  size := size + 1;
 end;
 procedurepop;begin
  size := size - 1;
 end;
{---------------------------------------------------}begin
 j:=1;   // нумерация элементов массива начинается с единицы
 i:=1;
 size := 0; {Изначально стек пуст}//readln(str_arr);       //считываем строку//str_arr:='+++[>+++[>+<-]<-]'; // 3*3=9
 str_arr:='+++[> +++[>+++[>+<-]<-] <-]'; //3^3=27;
 prev:
 if i>length(str_arr) thengoto 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]='.') thenwrite(chr(data_arr[j]));
    // скобкиif (str_arr[i]='[') then Push(i);
    if (str_arr[i]=']') thenbegin
      Pop();
      if (data_arr[j]>0) thenbegin
        i := a[size+1];
        goto prev;
       end;
      end;
 i:=i+1;
 goto prev;
 next:
for k:=1to10dobeginwrite(data_arr[k]);
write(' ');
end;
end.

ideone.com
If we encounter an opening bracket, then we simply put its address on the stack, when we meet the closing bracket, we retrieve its address from the stack, and if the value in the current cell is greater than zero, then we return to the opening bracket.

An example of using the normal / “standard” stack is shown in the bf51_stack.pas program .

Add a stack to the main assembler program

.model tiny                       ; bf7_stack_decoder.asm                      
jumps
.data
 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,'$'
.code
ORG    100h
start:
 ;Подготовим все необходимое
  mov AX,@data          ; настраиваем сегмент данных                                       
  mov DS,AX
  ;;;
  mov ah, 3fh          ; функция ввода
  mov cx, 100h	        ; 256 символов
  mov dx,OFFSET str_arr
  int21h
  ;;;             
  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]    ; да, увеличиваем  значение в ячейке на 1next: 
 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]
 int21h
next4:
 cmp DL, 5Bh         ; ячейка содержит [
 jne next5           ; нет, переходим на метку next5
 ;subDX,DXmovAL, i; иначе загружаем
 push AX 
next5:
 cmp DL, 5Dh         ; ячейка содержит ]
 jne next6           ; нет, переходим на метку next6
 subAX,AXpopAXmovBL, jmovDL, data_arr[BX]
 cmpDL, 00          ; да, проверяем текущий элемент data_arr на ноль  
 jz next6            ; если ноль, прыгаем дальше
 mov i, AL           ; в i_stor значение переменной i
 mov BL, i
 mov DL, str_arr[BX]   
 jmp prev
next6:
 inc i               ; переходим к следующей команде
 mov BL, i
 mov DL, str_arr[BX]   
 jmp prev
 exit_loop: 
 ;Выод ascii-символов чисел
MOV    AH,2         ; новая строка
 MOV    DL,0Ah       ; новая строка
 INT    21h          ; новая строка
; output data_arr    
mov CX, 0Ah          ; 10 тактов
subAL,AL; обнуляем AL
mov i, AL            ; обнуляем счётчик
subBX,BX; обнуляем BX
_prev:
; incorrect 1st element
 subAH, AH; обнуляем AH
 mov AL, data_arr[BX]   ; делимое
 ;mov AL, data_arr+1 
 mov BL, 10             ; делитель
 div BL                 ; частное  AL=десятки и AH=единицы
 mov BX,AX
 add BX,3030h
 mov AH,2            ; функция вывода 2 прерывания 21h 
 mov DL,BL           ; выводим десятки  
 int21h 
 mov DL, BH          ; выводим единицы
 int21h
               ; выводим пробел (пустой символ)
subDL, DLint 21h;;;
subBX,BXinci; увеличиваем индекс массива
mov BL, i
loop _prev
;;;;;;;;;;
 MOV    AH,2       ; новая строка
 MOV    DL,0Ah     ; новая строка
 INT    21h        ; новая строка 
 ;;;;;;;;;;;;;;;        
 mov AX, 4c00h      ; завершение программы  
 int21h 
END    start



Link to github.

Also popular now: