Учебник по ассемблеру (ASM)
 

Ассемблер в примерах - Ввод чисел, суммирование, вывод на экран и в файл

Вопрос:
Как в tasm написать программу: ввести с клавиатуры 7 чисел, вывести их на экран и в файл, найти их сумму, вывести результат на экран и в файл.

Ответ:
Пример окна программы:
Введите число со знаком по модулю не больше 3500: 1
Введите число со знаком по модулю не больше 3500: 2
Введите число со знаком по модулю не больше 3500: 100
Введите число со знаком по модулю не больше 3500: -200
Введите число со знаком по модулю не больше 3500: -100
Введите число со знаком по модулю не больше 3500: 500
Введите число со знаком по модулю не больше 3500: 1000
1 2 100 -200 -100 500 1000
Summ = 1303
Press any key ...
; нужно получать СОМ-файл
.model tiny
.code
; сначала мои любимые директивы для облегчения написания программы
   LOCALS @@     ; метки, начинающиеся с @@ считаюися локальными. Может быть несколько одинаковых. Сильно упрощает
   JUMPS         ; генерируется код, в котором условные переходы возможны на расстояние больше 128 байт
   
   StdOut equ 1 ; вывод на экран
   
org 100h
start:
   mov ax, 3
   int 10h
   
     lea si, array   ; подготовим к вводу
     mov cx, 7
@@next_number:
     lea dx, msg_prompt
     mov ah, 9
     int 21h
     
     mov WORD PTR f_handle, StdOut       
     
     CALL inputWord_signed
     mov  [si], ax
     add   si, 2
     LOOP @@next_number

; выведем массив полностью на экран  м заодно сумму 

     mov al, 13  ; перевод на следующую строку
     CALL WriteChar_to_file
     mov al, 10
     CALL WriteChar_to_file
     
     lea  si, array
     mov  cx, 7
@@next_screen:     
     mov  ax, [si]
     add  summ, ax
     CALL WriteWordDEC_signed
     mov  al, ' ' ; два побела для разделения чисел
     CALL WriteChar_to_file
     CALL WriteChar_to_file
     add  si, 2
     LOOP @@next_screen 
     
     lea dx, msg_summ
     mov ah, 9
     int 21h
     mov ax, summ
     CALL WriteWordDEC_signed
     
; теперь вывод в файл  
     lea dx, outFileName
     mov ah, 3Ch  ;функция создания файла
     mov cx, 20h  ; атрибут архивный
     int 21h
     jc  @@_file_error ; если установлен флаг переноса - ошибка
     
     mov f_handle, ax  ; здесь дескриптор файла 
 
     lea  si, array
     mov  cx, 7
@@next_to_file:     
     mov  ax, [si]
     add  summ, ax
     CALL WriteWordDEC_signed
     mov  al, ' ' ; два побела для разделения чисел
     CALL WriteChar_to_file
     CALL WriteChar_to_file
     add  si, 2
     LOOP @@next_to_file 
     
       lea si, msg_summ
@@_msg_to_file:
       mov  al, [si]
       cmp  al, '$'
       je   @@_summ_to_file
       CALL WriteChar_to_file
       inc  si
       jmp  @@_msg_to_file
       
@@_summ_to_file:      
     mov ax, summ
     CALL WriteWordDEC_signed
        jmp @@exit
@@_file_error:     
     lea dx, msg_fileError
     mov ah, 9
     int 21h
@@exit:     
; закрываем файл
     mov bx, f_handle
     cmp bx, 1
     je  @@_no_file
         mov ah,3Eh ; функция закрытия файла
         int 21h
     
@@_no_file:     
  lea dx, PressKey
  mov ah,9
  int 21h

  xor ax, ax
  int 16h

  int 20h
  
inputWord_signed proc
; Ввод числа со знаком - возвращает в AX
; нецифры игнорируются, кроме минуса в самом начале
 push bx
 push cx
 push dx
 push si ; накопитель
 push di ; если не 0, то число отрицательное
 
 mov cx, StdOut ; настройка f_handle для показа на экране
 mov f_handle, cx
   xor si, si
   xor di, di
   mov bx, 10
