Глава 11 команды обработки строк

__________

Ц е л ь: Объяснить назначение специальных цепочечных команд,

используемых для обработки символьных данных.

ВВЕДЕНИЕ

________________________________________________________________

Команды, показанные в предыдущих главах, оперировали одним байтом,

или одним словом за одно выполнение. Часто, однако, бывает необходимо

переслать или сравнить поля данных, которые превышают по длине одно слово.

Например, необходимо сравнить описания или имена для того, чтобы

отсортировать их в восходящей последовательности. Элементы такого формата

известны как строковые данные и могут являться как символьными, так и

числовыми. Для обработки строковых данных ассемблер имеет пять команд

обработки строк:

MOVS - переслать один байт или одно слово из одной области памяти в

другую;

LODS - загрузить из памяти один байт в регистр AL или одно слово в

регистр AX;

STOS - записать содержимое регистра AL или AX в память;

CMPS - сравнить содержимое двух областей памяти, размером в один байт

или в одно слово;

SCAS - сравнить содержимое регистра AL или AX с содержимым памяти.

Префикс REP позволяет этим командам обрабатывать строки любой длины.

СВОЙСТВА ОПЕРАЦИЙ НАД СТРОКАМИ

________________________________________________________________

Цепочечная команда может быть закодирована для повторяющейся

обpаботки одного байта или одного слова за одно выполнение. Например,

можно выбрать "байтовую" команду для обработки строки с нечетным числом

байт или "двухбайтовую" команду для обработки четного числа байт. Ниже

перечислены регистры, участвующие в цепочечных командах (для однобайтовых

и двухбайтовых вариантов). Предположим, что регистры DI и SI содержат

необходимые адреса:

Команда Операнды Байт Слово

MOVS DI,SI MOVSB MOVSW

LODS AL,SI или AX,SI LODSB LODSW

STOS DI,AL или DI,AX STOSB STOSW

CMPS SI,DI CMPSB CMPSW

SCAS DI,AL или DI,AX SCASB SCASW

Например, можно кодировать операнды для команды MOVS, но опустить их

для MOVSB и MOVSW. Эти команды предполагают, что pегистры DI и SI содержат

относительные адреса, указывающие на необходимые области памяти (для

загрузки можно использовать команду LEA). Регистр SI обычно связан с

регистром сегмента данных - DS:SI. Регистр DI всегда связан с регистром

дополнительного сегмента - ES:DI. Следовательно, команды MOVS, STOS, CMPS

и SCAS требуют инициализации регистра ES (обычно адресом в регистре DS).

REP: ПРЕФИКС ПОВТОРЕНИЯ ЦЕПОЧЕЧНОЙ КОМАНДЫ

________________________________________________________________

Несмотря на то, что цепочечные команды имеют отношение к одному байту

или одному слову, префикс REP обеспечивает повторение команды несколько

раз. Префикс кодируется непосредственно перед цепочечной командой,

например, REP MOVSB. Для использования префикса REP необходимо установить

начальное значение в регистре CX. При выполнении цепочечной команды с

префиксом REP происходит уменьшение на 1 значения в регистре CX до нуля.

Таким образом, можно обрабатывать строки любой длины.

Флаг направления определяет направление повторяющейся операции:

- для направления слева направо необходимо с помощью команды CLD

установить флаг DF в 0;

- для направления справа налево необходимо с помощью команды STD

установить флаг DF в 1.

В следующем примере выполняется пересылка 20 байт из STRING1 в

STRING2. Предположим, что оба регистра DS и ES инициализированы адресом

сегмента данных:

STRING1 DB 20 DUP('*')

STRING2 DB 20 DUP(' ')

...

CLD ;Сброс флага DF

MOV CX,20 ;Счетчик на 20 байт

LEA DI,STRING2 ;Адрес области "куда"

LEA SI,STRING1 ;Адрес области "откуда"

REP MOVSB ;Переслать данные

При выполнении команд CMPS и SCAS возможна установка флагов

состояния, так чтобы операция могла прекратиться сразу после обнаружения

необходимого условия. Ниже приведены модификации префикса REP для этих

целей:

REP - повторять операцию, пока CX не равно 0;

REPZ или REPE - повторять операцию, пока флаг ZF показывает "равно или

ноль". Прекратить операцию при флаге ZF, указывающему

на не равно или не ноль или при CX равном 0;

REPNE или REPNZ - повторять операцию, пока флаг ZF показывает "не равно

или не ноль". Прекратить операцию при флаге ZF,

указывающему на "равно или нуль" или при CX равным 0.

Для процессоров 8086, 80286 и 80386, обрабатывающих слово за oдно

выполнение, использование цепочечных команд, где это возможно, приводит к

повышению эффективности работы программы.

