Новичок
Профиль
Группа: Участник
Сообщений: 4
Регистрация: 13.11.2008
Репутация: нет Всего: нет
|
Программа написана, но есть небольшие заковырки: при возникновении переполнения при умножении не идет проверка флага OF и результат получается неверным. Потому его вычисление надо как-то запретить выводом текстового сообщения. Еще хотелось бы выйти из программы, не вводя чисел. Также при вводе неправильной конфигурации чисел совместно с правильной хотелось бы чтобы предыдущие введенные числа оставались и не приходилось их вводить заново Вот код программы: | Код | ;Разбить входные числа на массив положительных и массив отpицательных чисел, вычислить попаpные пpоизведения и их сумму.
COUNT equ 16 ;EQU - одна из команд препроцессора. EQU присваивает ячейке символическое имя и позволяет работать в тексте программы с именем переменной ;объявляем переменную 'count'
d1 segment para public 'data' mess1 db 'Enter numbers (For the input termination, press twice key "Enter"):',10,13,'$' mess2 db 10,13,'Output array:',10,13,'$' messNoPos db 10,13,'Positive numbers are not entered! Please, repeat input',10,13,'$' messNoNeg db 10,13,'Negative numbers are not entered! Please, repeat input',10,13,'$' messOper db 10,13,'1. Calculate sum' ;меню db 10,13,'2. Calculate mul' db 10,13,'3. Exit' db 10,13,'Your choice: $' in_str db 22 dup (?) ;строка для ввода числа pos_cnt dw ? ;количество положительных neg_cnt dw ? ;количество отрицательных positive dw COUNT dup (?) ;массив положительных (max COUNT) negative dw COUNT dup (?) ;массив отрицательных (max COUNT) d1 ends
st1 segment para stack 'stack' dw 100 dup (?) st1 ends
c1 segment para public 'code' assume cs:c1,ds:d1,ss:st1 start: mov ax,d1 mov ds,ax mov in_str,20 ;подготовим буфер ввода числа repeat: mov pos_cnt,0 ;обнулим счетчики mov neg_cnt,0 mov dx,offset mess1 ;Приглашение ввода mov ah,9 ;функция прерывания 21h DOS для вывода на экран строки символов int 21h mov cx,COUNT ;вводим максимум COUNT чисел input: mov dx,offset in_str mov ah,0ah ;функция прерывания 21h DOS для ввода с клавиатуры строки символов int 21h cmp in_str+1,0 ;по пустой строке заканчиваем ввод jz comp_counts ;проверим счетчики
call GetNum ;преобразуем строку в число (в AX) jc repeat ;при ошибке на повтор ввода
test ax,ax ;проверим знак числа js save_negative save_positive: mov di,pos_cnt ;счетчик положительных одновременно является индексом места, куда пишем shl di,1 ;только умножим его на 2, чтобы адресовать слово mov positive[di],ax ;сохраняем inc pos_cnt ;инкремент количества положительных jmp next_row ;на перевод строки save_negative: mov di,neg_cnt ;то же самое для отрицательных shl di,1 mov negative[di],ax inc neg_cnt next_row: mov al,0ah ;перевод строки int 29h ;функция DOS вывода на экран — недокументированное прерывание 29h. Быстрый вывод символа на экран. В большинстве случаев INT 29h просто немедленно вызывает функцию BIOS «вывод символа на экран в режиме телетайпа», так что никаких преимуществ, кроме экономии байт при написании как можно более коротких программ, она не имеет. loop input ;повторим ввод чисел
comp_counts: cmp pos_cnt,0 ;были ли введены положительные числа jne comp_neg lea dx,messNoPos ;сообщение об ошибке (не были введены положительные числа) jmp Message comp_neg: cmp neg_cnt,0 ;были ли введены отрицательные числа jne output lea dx,messNoNeg ;сообщение об ошибке (не были введены отрицательные числа) Message: mov ah,9 int 21h jmp repeat ;на повтор ввода
output: ;выведем введенные числа mov dx,offset mess2 ;Вывод mov ah,9 ; функция прерывания 21h DOS для вывода на экран строки символов int 21h
mov cx,pos_cnt ;число положительных lea si,positive ;их адрес call PrintNumbers
mov cx,neg_cnt ;отрицательные lea si,negative call PrintNumbers
oper_loop: ;вывем меню и отработаем операции mov dx,offset messOper ;Вывод mov ah,9 ; функция прерывания 21h DOS для вывода на экран строки символов int 21h
mov ah,1 ;ввод кода клавиши с одновременным выводом на экран int 21h
push ax mov al,0ah ;перевод строки int 29h pop ax ;проанализируем код (в al) cmp al,'3' ;если 3, то выход je exit cmp al,'1' ;если 1, то сумма je summa cmp al,'2' ;если 2, то произведение jne oper_loop ;если что-то другое, то на повтор xor bp,bp ;признак произведения jmp calc_oper summa: mov bp,1 ;признак суммы calc_oper: mov cx,pos_cnt ;количество положительных mov bx,neg_cnt ;кол отрицательных lea si,positive ;адрес положительных lea di,negative ;адрес отрицательных cmp cx,bx ;найдем минимум jbe next_oper xchg cx,bx xchg si,di next_oper: ;сначала отработаем общую часть ;в CX минимум из наборов, в SI - его адрес! lodsw ;загрузка (слова) в AX первого операнда test bp,bp ;код операции jz mult add ax,[di] jmp print_oper mult: imul word ptr [di] ;знаковое умножение print_oper: add di,2 ;сдвинем индекс второго операнда call PrintNum ;выведем cmp bx,1 ;в случае одинаковых количеств обойдем вывод запятой je print_last mov al,',' ;разделительные запятая и пробел int 29h mov al,' ' int 29h dec bx ;уменьшим счетчик большего набора loop next_oper ;выведем остаток болшьшего набора mov cx,bx ;оставшееся количество в большем наборе print_tail: mov ax,[di] ;значение add di,2 ;сдвинем индекс call PrintNum ;выведем cmp cx,1 ;обойдем вывод запятой после последнего числа je Print_last mov al,',' ;разделительные запятая и пробел int 29h mov al,' ' int 29h loop print_tail
Print_last: ;перевод строки mov al,0dh int 29h mov al,0ah int 29h jmp oper_loop ;перейти на вывод меню exit: mov ax,4c00h ;выход int 21h ; PrintNumbers proc ;вывод введенных чисел PN_loop: lodsw ;число call PrintNum ;вывод cmp cx,1 ;обойдем вывод запятой после последнего числа je PN_last mov al,',' int 29h mov al,' ' int 29h loop PN_loop PN_last: mov al,0dh ;перевод строки int 29h mov al,0ah int 29h ret PrintNumbers endp
PrintNum proc ; вывод числа из AX push bx cx test ax, ax ;проверим на знак jns form_str ;для положительного на вывод push ax ;для отрицательного выводим - и меняем знак mov al,'-' ;знак - int 29h pop ax neg ax ;меняем знак числа на +, теперь оно положительное
form_str: mov bx, 10 ; будем делить на 10 xor cx, cx ; счетчик цифр div_loop: ; цикл получения десятичных разрядов xor dx, dx ; подготовимся для очередного деления div bx ; в dx остаток - очередной десятичный разряд push dx ; сохраним в стеке (от младшего к старшему) inc cx ; посчитаем test ax, ax ; есть еще десятичные разряды? jnz div_loop ; продолжим
pr_loop: ; цикл вывода десятичных цифр-символов pop ax ; востановим очередной разряд (от старшего к младшему) add al, '0' ; символ цифры int 29h ; вывод loop pr_loop ; по всем цифрам pop cx bx ret PrintNum endp ; GetNum proc ; преобразование сроки в число push cx xor di, di ; здесь будем накапливать число mov cl, 0 ; флаг знака mov ch, 0 ; количество цифр xor bx, bx ; очередной знак (для сложения со словом) mov si,offset in_str+2 ;первый символ для обработки get_num_loop: lodsb ; очередная цифра ; проверим на разделители cmp al, 0dh je num_end_found ; конец ввода cmp al, ' ' je num_end_found cmp al, 9 je num_end_found ; минус может быть только один и в первой позиции! cmp al, '-' jne cmp_num test ch, ch ; были ли введены цифры? jnz set_c ; были - ошибка - минус не в первой позиции! test cl, cl ; был ли уже введен минус? jnz set_c ; был - ошибка - можно только один! mov cl, 1 ; пометим отрицательное число jmp get_num_loop ; на анализ следующего символа cmp_num: cmp al, '0' ; цифра? jb set_c ; ошибка - не цифра! cmp al, '9' ja set_c
inc ch ; считаем цифры and al, 0fh ; цифра -> число (30h-39h -> 0-9) mov bl, al ; сохраним (bh=0) mov ax, 10 ; умножим на 10 imul di ; предыдущее значение test dx, dx ; больше cлова - ошибка! jnz set_c add ax, bx ; добавим сохраненный разряд jc set_c ; больше слова - ошибка! js set_c ; больше 32767 - ошибка! mov di, ax ; сохраним jmp get_num_loop ; идём на анализ следующего символа
num_end_found: ; встретили разделитель test ch, ch ; что-то было? jz set_c ; не было числа (например, был введен один минус) test cl, cl ; число отрицательное? jz get_num_ret neg di ; дополнительный код отрицательного числа get_num_ret: mov ax, di ; результат в ax pop cx clc ; все ок. Команда clc сбрасывает флаг переноса CF в регистре флагов. Команда не имеет параметров и не воздействует на остальные флаги процессора. ret ; Возврат из процедуры, вызванной командой call set_c: pop cx stc ; ошибка. Установка флага переноса CF в 1 ret GetNum endp
c1 ends
end start
|
Это сообщение отредактировал(а) denura - 22.5.2009, 17:58
|