Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Абель.docx
Скачиваний:
13
Добавлен:
26.11.2018
Размер:
569.84 Кб
Скачать

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 ; нет -