MOVS: ПЕРЕСЫЛКА СТРОК

________________________________________________________________

На рис.7.5 была показана программа для пересылки девятибайтового

поля. Программа включала три команды для инициализации и пять команд для

цикла. Команда MOVS с префиксом REP и длиной в регистре CX может выполнять

пересылку любого числа символов более эффективно.

Для области, принимающей строку, сегментным регистром, является

pегистр ES, а регистр DI содержит относительный адрес области, передающей

строку. Сегментным регистром является регистр DS, а регистр SI содержит

относительный адрес. Таким образом, в начале программы перед выполнением

команды MOVS необходимо инициализировать регистр ES вместе с регистром DS,

а также загрузить требуемые относительные адреса полей в регистры DI и SI.

В зависимости от состояния флага DF команда MOV S производит увеличение

или уменьшение на 1 (для байта) или на 2 (для слова) содержимого регистров

DI и SI.

Приведем команды, эквивалентные цепочечной команде REP MOVSB:

JCXZ LABEL2

LABEL1: MOV AL,[SI]

MOV [DI],AL

INC/DEC DI ;Инкремент или декремент

UNC/DEC SI ;Инкремент или декремент

LOOP LABEL1

LABEL2: ...

В программе на рис.11.1 процедура C10MVSB использует команду MOVSB

для пересылки содержимого десятибайтового поля NAME1 в поле NAME2. Первая

команда CLD сбрасывает флаг направления в 0 для обеспечения процесса

пересылки слева направо. В нормальном состоянии флаг DF обычно имеет

нулевое значение и команда CLD используется из предосторожности.

__________

page 60,132

TITLE STRING (EXE) Проверка строковых операций

; ---------------------------------------------------

STACKSG SEGMENT PARA STACK 'Stack'

DW 32 DUP(?)

STACKG ENDS

; ---------------------------------------------------

DATASG SEGMENT PARA 'Data'

NAME1 DB 'Assemblers' ;Элементы данных

NAME2 DB 10 DUP(' ')

NAME3 DB 10 DUP(' ')

DATASG ENDS

; ---------------------------------------------------

CODESG SEGMENT PARA 'Code'

BEGIN PROC FAR ;Основная процедура

ASSUME CS:CODESG,DS:DATASG,SS:STACKSG,ES:DATASG

PUSH DS

SUB AX,AX

PUSH AX

MOV AX,DATASG

MOV DS,AX

MOV ES,AX

CALL C10MVSB ;Подпрограмма MVSB

CALL D10MVSW ;Подпрограмма LODS

CALL E10LODS ;Подпрограмма LODS

CALL F10STOS ;Подпрограмма CMPS

CALL H10SCAS ;Подпрограмма SCAS

RET

BEGIN ENDP

; Использование MOVSB:

; -------------------

C10MVSB PROC NEAR

CLD

LEA SI,NAME1

LEA D1,NAME2

MOV CX,10 ;Переслать 10 байтов

REP MOVSB ; из NAME1 в NAME2

RET

C10MVSB ENDP

; Использование MOVSW:

; -------------------

D10MVSW PROC NEAR

CLD

LEA SI,NAME2

LEA DI,NAME3

MOV CX,05 ;Переслать 5 слов

REP MOVSW ; из NAME2 в NAME3

RET

D10MVSW ENDP

; Использование LODSW:

; -------------------

E10LODS PROC NEAR

CLD

LEA SI,NAME1 ;Загрузить первое слово

LODSW ; из NAME1 в AX

RET

E10LODS ENDP

; Использование STOSW:

; -------------------

F10STOS PROC NEAR

CLD

LEA D1,NAME3

MOV CX,05

MOV AX,2020H ;Переслать пробелы

REP STOSW ; в NAME3

RET

F10STOS ENDP

; Использование CMPSB:

; -------------------

G10CMPS PROC NEAR

CLD

MOV CX,10

LEA SI,NAME1

LEA DI,NAME2

REPE CMPSB ;Сравнить NAME1 и NAME2

JNE G20 ;Не равны?

MOV BH,01

G20: MOV CX,10

LEA SI,NAME2

LEA DI,NAME3

REPE CMPSB ;Сравнить NAME2 и NAME3

JE G30 ;Если равны, то выйти

MOV BL,02

G30: RET

G10CMPS ENDP

; Использование SCASB:

; -------------------

H10SCAS PROC NEAR

CLD

MOV CX,10

LEA DI,NAME1

MOV AL,'m' ;Поиск символа 'm'

REPNE SCASB ; в NAME1

JNE H20 ;Если не найден - выйти

MOV AH,03

H20: RET

H10SCAS ENDP

CODES ENDS

END BEGIN

__________

Рис.11.1. Использование цепочечных команд.

Две команды LEA загружают регистры SI и DI относительными адресами

