Команды обработки строк

Рассмотренных групп команд вполне достаточно для реализации алгоритмов обработки строк. Однако система команда микропроцессора 8086 имеет специальные команды, т.к. они позволяют выполнить операцию сразу над всей строкой.

Во всех строковых командах под строкой понимается последовательность байтов (символов) или последовательность слов. Поэтому каждая команда представлена двумя вариантами – для обработки строк из байтов и из слов. Мнемокоды команд различаются только последней буквой – B (Byte) или W (Word) соответственно.

Команда CMPS(сравнение строк) сравнивает между собой байты или слова источника и приёмника (табл. 53). Флаги устанавливаются в соответствии с результатами выполнения операции сравнения. Оба операнда должны быть расположены в памяти. Адрес источника задаётся регистровой парой DS:SI, адрес приёмника – ES:DI. Сегментный регистр DS может быть заменён другим сегментным регистром с помощью префикса замены сегмента. Сегментный регистр ES не может быть заменён другим.

 

 

Табл. 53. Команда CMPS.

Код Инструкция Описание
A6 CMPSB Сравнение байтов [DS:SI] и [ES:DI].
A7 CMPSW Сравнение слов [DS:SI] и [ES:DI].

 

 

После выполнения операции содержимое регистров SI и DI автоматически увеличивается или уменьшается на размер операнда, т.е. на 1 или на 2 байта. Увеличение (инкремент) имеет место, если флаг направления DF в регистре флагов сброшен, а уменьшение (декремент) – если флаг DF установлен. Изменить флаг направления можно с помощью команд CLD и STD (см. раздел 5.11).

Сравнение, как и в команде CMP, выполняется вычитанием значения приёмника из значения источника. Эти значения рассматриваются как двоичные числа со знаком. Результат вычитания не сохраняется, и исходные операнды не изменяются. По результатам вычитания устанавливаются соответствующие признаки в регистре флагов. Инструкция CMPS выполняет сравнение только одной пары байтов или слов.

Рассмотрим пример сравнения двух байтовых строк A и B. Предположим, строка A расположена в сегменте данных DS, а строка B – в дополнительном сегменте ES. Длина обеих строк одинакова и равна N. Для организации побайтного сравнения от начала к концу строк необходимо сбросить флаг DF и организовать цикл. В регистр счетчика следует поместить число N, а выход из цикла выполнять по условию JNE.

 

CLD ; DF=0 просмотр вперед

LEA SI, A ; DS:SI = начало A

LEA DI, B ; ES:DI = начало B

MOV CX, N ; CX = длина строки

L: CMPSB ; сравнение пары символов

JNE L1 ; выход по метке L1, если A<>B

LOOP L ; переход к проверке следующей пары

... ; A=B

L1:... ; A<>B

 

Команда CMPSBсама изменяет значения индексных регистров SI и DI. Однако система команд предоставляет дополнительные средства, еще упрощающие приведенную конструкцию с помощью специальных префиксов повторения REP/REPxx (табл. 54). Префикс повторения обеспечивает многократное повторение одной и той же операции до обнуления счётчика или до выполнения заданного условия.

 

 

Табл. 54. Префикс повторения REP.

Код Инструкция Описание
F3 A4 REP MOVSB Пересылка CX байтов из DS:SI в ES:DI.
F3 A5 REP MOVSW Пересылка CX слов из DS:SI в ES:DI.
F3 AC REP LODSB Загрузка CX байтов из DS:SI в AL.
F3 AD REP LODSW Загрузка CX слов из DS:SI в AX.
F3 AA REP STOSB Запись CX байтов из AL в ES:DI.
F3 AB REP STOSW Запись CX слов из AX в ES:DI.
F3 A6 REPE CMPSB Сравнение CX байтов в DS:SI и ES:DI до несовпадения.
F3 A7 REPE CMPSW Сравнение CX слов в DS:SI и ES:DI до несовпадения.
F3 AE REPE SCASB Поиск байта, отличающегося от AL, в CX байтах в ES:DI.
F3 AF REPE SCASW Поиск слова, отличающегося от AX, в CX словах в ES:DI.
F2 A6 REPNE CMPSB Сравнение CX байтов в DS:SI и ES:DI до совпадения.
F2 A7 REPNE CMPSW Сравнение CX слов в DS:SI и ES:DI до совпадения.
F2 AE REPNE SCASB Поиск байта, совпадающего с AL, в CX байтах в ES:DI.
F2 AF REPNE SCASW Поиск слова, совпадающего с AX, в CX словах в ES:DI.

 

 