@@1:
   mov ah, 7
   int 21h    ; ввод без эхо 
   xor ah, ah  
   cmp al, '-'
   jne  @@2
     CALL WriteChar_to_file  ; показали
     inc di    ; установили флаг и дальше
     jmp @@_next_char   ; следующий символ
@@2:
   cmp al, 13 ; ENTER = конец ввода
   je   @@_finish
   cmp al, '0'
   jb   @@_next_char
   cmp al, '9'
   ja   @@_next_char
      mov cl, al   ; сохраняем для вывода, если все будет нормально
      sub al, '0'  ; превращаем в число
      or  si, si   ; это первое число?
      jnz @@_not_new  ; если не 0, но НЕ первое - переход
@@_not_zerou:          
          mov si, ax
          or  di, di
          jz  @@_positive
              neg si
@@_positive:   
          mov  al, cl
          CALL WriteChar_to_file           
          jmp @@_next_char              
@@_not_new:      
      push ax
      ; накопитель умножаем на 10
        mov  ax, si 
        imul bx ; знаковое умножение
        jc   @@_finish ; переполение = конец ввода
        mov di, ax ; произведение в dx         
        mov al, cl
        CALL WriteChar_to_file
      pop  ax
      or   di, di
      jns   @@_add
        sub di, ax
        jo  @@_finish
        jmp @@_ok
@@_add:      
      add   di, ax
      jo    @@_finish
@@_ok:      
      mov  si, di  ; все в порядке = результат помещаем в si
@@_next_char:
   mov ah, 7
   int 21h
   xor ah, ah
   jmp @@2   
@@_finish:
   mov ax, si   ; результат возвращает в AX
 pop  di 
 pop  si
 pop  dx
 pop  cx
 pop  bx
 ret
inputWord_signed endp 

writeWordDEC proc near
; вывод на экран слова в AX, воспринимается как беззнаковое
 push ax
 push bx
 push dx
 push cx
   mov bx, 10
   xor cx, cx
@@1:
   xor dx, dx
   div  bx
   push dx
   inc cx
   or ax, ax
   jnz @@1
 @@2:
   pop ax
   add al, '0'
   CALL WriteChar_to_file
   LOOP @@2    
 pop  cx
 pop  dx
 pop  bx
 pop  ax
 ret
writeWordDEC endp

WriteWordDEC_signed proc
; вывод на экран слова в AX как знакового
push ax ; сохраним AX от изменения
 or  ax, ax
 jns @@_no_sign 
   push ax ; сохраним число, так как буфер нам понадобится для минуса
   mov al, '-'
   CALL writeChar_to_file   
   pop ax
   neg ax ; изменение знака на +
@@_no_sign:
CALL writeWordDEC     
pop  ax 
ret
WriteWordDEC_signed endp

; процедура для вывода символа в файл или на экран, в зависимости от содержимого f_handle
; выводимый символ должен быть в AL
; f_handle должен быть установлен заранее
WriteChar_to_file proc
push ax
push bx
push cx
push dx
   mov buf, al
   mov ah, 40h
   mov bx, f_handle
   lea dx, buf
   mov cx, 1
   int 21h
pop  dx
pop  cx
pop  bx
pop  ax
ret
WriteChar_to_file endp 

array       dw 7 dup (?) ; место для хранения массива из 7 чисел 
outFileName db '168041.txt',0  ; обязательно нуль после имени = ASCIIZ
msg_fileError db 13,10,'Ошибка создания файла$'
f_Handle    dw ? ; дескриптор файла для вывода, в том числе и на экран, если = 1
; для вывода будет использоваться функция 40h = вывод в файл

msg_summ    db 13,10,'Summ = $'
summ        dw 0 ; здесь будет сумма

buf         db ?
msg_prompt  db 13,10,'Введите число со знаком по модулю не больше 3500: $' ; вначале символы перехода на следующую строку
PressKey    db 13,10,'Press any key ...$' 
end start

   Вперёд
   Содержание