сравнении строк, которые содержат числовые данные, определенные как DW, DD
или DQ.
SCAS: СКАНИРОВАНИЕ СТРОК
________________________________________________________________
Команда SCAS отличается от команды CMPS тем, что сканирует
(просматривает) строку на определенное значение байта или слова. Команда
SCAS сравнивает содержимое области памяти (адресуемой pегистрами ES:DI) с
содержимым регистра AL или AX. В зависимости от значения флага DF команда
SCAS также увеличивает или уменьшает адрес в регистре DI на 1 для байта
или на 2 для слова. Команда SCAS устанавливает флаги AF, CF, OF, PF, SF и
ZF. При использовании префикса REP и значения длины в регистре CX команда
SCAS может сканировать строки любой длины.
Команда SCAS особенно полезна, например, в текстовых редакторах, где
программа должна сканировать строки, выполняя поиск знаков пунктуации:
точек, запятых и пробелов.
На рис.11.1 процедура H10SCAS сканирует область NAME1 на строчную
букву "m". Так как команда SCASB должна продолжать сканирование, пока
результат сравнения - "не равно" или регистр CX не равен нулю, то
используется префикс REPNE:
REPNE SCASB
Так как область NAME1 содержит слово "Assemblers", то команда SCASB
находит символ "m" в пятом сравнении. При использовании отладчика DEBUG
для трассировки команд в конце процедуры H10SCAS можно увидеть в регистре
AH значение 03 для индикации того, что символ "m" найден. Команда REP
SCASB кроме того уменьшит значение регистра CX от 10 до 06.
Команда SCASW сканирует в памяти слово на соответствие значению в
регистре AX. При использовании команд LODSW или MOV для пересылки слова в
регистр AX, следует помнить, что первый байт будет в регистре AL, а второй
байт - в регистре AH. Так как команда SCAS сравнивает байты в обратной
последовательности, то oперация корректна.
СКАНИРОВАНИЕ И ЗАМЕНА
________________________________________________________________
В процессе обработки текстовой информации может возникнуть
необходимость замены определенных символов в тексте на другие, например,
подстановка пробелов вместо различных редактирующих символов. В
приведенном ниже фрагменте программы осуществляется сканирование cтроки
STRING и замена символа амперсанд (&) на символ пробела. Когда команда
SCASB обнаружит символ & (в примере это будет позиция STRING+8), то
операция сканирования прекратится и регистр DI будет содержать aдрес
STRING+9. Для получения адреса символа & необходимо уменьшить содержимое
DI на единицу и записать по полученному адресу символ пробела.
STRLEN EQU 15 ;Длина поля STRING
STRING DB 'The time&is now'
...
CLD
MOV AL,'&' ;Искомый символ
MOV CX,STRLEN ;Длина поля STRING
LEA DI,STRING ;Адрес поля STRING
REPNE SCASB ;Сканировать
JNZ K20 ;Символ найден?
DEC DI ;Да - уменьшить адрес
MOV BYTE PTR[DI],20H ;Подставить пробел
K20: RET
АЛЬТЕРНАТИВНОЕ КОДИРОВАНИЕ
________________________________________________________________
При использовании команд MOVSB или MOVSW ассемблер предполагает
наличие корректной длины строковых данных и не требует кодирования
операндов в команде. Для команды MOVS длина должна быть закодирована в
операндах. Например, если поля FLDA и FLDB определены как байтовые (DB),
то команда
REP MOVS FLDA,FLDB
предполагает повторяющуюся пересылку байтов из поля FLDB в поле FLDA. Эту
команду можно записать также в следующем виде:
REP MOVS ES:BYTE PTR[DI],DS:[SI]
Однако загрузка регистров DI и SI адресами FLDA и FLDB oбязательна в любом
случае.
ДУБЛИРОВАНИЕ ОБРАЗЦА
________________________________________________________________
Команда STOS бывает полезна для установки в некоторой области
oпределенных значений байтов и слов. Для дублирования образца, длина
которого превышает размер слова, можно использовать команду MOVS с
небольшой модификацией. Предположим, что необходимо сформировать строку
следующего вида:
***---***---***---***---***--- . . .
Вместо того, чтобы определять полностью всю строку, можно определить
только первые шесть байтов. Закодируем образец непосредственно перед
обрабатываемой строкой следующим образом:
PATTERN DB '***---'
DISAREA DB 42 DUP(?)
.
.
CLD
MOV CX,21
LEA DI,DISAREA
LEA SI,PATTERN
REP MOVSW
В процессе выполнения команда MOVSW сначала пересылает первое слово (**)
из образца PATTERN в первое слово области DISAREA, затем - второе слово
(*-), потом третье (--):
***---***---
| |
PATTERN DISAREA
К этому моменту регистр DI будет содержать адрес DISAREA+6, а pегистр SI -
PATTERN+6, который также является адресом DISAREA. Затем команда MOVSW
автоматически дублирует образец, пересылая первое слово из DISAREA в
DISAREA+6, из DISAREA+2, в DISAREA+8, из DISAREA+4 в DISAREA+10 и т.д. В
результате образец будет полностью продублирован по всей области DISAREA:
***---***---***---***---***--- . . . ***---
| | | |
PATTERN DISAREA+6 DISAREA+12 DISAREA+42
Данную технику можно использовать для дублирования в области памяти
любого образца любой длины. Образец должен быть расположен непосредственно
перед принимающей областью.
ПРОГРАММА: ВЫРАВНИВАНИЕ ВПРАВО ПРИ ВЫВОДЕ НА ЭКРАН
________________________________________________________________
COM-программа, изображенная на рис.11.2, иллюстрирует почти весь
материал, приведенный в этой главе. Процедуры программы выполняют
следующие действия:
B10INPT - Принимает имена длиной до 30 символов, вводимых вверху экрана.
D10SCAS - Использует команду SCASB для сканирования имен и об хода любого
ввода, содержащего символ "звездочка".
E10RGHT - Использует команду MOVSB для выравнивания имен по правой границе
выводит имена в колонку в правой части экрана. Длина в поле
ACTNLEN из списка параметров ввода используется для вычисления
самого правого символа в имени, например:
JEROME KERN
OSCAR HAMMERSTEIN
RICHARD ROGERS
F10CLNM - Использует команду STOSW для очистки области имени в памяти.
__________________________________________________________________________
page 60,132
TITLE EXRING (COM) Вывод имен, выровненных справа
CODESG SEGMENT PARA 'Code'
ASSUME CS:CODESG,DS:CODESG,SS:CODESG,ES:CODESG
ORG 100H
BEGIN: JMP SHORT MAIN
;--------------------------------------------------------
NAMEPAR LABEL BYTE ;Имя списка параметров
MAXNLEN DB 31 ;Макс. длина
ACTNLEN DB ? ;Число введенных символов
NAMEFLD DB 31 DUP(' ') ;Имя
PROMPT DB 'Name?', '$'
NAMEDSP DB 31 DUP(' '), 13, 10, '$'
ROW DB 00
;--------------------------------------------------------
MAIN PROC NEAR ;Основная процедура
MOV AX,0600H
CALL Q10SCR ;Очистить экран
SUB DX,DX ;Установить курсор в 00,00
CALL Q20CURS
A10LOOP:
CALL B10INPT ;Ввести имя с клавиатуры
TEST ACTNLEN,0FFH ;Нет имени? (т.е. конец)
JZ A90 ; да - выйти
CALL D10SCAS ;Найти звездочку
CMP AL,'*' ;Найдена?
JE A10LOOP ; да - обойти
CALL E10RGHT ;Выровнять имя справа
CALL A10LOOP
A90: RET
MAIN ENDP
; Вывод запроса для ввода имени:
; -----------------------------
B10INPT PROC
MOV AH,09
LEA DX,PROMPT ;Выдать текст запроса
INT 21H
RET
B10INPT ENDP
; Поиск звездочки в имени:
; -----------------------
D10SCAS PROC
CLD
MOV AL,'*'
MOV CX,30 ;Длина сканирования - 30
LEA DI,NAMEFLD
REPNE SCASB ;Звездочка найдена?
JE D20 ; да - выйти,
MOV AL,20H ; нет стереть * в AL
D20: RET
D10SCAS ENDP
; Выравнивание справа и вывод на экран:
; ------------------------------------
E10RGHT PROC
STD
SUB CH,CH
MOV CL,ACTNLEN ;Длина в CX для REP
LEA SI,NAMEFLD ;Вычислить самую правую
ADD SI,CX ; позицию
DEC SI ; введенного имени
LEA DI,NAMEDSP+30 ;Правая поз. поля имени
REP MOVSB ;Переслать справа налево
MOV DH,ROW
MOV DL,48
CALL Q20CURS ;Установить курсор
MOV AH,09
LEA DX,NAMEDSP ;Выдать имя на экран
INT 21H
CMP ROW,20 ;Последняя строка экрана?
JAE E20 ; нет -
INC ROW ; увеличить строку,
JMP E90
E20:
MOV AX,0601H ; да -
CALL Q10SCR ; прокрутить и
MOV DH,ROW ; установить курсор
MOV DL,00
CALL Q20CURS
E90: RET
E10RGHT ENDP
; Очистить область имени:
; ----------------------
F10CLNM PROC
CLD
MOV AX,2020H
MOV CX,15 ;Очистить 15 слов
LEA DI,NAMEDSP
REP STOSW
RET
F10CLNM ENDP
; Прокрутка экрана:
; ----------------
Q10SCR PROC ;AX установлен при вызове
MOV BH,30 ;Цвет ( 07 для ч/б)
MOV CX,00
MOV DX,184FH
INT 10H
RET
Q10SCR ENDP
; Установить курсор (строка/столбец):
; ----------------------------------
Q20CURS PROC ;DX установлен при вызове
MOV AH,02
SUB BH,BH
INT 10H
RET
Q20CURS ENDP
CODESG ENDS
END BEGIN
__________________________________________________________________________
Рис.11.2. Выравнивание вправо при выводе на экран.
ОСНОВНЫЕ ПОЛОЖЕНИЯ НА ПАМЯТЬ
________________________________________________________________
- Для цепочечных команд MOVS, STOS, CMPS и SCAS не забывайте
инициализировать регистр ES.
- Сбрасывайте (CLD) или устанавливайте (STD) флаг направления в
соответствии с направлением обработки.
- Не забывайте устанавливать в регистрах DI и SI необходимые
значения. Например, команда MOVS предполагает операнды DI,SI, а команда
CMPS - SI,DI.
- Инициализируйте регистр CX в соответствии с количеством байтов или
слов, участвующих в процессе обработки.
- Для обычной обработки используйте префикс REP для команд MOVS и
STOS и модифицированный префикс (REPE или REPNE) для команд CMPS и SCAS.
- Помните об обратной последовательности байтов в сравниваемых cловах