6.2. Аргументы макрокоманд

В обработке макрокоманд применяется одно из ценных свойств процедур: в генерацию макрокоманды можно вносить изменения с помощью параметров. Точно так же, как параметры подпрограммы могут влиять на ее выполнение, параметры макрокоманды определяют фактически генерируемые команды. И так же, как и процедуры, макрокоманды без параметров встречаются относительно редко.

Рассмотрим еще один простой пример. Мы составили программу так, что во многих ее местах содержимое определенной ячейки памяти складывается с различными константами. Вместо того, чтобы много раз писать команду

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:00:28
Фиг. 6.2 Макрокоманда с аргументом                              Page  1-1
PAGE ,132

                         TITLE    Фиг. 6.2 Макрокоманда с аргументом
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:00:28
Фиг. 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

В следующем примере вы увидите некоторые возможности множественности параметров.