 |
Ассемблер в примерах - Ввод чисел, суммирование, вывод на экран и в файл
- Вопрос:
- Как в 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
|  |