NAME1 и NAME2 соответственно. Так как регистры DS и ES были ранее

инициализированы адресом DATASG, то полные адреса полей NAME1 и NAME2

будут в регистрах ES:DI и DS:SI. (COM программа автоматически

инициализирует регистры ES и DS). Команда MOV заносит в регистр CX

значение 10 - длину полей NAME1 и NAME2. Команда REP MOVSB выполняет

следующее:

- Пересылает самый левый байт из поля NAME1 (адресованного

pегистрами ES:DI) в самый левый байт поля NAME2 (адресованного

регистрами DS:SI).

- Увеличивает на 1 адреса в регистрах DI и SI для следующего

байта.

- Уменьшает CX на 1.

- Повторяет перечисленные действия (в данном случае 10 раз),

пока содержимое регистра CX не станет равным нулю.

Поскольку флаг DF имеет нулевое значение, команда MOVSB увеличивает

адреса в регистрах DI и SI, и в каждой итерации процесс переходит на байт

вправо, т.е. пересылает байт из NAME1+1 в NAME2+1 и т.д. Если бы флаг DF

был равен 1, тогда команда MOVSB уменьшала бы адреса в регистрах DI и SI,

выполняя процесс справа налево. Но в этом случае регистры SI и DI

необходимо инициализировать адресами последних байтов полей, т.е. NAME1+9

и NAME2+9 соответственно.

В процедуре D10MVSW (рис.11.1) используется команда MOVSW,

пересылающая одно слово за одно выполнение. Так как команда MOVSW

увеличивает адреса в регистрах DS и SI на 2, операция требует только пять

циклов. Для процесса пересылки справа налево регистр SI должен быть

инициализирован адресом NAME1+8, а регистр DI - NAME2+8.

LODS: ЗАГРУЗКА СТРОКИ

________________________________________________________________

Команда LODS загружает из памяти в регистр AL один байт или в регистр

AX одно слово. Адрес памяти определяется регистрами DS:SI. В зависимости

от значения флага DF происходит увеличение или уменьшение регистра SI.

Поскольку одна команда LODS загружает регистр, то практической пользы

от префикса REP в данном случае нет. Часто простая команда MOV полностью

адекватна команде LODS, хотя MOV генерирует три байта машинного кода, а

LODS - только один, но требует инициализацию регистра SI. Можно

использовать команду LODS в том случае, когда требуется продвигаться вдоль

строки (по байту или по слову), проверяя загружаемый регистр на конкретное

значение.

Команды, эквивалентные команде LODSB:

MOV AL,[SI]

INC SI

На рис.11.1 процедура E10LODS демонстрирует использование команды

LODSW. В примере обрабатывается только одно слово: первый байт из области

NAME1 (содержащий As) заносится в регистр AL, а второй байт - в регистр

AH. В результате в регистре AX получится значение sA.

STOS: ЗАПИСЬ СТРОКИ

________________________________________________________________

Команда STOS записывает (сохраняет) содержимое регистра AL или AX в

байте или в слове памяти. Адрес памяти всегда представляется регистрами

ES:DI. В зависимости от флага DF команда STOS также увеличивает или

уменьшает адрес в регистре DI на 1 для байта или на 2 для слова.

Практическая польза команды STOS с префиксом REP - инициализация

области данных конкретным значением, например, очистка дисплейного буфера

пробелами. Длина области (в байтах или в cловах) загружается в регистр AX.

Команды, эквивалентные команде REP STOSB:

JCXZ LABEL2

LABEL1: MOV [DI],AL

INC/DEC DI ;Инкремент или декремент

LOOP LABEL1

LABEL2: ...

На рис.11.1 процедура F10STOS демонстрирует использование команды

STOSW. Операция осуществляет запись шест. 2020 (пробелы) пять раз в

область NAME3, причем значение из регистра AL заносится в первый байт, а

из регистра AH - во второй. По завершении команды регистр DI содержит

адрес NAME3+10.

CMPS: СРАВНЕНИЕ СТРОК

________________________________________________________________

Команда CMPS сравнивает содержимое одной области памяти (адресуемой

регистрами DS:SI) с содержимыми другой области (адресуемой как ES:DI). В

зависимости от флага DF команда CMPS также увеличивает или уменьшает

адреса в регистрах SI и DI на 1 для байта или на 2 для слова. Команда CMPS

устанавливает флаги AF, CF, OF, PF, SF и ZF. При использовании префикса

REP в регистре CX должна находиться длина сравниваемых полей. Команда CMPS

может сравнивать любое число байт или слов.

Рассмотрим процесс сравнения двух строк, содержащих имена JEAN и

JOAN. Сравнение побайтно слева направо приводит к следующему:

J : J Равно

E : O Не равно (E меньше O)

A : A Равно

