. . . . . . . . . . . . . . . .
F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 FA FB FC FD FE FF
Как было показано еще на рис.8.1, отображение ASCII-символов, oсобых
проблем не вызывает. Что же касается отображения шест. значений в символах
ASCII, то этот процесс более сложный. Например, для вывода на экран в коде
ASCII шест.00, 01 и т.д. необходимо преобразовать шест.00 в шест.3030,
шест.01 в шест.3031 и т.д.
В программе начальное значение поля HEXCTR равно 00. Это значение
последовательно увеличивается на 1. Процедура C10HEX расщепляет байт
HEXCTR на две щест. цифры. Предположим, что байт HEXCTR содержит шест.4F.
Процедура сначала выделяет шест. цифру 4 и использует это значение для
перекодировки по таблице XLATAB. В регистре AL устанавливается в
результате значение шест.34. Затем процедура выделяет вторую шест. цифру F
и перекодирует ее в шест.46. В результате oбработки получается шест.3446,
что отображается на экране как 4F.
Так как функция DOS для вывода на экран (шест.40) рассматривает
шест.1A как конец файла, то в программе это значение заменяется на пробел.
Программа, использующая для вывода на экран функцию DOS (шест.09), должна
заменять символ ограничитель '$' на пробел.
Существует много различных способов преобразования шест. цифр в
ASCII-символы. Можно поэкспериментировать с операциями сдвига и сравнения.
ПРОГРАММА: СОРТИРОВКА ЭЛЕМЕНТОВ ТАБЛИЦЫ
________________________________________________________________
Часто возникает необходимость сортировки элементов таблицы в
восходящем или нисходящем порядке. Например, пользователю может
потребоваться список наименований товара в алфавитном порядке или список
общих цен в нисходящей последовательности. Обычно, табличные данные не
определяются как в предыдущей программе, а загружаются с клавиатуры или с
диска. Данный раздел посвящен сортировке элементов таблицы, что касается
различных применений, включающих сортировку записей на дисках, то здесь
возможны более сложные программы.
Существует несколько алгоритмов сортировки таблиц от неэффективных,
но понятных, до эффективных и непонятных. Программа сортировки,
предлагаемая в данном разделе, весьма эффективна и может применяться для
большинства табличных сортировок. Конечно, если не проверить различные
алгоритмы сортировок, то даже самая неэффективная программа может
показаться работающей со скоростью света. Но цель данной книги - показать
технику ассемблера, а не сортировки. Основной подход заключается в
сравнении соседних элементов таблицы. Если первый элемент больше второго,
то элементы меняются местами. Таким образом выполняется сравнение
элементов 1 со 2, 2 с 3 и т.д. до конца таблицы с перестановкой элементов
там, где это необходимо. Если в проходе были сделаны перестановки, то весь
процесс повторяется с начала таблицы т.е. сравниваются снова элементы 1-2,
2-3 и т.д. Если в проходе не было перестановок, то таблица отсортирована и
можно прекратить процесс.
Ниже приведен алгоритм, в котором переменная SWAP является
индикатором: была перестановка элементов (YES) или нет (NO):
G10: Определить адрес последнего элемента
G20: Установить SWAP=NO
Определить адрес первого элемента
G30: Элемент > следующего элемента?
Да: Представить элементы
Установить SWAP=YES
Перейти к следующему элементу
Конец таблицы?
Нет: Перейти на G30
Да: SWAP=YES?
Да: Перейти на G20 (повторить сорт.)
Нет: Конец сортировки
Программа, показанная на рис.14.6, обеспечивает ввод с клавиатуры до
30 имен, сортировку введенных имен в алфавитном порядке и вывод на экран
отсортированного списка имен.
__________________________________________________________________________
page 60,132
TITLE NMSORT (EXE) Ввод и сортировка имен
; -----------------------------------------------
STACK SGMENT PARA STACK 'Stack'
DW 32 DUP(?)
STACK ENDS
; -----------------------------------------------
DATASG SEGMENT PARA 'Data'
NAMEPAR LABEL BYTE ;Имя списка параметров:
MAXNLEN DB 21 ; макс. длина
NAMELEN DB ? ; число введенных символов
NAMEFLD DB 21 DUP(' ') ; имя
CRLF DB 13, 10, '$'
ENDADDR DW ?
MESSG1 DB 'Name?', '$'
NAMECTR DB 00
NAMETAB DB 30 DUP(20 DUP(' ')) ;Таблица имен
NAMESAV DB 20 DUP(?), 13, 10, '$'
SWAPPED DB 00
DATA ENDS
; -----------------------------------------------
CODESG SEGMENT PARA 'Code'
BEGIN PROC FAR
ASSUME CS:CODESG,DS:DATDSG,SS:STACK,ES:DATASG
PUSH DS
SUB AX,AX
PUSH AX
MOV AX,DATASG
MOV DS,AX
MOV ES,AX
CLD
LEA DI,NAMETAB
CALL Q10CLR ;Очистить экран
CALL Q20CURS ;Установить курсор
A20LOOP:
CALL B10READ ;Ввести имя с клавиатуры
CMP NAMELEN,00 ;Есть ли еще имена?
JZ A30 ; нет - идти на сортировку
CMP NAMECTR,30 ;Введено 30 имен?
JE A30 ; да - идти на сортировку
CALL D10STOR ;Записать имя в таблицу
JMP A20LOOP
A30: ;Конец ввода имен
CALL Q10CLR ;Очистить экран
CALL Q20CURS ; и установить курсор
CMP NAMECTR,01 ;Введено менее 2 имен?
JBE A40 ; да - выйти
CALL G10SORT ;Сортировать имена
CALL K10DISP ;Вывести результат на экран
A40: RET ;Завершить программу
BEGIN ENDP
; Ввод имен с клавиатуры?
; ----------------------
B10READ PROC
MOV AH,09
LEA DX,MESSG1 ;Вывести текст запроса
INT 21H
MOV AH,0AH
LEA DX,NAMEPAR ;Ввести имя
INT 21H
MOV AH,09
LEA DX,CRLF ;Вывести CRLF
INT 21H
MOV BH,00 ;Очистить поле после имени
MOV BL,NAMELEN ;Получить счетчик символов
MOV CX,21
SUB CX,BX ;Вычислить оставшуюся длину
B20:
MOV NAMEFLD[BX],20H ;Установить символ пробела
INC BX
LOOP B20
RET
B10READ ENDP
; Запись имени в таблицу:
; ----------------------
D10STOR PROC
INC NAMECTR ;Число имен в таблице
CLD
LES SI,NAMEFLD
MOV CX,10
REP MOVSV ;Переслать имя в таблицу
RET
D10STOR ENDP
; Сортировка имен в таблице:
; -------------------------
G10SORT PROC
SUB DI,40 ;Установить адреса останова
MOV ENDADDR,DI
G20:
MOV SWAPPED,00 ;Установить начало
LEA SI,NAMETAB ; таблицы
G30:
MOV CX,20 ;Длина сравнения
MOV DI,SI
ADD DI,20 ;Следующее имя для сравнения
MOV AX,DI
MOV BX,SI
REPE CMPSB ;Сравнить имя со следующим
JBE G40 ; нет перестановки
CALL H10XCHG ; перестановка
G40:
MOV SI,AX
CMP SI,ENDADDR ;Конец таблицы?
JBE G30 ; нет - продолжить
CMP SWAPPED,00 ;Есть перестановки?
JNZ G20 ; да - продолжить,
RET ; нет - конец сортировки
G10SORT ENDP
; Перестановка элементов таблицы:
; ------------------------------
H10XCHG PROC
MOV CX,10
LEA DI,NAMESAV
MOV SI,BX
REP MOVSW ;Сохранить меньший элемент
MOV CX,10
MOV DI,BX
REP MOVSW ;Переслать больший элемент
; на место меньшего
MOV CX,10
LEA SI,NAMESAV
REP MOVSW ;Переслать сохраненный
; элемент на место большего
MOV SWAPPED,01 ;Признак перестановки
RET
H10XCHG ENDP
; Вывод на экран отсортированные имена:
; ------------------------------------
K10DISP PROC
LEA SI,NAMETAB
K20:
LEA DI,NAMESAV ;Начальный адрес таблицы
MOV CX,10
REP MOVSV
MOV AH,09
LEA DX,NAMESAV
INT 21H ;Вывести на экран
DEC NAMECTR ;Это последний элемент?
JNZ K20 ; нет - повторить цикл,
RET ; да - выйти
K10DISP ENDP
; Очистка экрана:
; --------------
Q10CLR PROC
MOV AX,0600H
MOV BH,61H ;Цвет (07 для ч/б)
SUB CX,CX
MOV DX,184FH
INT 10H
RET
Q10CLR ENDP
; Установка курсора:
; -----------------
Q20CURS PROC
MOV AH,02
SUB BH,BH
SUB DX,DX ;Установить курсор в 00,00
INT 10H
RET
Q20CURS ENDP
CODESG ENDS
END BEGIN
__________________________________________________________________________
Рис.14.6. Сортировка таблицы имен
ОПЕРАТОРЫ ТИПА, ДЛИНА И РАЗМЕРА
________________________________________________________________
Ассемблер содержит ряд специальных операторов, которые могут
оказаться полезными при программировании. Например, при изменении длины
таблицы придется модифицировать программу (для нового определения таблицы)
и процедуры, проверяющие конец таблицы. В этом случае использование
операторов TYPE (тип), LENGTH (длина) и SIZE (размер) позволяют уменьшить
число модифицируемых команд.
Рассмотрим определение следующей таблицы из десяти слов:
TABLEX DW 10 DUP(?) ;Таблица из 10 слов
Программа может использовать оператор TYPE для определения типа (DW в
данном случае), оператор LENGTH для определения DUP-фактора (10) и
оператор SIZE для определения числа байтов (10 х 2 = 20). Следующие
команды иллюстрируют три таких применения:
MOV AX,TYPE TABLEX ;AX=0002
MOV BX,LENGTH TABLEX ;BX=000A (10)
MOV CX,SIZE TABLEX ;CX=0014 (20)
Значения LENGTH и SIZE можно использовать для окончания табличного
поиска или сортировки. Например, если регистр SI содержит продвинутый
адрес таблицы при осуществлении поиска, то проверка на конец таблицы может
быть следующий:
CMP SI,SIZE TABLEX
В главе 23 "Справочник по директивам ассемблера" дается детальное
описание операторов TYPE, LENGTH и SIZE.
ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ
________________________________________________________________
- Для большинства применений, определяйте таблицы, имеющие
родственные элементы одной длины и формата данных.
- Стройте таблицы на основе форматов данных. Например, элементы могут
быть символьные или числовые длиной один, два и более байтов каждый. Может
оказаться более практичным определение двух таблиц: одна, например, для
трехсимвольных значений номеpов, а другая для двухбайтовых значений цен
единиц товара. В процессе поиска адрес элементов таблицы номеров должен