На этом шаге мы приведем текст процедур, позволяющих вводить с клавиатуры и выводить на экран многозначные числа.
Приведем тексты процедур, которые можно использовать для организации ввода и вывода многозначных чисел. Эти процедуры можно взять за основу при разработке собственных аналогичных процедур.
Дадим краткое описание алгоритмов, использованных при реализации этих процедур.
Процедура ввода принимает символ с клавиатуры и помещает его в стек, увеличивая на единицу значение регистра 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 - откомпилированный файл с набором процедур.
Отметим также, что крайне желательно в создаваемых процедурах сохранять используемые в процедуре регистры в начале и восстанавливать их в конце процедуры. Это позволит при разработке основной программы не вспоминать, какие регистры были задействованы в реализации той или иной процедуры.
На следующем шаге мы приведем несколько примеров использования операторов условного перехода.