На этом шаге мы приведем текст процедур, позволяющих вводить с клавиатуры и выводить на экран многозначные числа.
Приведем тексты процедур, которые можно использовать для организации ввода и вывода многозначных чисел. Эти процедуры можно взять за основу при разработке собственных аналогичных процедур.
Дадим краткое описание алгоритмов, использованных при реализации этих процедур.
Процедура ввода принимает символ с клавиатуры и помещает его в стек, увеличивая на единицу значение регистра CX, сохраняющего количество введенных символов. После нажатия пользователем клавиши Enter, из стека извлекается очередная цифра, которая умножается соответственно на 1, 10, 1000 и т.д. Полученное значение прибавляется к результату, находящемуся в регистре BX. Эти операции осуществляются в цикле.
Например, если было введено число 124, то тело цикла будет выполнено 3 раза и при извлечении цифр из стека будет вычислена такая сумма: 4*1+2*10+1*100, что составляет 124.
Процедура позволяет вводить отрицательные числа. В этом случае знак '-' будет последним в стеке, что является признаком завершения цикла.
Процедура вывода числа осуществляет деление значения, находящегося в регистре BX, на 10 и размещение в стеке остатков от деления. После того, как получившееся на очередном шаге частное стало равно нулю, осуществляется извлечение из стека находящихся там символов и вывод их на экран.
При выводе отрицательного числа сначала выводится знак '-', берется соответствующее этому отрицательному положительное число и далее выполняется описанный алгоритм.
Приведем текст модуля, содержащего описанные процедуры.
PUBLIC Vvod,Vyvod ;Экспортируемые процедуры. ;------------------Сегмент стека ------------------- StackSg SEGMENT PARA Stack 'Stack' DW 132 DUP (?) StackSg ENDS ;------------------Сегмент кодов ------------------- CodeSg SEGMENT PARA PUBLIC ASSUME CS:CodeSg Vvod PROC FAR ;Процедура ввода числа. ;Число помещается в регистр BX. ;------------------ Сохранение регистров -------------- PUSH AX PUSH CX PUSH DX ;------------------ Ввод с клавиатуры ----------------- MOV BX,0000 ;Введенное число. MOV CX,0000 ;Количество помещений в стек. MOV DX,1 ;Множитель. @V1: MOV AH,01 INT 21H CMP AL,0DH ;Это клавиша Enter? JE @V2 ;Переход на обработку числа. CMP AL,'-' ;Это знак '-'? JE @V3 ;Ничего вычитать не надо. SUB AL,30H @V3: MOV AH,0 PUSH AX ;Поместить цифру в стек. INC CX ;Увеличить счетчик на 1. JMP @V1 ;Переход на ввод новой цифры. ;------------------ Получение числа -------------------- @V2: POP AX ;Достать цифру из стека. CMP AL,'-' ;Это '-'? JNE @V4 ;Нет - перейти на обработку. NEG BX ;Да - сменить знак числа. JMP @V5 ;Выход из процедуры. @V4: MUL DL ;Умножить ее на множитель. ADD BX,AX ;Прибавить произведение к результату. ;Получить очередной множитель. MOV AX,DX MOV DX,000AH MUL DL MOV DX,AX ;Поместить множитель в DX. LOOP @V2 ;Извлечь очередную цифру. ;-- Выход из процедуры. Восстановление регистров -------- @V5: POP DX POP CX POP AX RET Vvod ENDP Vyvod PROC FAR ;Процедура вывода числа на экран. ;Число находится в регистре BX. ;------------------ Сохранение регистров -------------- PUSH AX PUSH CX PUSH DX ;------------------ Проверяем знак числа -------------- CMP BX,0 JGE @K1 ;Да - число неотрицательное. MOV AH,02 ;Выводим на экран символ '-'. MOV DL,'-' INT 21H NEG BX ;Меняем знак. ;------------------ Получаем цифры числа --------------- @K1: MOV AX,BX MOV BX,0000 MOV DX,000AH;Делитель. MOV CX,0000 ;Количество помещений в стек. @K2: DIV DL MOV BL,AH ;Остаток от деления - в стек. PUSH BX MOV AH,0 INC CX ;Увеличить счетчик на 1. CMP AX,0 JNE @K2 ;Получение следующей цифры. ;------------------ Вывод цифр на экран ----------------- MOV AH,02 @K3: POP DX ADD DL,30H INT 21H LOOP @K3 ;-- Выход из процедуры. Восстановление регистров -------- POP DX POP CX POP AX RET Vyvod ENDP CodeSg ENDS END
Понятно, что эти процедуры далеки от совершенства. Они могут послужить основой для написания полнофункциональных процедур.
Отметим, что можно добавить к этим процедурам еще несколько процедур (например, процедуры очистки экрана, установки курсора, вывода строки на экран и т.д.) и оформить их в виде файла, который присоединять к файлу с программой на этапе компоновки при выполнении, например, следующей команды:
LINK.EXE PROG.OBJ + SERVIS.OBJ .
Здесь PROG.OBJ - откомпилированный файл с основной программой, SERVIS.OBJ - откомпилированный файл с набором процедур.
Отметим также, что крайне желательно в создаваемых процедурах сохранять используемые в процедуре регистры в начале и восстанавливать их в конце процедуры. Это позволит при разработке основной программы не вспоминать, какие регистры были задействованы в реализации той или иной процедуры.
На следующем шаге мы приведем несколько примеров использования операторов условного перехода.