N : N Равно

Сравнение всех четырех байт заканчивается сравнением N:N -

pавно/нуль. Так как имена "не равны", операция должна прекратиться, как

только будет обнаружено условие "не равно". Для этих целей команда REP

имеет модификацию REPE, которая повторяет сравнение до тех пор, пока

сравниваемые элементы равны, или регистр CX не pавен нулю. Кодируется

повторяющееся однобайтовое сравнение следующим образом:

REPE CMPSB

На рис.11.1 в процедуре G10CMPS имеются два примера использования

команды CMPSB. В первом примере происходит сравнение содержимого полей

NAME1 и NAME2. Так как ранее команда MOVSB переслала содержимое поля NAME1

в поле NAME2, то команда CMPSB продолжается на всех десяти байтах и

завершается состоянием pавно/нуль: флаг SF получает значение 0

(положительно) и флаг ZF - 1(нуль).

Во втором примере сравнивается поля NAME2 и NAME3. Ранее команда

STOSW заполнила поле NAME3 пробелами, поэтому команда CMPB завершается

после сравнения первых же байт с результатом "больше/неравно": флаг SF

получает значение 0 (положительно) и флаг ZF - 0 (не нуль).

Первый пример заканчивается с результатом "равно/нуль" и заносит 01 в

регистр BH. Второй пример заканчивается с результатом "неравно" и заносит

02 в регистр BL. При трассировке команд с помощью отладчика DEBUG можно

увидеть, что в конце процедуры G10CMPS регистр BX будет содержать значение

0102.

Предупреждение! Показанные примеры используют команду CMPSB для

сравнения одного байта за одно выполнение. При использовании команды CMPSW

для сравнения одного слова, необходимо инициализиpовать регистр CX

значением 5. Кроме того следует помнить, что команда CMPSW при сравнении

слов переставляет байты. Например, сравнивая имена SAMUEL и ARNOLD команда

CMPSW выбирает вместо SA и AR переставленные значения, т.е. AS и RA. В

результате вместо "больше" получится "меньше", т.е. неправильный

результат. Таким образом команда CMPSW работает правильно только при

сравнении строк, которые содержат числовые данные, определенные как 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ловах

при выполнении команд CMPSW и SCASW.

- При обработке справа налево устанавливайте начальные адреса на

последний байт обрабатываемой области. Если, например, поле NAME1 имеет

длину 10 байтов, то для побайтовой обработки данных в этой области справа

налево начальный адрес, загружаемый командой LEA, должен быть NAME1+9. Для

обработки слов начальный адрес в этом случае - NAME1+8.

ВОПРОСЫ ДЛЯ САМОПРОВЕРКИ

________________________________________________________________

11.1. В данной главе приведены эквивалентные команды для а) MOVSB, б)

LODSB и в) STOSB с префиксом REP. Напишите эквивалентные команды для

обработки по словам а) MOVSW, б) LODSW и в) STOSW с префиксом REP.

11.2. Введите, ассемблируйте и выполните компоновку программы,

приведенной на рис.11.1. Не забудьте о инициализации регистра ES. Замените

команды MOVSB и MOVSW для пересылки справа налево. Измените процедуру

H10SCAS для сканирования поля NAME1 на слово "mb". Используя отладчик

DEBUG для трассировки процедур, обратите внимание на содержимое сегмента

данных и регистров.

11.3. Имеются следующие определения:

DATASG SEGMENT PARA

CONAME DB 'SPACE EXPLORERS INC.'

PRLINE DB 20 DUP(' ')

Используя цепочечные команды, выполните:

а) пересылку данных из CONAME в PRLINE слева направо;

б) пересылку данных из CONAME в PRLINE справа налево;

в) загрузку третьего и четвертого байтов области CONAME в регистр AX;

г) сохранение содержимого регистра AX в область по адресу PRLINE+5;

д) сравнение данных в областях CONAME и PRLINE (они должны быть не

равны);

е) сканирование областей CONAME и PRLINE, и поиск в ней символа

пробел. Если символ будет найден, то переслать его в регистр BH.

11.4. Переделайте процедуру H10SCAS (рис.11.1) так, чтобы выполнялось

сканирование поля NAME1 на символ "er". Обратите внимание, что символы

"er" не встречаются в поле NAME1 как одно слово: /As/se/mb/le/rs/. Для

решения этой проблемы возможны два варианта:

а) использовать команду SCASW дважды, причем первая должна начинаться

по адресу NAME1, а вторая - по адресу NAME1+1;

б) использовать команду SCASB для поиска символа "е" и сравнить затем

следующий байт на символ "r".

11.5. Определите поле, содержащее шест. значения 03, 04, 05 и B4.

Продублируйте это поле 20 раз и выдайте результат на экран.

Наши рекомендации