100 БАЛЛОВ. Простая задача на вывод чисел на Ассемблер NASM intel x86: Задание во вложении.
Пожалуйста, приложите к ответу небольшую блок схему с описанием алгоритма и дерево подпрограмм, а так же исходные файлы программы (.asm и .com) с загрузочным модулем. Спасибо!
Answers & Comments
.model tiny
.code
.startup
call GetString ;вводим строку с числами
call GetNumbers ;разбираем строку и выводим числа в виде hex и в обратном порядке
lea dx, sPress ;сообщение нажать любую клавишу
mov ah, 9 ;функция вывода строки
int 21h
mov ah, 0 ;ждем нажатие на клавишу
int 16h
.exit 0 ;выход из программы (эквивалентно mov ax, 4c00h / int 21h)
;ввод строки с консоли
GetString proc
lea dx, sNumbers ;сообщение 'Enter Numbers: '
mov ah,9
int 21h
lea dx, InputString ;адрес параметра функции ввода строки (формат описан ниже)
mov ah, 0ah ;номер функции ввода строки
int 21h
ret
GetString endp
;разбор строки и вывод результата
;числа будем хранить в стеке, чтобы вывести их в обратном порядке!
GetNumbers proc
mov bp, 10 ;будем умножать на 10 (при преобразовании строки в число)
xor cx, cx ;счетчик введенных чисел (хранятся в стеке)
lea si, InputString+2 ;адрес самой строки
;+2, т.к. в первых двух байтах длина строки и число введенных символов
;длину строки не используем, строку будем анализировать до кода конца строки (0dh)
num_loop: ;цикл формирования очередного числа
xor bx, bx ;здесь будем накапливать число
xor di, di ;счетчик цифр очередного числа,
; т.о. если =0, то числа нет (для контроля лишних пробелов)
sym_loop: ;цикл преобразования числовой строки в число
lodsb ;читаем очередной байт в регистр al из ds:[si], автоинкремент si
;анализируем байт
cmp al, 0dh ;прошли до конца строки?
je cmp_last ;да, учтем последнее число из строки
cmp al, ' ' ;пробел?
je space_found ;или конец введенного числа, или дополнительные разделители,
; которые проигнорируем
;ждем только цифры '0' <= al <= '9'
cmp al, '0' ;проверим на цифру
jb sym_loop ;нецифры игнорируем
cmp al, '9'
ja sym_loop
inc di ;есть очередная цифра, считаем, чтобы знать, что что-то есть
;вдвинем в формируемое число введенный десятичный разряд
;для этого предыдущие разряды умнодим на 10 и сложим с введенным
xchg ax, bx ;ax = предыдущим разрядам, bx = введенной цифре
mul bp ;dx:ax = предыдущим старшим разрядам * 10
and bx, 000fh ;превратим символ цифры 30h-39h в число 0-9
add bx, ax ;bx = введенному числу (на данный момент)
jmp sym_loop ;повторяем анализ символов строки
space_found: ;встретили пробел
test di, di ;есть число?
jz sym_loop ;нет - дополнительные пробелы игнорируем
push bx ;число сохраняем в стеке!
inc cx ;считаем
jmp num_loop ;на формирование следующего числа
cmp_last: ;встретили 0dh-конец строки
test di, di ;проверим, было ли у нас сформировано число
jz output_hex ;если в конце строки есть пробелы, то счетчик di=0
;если строка заканчивается цифрой, то di не равен 0
;и тогда это последнее число также надо сохранить в стеке
push bx ;в стек!
inc cx ;считаем
output_hex: ;выводим результат
lea dx, sHex ;сообщение 'Hex values: '
mov ah,9
int 21h
mov si, cx ;счетчик введенных чисел в si
hex_loop: ;цикл вывода hex-значений
test si, si ;проверим на 0
jnz hex_continue
ret ;все выведено или не было ни одного - выходим!
hex_continue: ;продолжаем вывод
pop bp ;извлекаем из стека очередного числа
;(в обратном порядке! так работает стек!)
mov cx, 4 ;счетчик hex-цифр
form_hex_loop: ;цикл вывода hex-цифр, начиная со старшей
rol bp, 1 ;циклически сдвигаем 4 раза, чтобы старшие 4 бита
rol bp, 1 ;(старшая hex-цифра) попали на мели младших бит
rol bp, 1
rol bp, 1
mov bx, bp ;получаем код очередной цифры в младших битах
and bx, 0fh ;маскируем все остальные биты
mov dl, byte ptr Hex[bx] ;получаем символ hex-цифры из строки Hex
mov ah, 2 ;и выводим на экран
int 21h
loop form_hex_loop ;по всем 4 цифрам
mov dl, ' ' ;разделим числа пробелом
mov ah, 2
int 21h
dec si ;уменьшим счетчик чисел
jmp hex_loop ;и на повтор
GetNumbers endp
;
Hex db '0123456789ABCDEF'
sNumbers db 0dh,0ah,"Enter numbers: $"
sHex db 0dh,0ah,"Hex values: $"
sPress db 0dh,0ah,"Press any key$"
InputString db 128,0,128 dup(?)
end