Счётчик должен находиться в регистре CX. После каждого выполнения инструкции, совместно с префиксом повторения, содержимое CX уменьшается на единицу и проверяется на равенство нулю. Инструкция повторяется до тех пор, пока в результате вычитания содержимое CX не обнулится. Помимо завершения операции по обнулению счётчика, в некоторых инструкциях предусмотрено её завершение при равенстве или неравенства флага ZF нулю.

Существует три разновидности префикса повторения, которым соответствует пять мнемоник:

- Префикс простого повторения REP (код операции F3). Операция заканчивается, при обнулении содержимого регистра CX.

- Префикс повторения, пока соблюдается равенство REPE/REPZ (код операции F3). Операция заканчивается, при обнулении содержимого регистра CX или сбросе флаг ZF.

- Префикс повторения, пока равенство не соблюдается REPNE/REPNZ (код операции F2). Операция заканчивается, при обнулении содержимого регистра CX или установлении флага ZF.

В синтаксисе языка Паскаль действие префиксов REPE/REPZ/REP можно записать так:

 

L: if CX = 0 then goto L1;

CX:=CX-1;

{ строковая команда }

if ZF = 1 then goto L;

L1:...

 

Действие префиксов REPNE/REPNZ отличается проверкой флага нуля ZF = 0. С инструкциями MOVS, LODS и STOS может применяться только обычный префикс повторения REP. Когда он используется, операция продолжает выполняться до тех пор, пока регистр CX не обнулится.

С инструкциями CMPS и SCAS используются префиксы REPE/REPZ и REPNE/REPNZ. Первый префикс обеспечивает прекращение операции при обнулении счётчика или при сбросе флага ZF (при обнаружении неравенства сравниваемых байтов или слов). Второй префикс обеспечивает прекращение операции при обнулении счётчика или при установке флага ZF (при обнаружении равенства сравниваемых байтов или слов).

Пример сравнения двух строк с помощью префикса повторения REPE может быть записан в более компактной форме:

 

CLD ; DF=0 просмотр вперед

LEA SI, A ; DS:SI = начало A

LEA DI, B ; ES:DI = начало B

MOV CX, N ; CX = длина строки

REPE CMPSB ; сравнивать пары символов, пока элементы равны (пока ZF=1)

JE L ; выход по метке L, если A = B (ZF=1)

... ; A<>B (ZF=0)

 

Команда SCAS(сканирование строки) производит поиск байта или слова, содержащегося в регистре AL или AX, в строке по адресу ES:DI (табл. 55). Сегментный регистр ES не может быть заменён другим сегментным регистром с помощью префикса замены сегмента. Флаги изменяются в соответствии с результатами выполнения сравнения. После загрузки байта или слова в аккумулятор содержимое регистра DI увеличивается (DF=0) или уменьшается (DF=1) на 1 или 2 в зависимости от размера операнда.

 

 

Табл. 55. Команда SCAS.

Код Инструкция Описание
AE SCASB Поиск байта AL в [ES:DI].
AF SCASW Поиск слова AX в [ES:DI].

 

 

Рассмотрим простой пример поиска в байтовой строке A размерностью N символа точки. Для выполнения поиска следует использовать префикс REPNE. Если символ входит в строку, после выхода из цикла флаг ZF будет установлен, а регистр DI будет содержать номер символа, следующего за первым вхождением искомого символа в строку. В примере сегментный регистр ES уже настроен на начало сегмента данных DS.

 

