В обработке макрокоманд применяется одно из ценных свойств
процедур: в генерацию макрокоманды можно вносить изменения с
помощью параметров. Точно так же, как параметры подпрограммы могут
влиять на ее выполнение, параметры макрокоманды определяют
фактически генерируемые команды. И так же, как и процедуры,
макрокоманды без параметров встречаются относительно редко.
Рассмотрим еще один простой пример. Мы составили программу так,
что во многих ее местах содержимое определенной ячейки памяти
складывается с различными константами. Вместо того, чтобы много раз
писать команду
ADD MEMORY_BYTE,5
или
ADD MEMORY_BYTE,7
нам хотелось бы воспользоваться для нее соответствующей
макрокомандой. Однако во всех приведенных командах константы
разные. Поэтому мы сделаем константу параметром макрокоманды. На
Фиг. 6.2 показаны определение и применение макрокоманды ADDBYTE. В
этом примере в качестве параметра в определении макрокоманды
используется символическое имя CONSTANT. Любые символичесике имена,
появляющиеся в поле операнда оператора MACRO, интерпретируются как
параметры. В момент определения макрокоманды у имени CONSTANT нет
никакого значения: оно просто резервирует место в тексте
макрокоманды. Позднее, при вызове и обработке текста макрокоманды,
вместо символического имени в определении макрокоманды
подставляется определенное значение параметра.
Важно отметить, что параметр макрокоманды - это текстовый
параметр. Так как макропроцессор фактически является текстовым
процессорорм, то он не отличает цифры от букв и наоборот. Это
позволяет при вызове макрокоманды использовать вместо чисел
символические имена. Любой смысл приписывается символьной строке не
макропроцессором, а ассемблером. Макропроцессор подставляет
Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:02:43
Фиг. 6.2 Макрокоманда с аргументом Page 1-1
PAGE ,132
TITLE Фиг. 6.2 Макрокоманда с аргументом
ADDBYTE MACRO CONSTANT
ADD MEMORY_BYTE, CONSTANT
ENDM
0000 CODE SEGMENT
ASSUME CS:CODE
0000 ?? MEMORY_BYTE DB ?
= 0004 FOUR EQU 4 ; Симвользое изображение константы
ADDBYTE 2
0001 2E: 80 06 0000 R 02 1 ADD MEMORY_BYTE, 2
ADDBYTE 4
0007 2E: 80 06 0000 R 04 1 ADD MEMORY_BYTE, 4
ADDBYTE FOUR
000D 2E: 80 06 0000 R 04 1 ADD MEMORY_BYTE, FOUR
0013 CODE ENDS
END
Фиг. 6.2 Аргументы макрокоманды
текстовую строку из вызова макрокоманды на место символического
имени в определении макрокоманды. Таким образом программа может
использовать константное значение "FOUR" с тем же успехом, что и
константу "4".
Возможность использовать символические имена в качестве
параметров макрокоманд принципиально важна для следующего примера
макрокоманды. Этой макрокоманда, одной из команд сопроцессора 8087,
требуется параметр, который при обычном ее использовании почти
всегда бывает символическим именем. Макрокоманда FLDCW - это
команда сопроцессора 8087, которая задает ячейку памяти. Так как в
программах на языке ассемблера в большинстве случаев обращаются к
ячейкам памяти с помощью символических имен, то желательно
сохранить этот способ и для программирования сопроцессора 8087.
На Фиг.6.3 приводится макрокоманда FLDCW и несколько обрашений
к ней. Заметьте, что макрокоманда FLDCW использует в качестве
параметра символическое имя "SOURCE". Параметр SOURCE является
адресом, с которого сопроцессор 8087 загружает управляющее слово.
Для генерации требуемого машинного кода макрокоманда FLDCW
использует команду 8088 ESC. Однако для того, чтобы определить байт
mod=r/m команды, команде ESC требуется значение адреса. Как раз для
Microsoft (R) Macro Assembler Version 5.00 1/1/80 04:02:47
Фиг. 6.3 Макрокоманда для команды FLDCW Page 1-1
PAGE ,132
TITLE Фиг. 6.3 Макрокоманда для команды FLDCW
FLDCW MACRO SOURCE
DB 09BH
ESC 0DH, SOURCE
ENDM
0000 CODE SEGMENT
ASSUME CS:CODE
0000 ???? MEMORY_LOCATION DW ?
FLDCW MEMORY_LOCATION
0002 9B 1 DB 09BH
0003 2E: D9 2E 0000 R 1 ESC 0DH, MEMORY_LOCATION
FLDCW ES:[DI]
0008 9B 1 DB 09BH
0009 26: D9 2D 1 ESC 0DH, ES:[DI]
FLDCW MEMORY_LOCATION[BX+SI]
000C 9B 1 DB 09BH
000D 2E: D9 A8 0000 R 1 ESC 0DH, MEMORY_LOCATION[BX+SI]
0012 CODE ENDS
END
Фиг. 6.3. Макрокомнда FLDCW
этого макрокоманда и использует параметр SOURCE. Такая организация
макрокоманды FLDCW позволяет программировать весьма естественным
способом. Точно так же как пишется
INC MEMORY_LOCATION
вы можно написать команду для сопроцессора 8087
FLDCW MEMORY_LOCATION
Это справедливыо не только для адресов, заданных символическими
именами, но и для других способов адресации. На Фиг. 6.3 показано
несколько примеров задания операнда с помощью адресации по базе и
индексу. Так как макропроцессор воспринимает параметр как какой-то
фрагмент текста, то параметр может быть образован любой символьной
строкой, какую вы пожелаете.
Можно задать макрокоманду и с несколькими параметрами.
Единственное, что ограничивает число параметров макрокоманды, это
длина ассемблерной строки. Все, что следует за оператором MACRO
интерпретируется макропроцессором как параметр. Для разделения
символических имен в определении макрокоманды пользуются запятыми.
Оператор MACRO с тремя параметрами будет выглядеть следующим
образом:
EXAMPLE MACRO ARG1, ARG2, ARG3
Аналогично, при вызове макрокоманды вы должны задать значение
каждого из параметров. Если вы хотите пропустить какой-то параметр,
то ассемблер подставит вместо него символьную строку нулевой длины.
Иногда это полезно, но часто приводит к неправильной трансляции.
Если макрокоманда имеет более одного параметра, то при вызове
макрокоманды относящийся к параметрам текст разделяется запятыми.
Это в точности совпадает со способом задания нескольких параметров
к любой из команд микропроцессора 8088, поэтому будет вполне
естественным для вас. Вызов макрокоманды с тремя параметрами может
выглядеть так:
EXAMPLE 5, [BX], MEMORY_BYTE
В следующем примере вы увидите некоторые возможности множествен-
ности параметров.