CLD ; просмотр вперед

LEA DI, A ; ES:DI = начало A

MOV CX, N ; CX = длина строки

MOV AL, 2Eh ; ASCII-код «точки» (искомый символ)

REPNE SCASB ; поиск первого вхождения символа в строку

JNE L ; символ не найден, переход по метке L (ZF=0)

DEC DI ; порядковый номер искомого символа

MOV DL, DI ; сохранение номера символа в DL

L:...

 

Команда MOVS(пересылка строк) пересылает операнд-источник на место операнда-приёмника (табл. 56). Флаги команда не изменяет. Оба операнда должны находиться в памяти. Адрес источника задаётся регистровой парой DS:SI, адрес приёмника – ES:DI. Сегментный регистр DS может быть заменён другим сегментным регистром с помощью префикса замены сегмента. Сегментный регистр ES не может быть заменён другим.

После выполнения операции содержимое регистров SI и DI автоматически увеличивается (DF=0) или уменьшается (DF=1) на 1 или 2 в зависимости от размера операнда. За одно выполнение инструкции пересылается один байт или одно слово. Группа байтов или слов может быть передана с помощью префикса повторения REP.

 

 

Табл. 56. Команда MOVS.

Код Инструкция Описание
A4 MOVSB Пересылка байта из [DS:SI] в [ES:DI].
A5 MOVSW Пересылка слова из [DS:SI] в [ES:DI].

 

 

Команда MOVS удобна при переносе данных из одной области памяти в другую. Например, если определены два байтовых массива размерностью N:

 

X DB N DUP(?)

Y DB N DUP(?)

 

и требуется передать содержимое массива Y в X, то можно записать:

 

CLD ; просмотр вперед

LEA SI, Y ; DS:SI=начало Y

MOV AX, DS

POP ES, AX ; устанавливаем ES на сегмент данных DS

LEA DI, X ; ES:DI=начало X

MOV CX, N ; объем пересылаемой области

REP MOVSB ; выполнение операции

 

Команда STOS(запись строки) записывает содержимое регистра AL или AX по адресу ES:DI (табл. 57). Флаги команда не изменяет. Операнд-приёмник находится в памяти по адресу, содержащемуся в регистровой паре ES:DI. Сегментный регистр ES не может быть заменён другим. Операндом-источником всегда является регистр AL или AX. После записи байта или слова из аккумулятора в память содержимое регистра DI увеличивается (DF=0) или уменьшается (DF=1) на 1 или 2 в зависимости от размера операнда.

 

 

Табл. 57. Команда STOS.

Код Инструкция Описание
AA STOSB Запись байта из AL в [ES:DI].
AB STOSW Запись слова из AX в [ES:DI].

 

 

С командой STOS можно использовать префикс повторения REP для инициализации области памяти некоторой величиной. Например, для заполнения пробелами строки S размерностью N можно записать (регистр ES должен быть предварительно настроен на DS):

 

CLD ; просмотр вперед

MOV AL, 20h ; ASCII-код пробела

MOV CX, N ; количество символов

LEA DI, S ; ES:DI = начало S

REP STOSB ; выполнение операции

 

 

Команда LODS(загрузка строки) загружает в регистр AL или AX байт или слово по адресу DS:SI (табл. 58). Флаги команда не изменяет. Операнд-источник должен находиться в памяти по адресу, содержащемуся в регистровой паре DS:SI. Сегментный регистр DS может быть заменён другим сегментным регистром с помощью префикса замены сегмента. Операндом-приёмником всегда является регистр AL или AX. После загрузки байта или слова в аккумулятор содержимое регистра SI увеличивается (DF=0) или уменьшается (DF=1) на 1 или 2 в зависимости от размера операнда.

 

 

Табл. 58. Команда LODS.

Код Инструкция Описание
AC LODSB Загрузка байта из [DS:SI] в AL.
AD LODSW Загрузка слова из [DS:SI] в AX.