В обработке макрокоманд применяется одно из ценных свойств процедур: в генерацию макрокоманды можно вносить изменения с помощью параметров. Точно так же, как параметры подпрограммы могут влиять на ее выполнение, параметры макрокоманды определяют фактически генерируемые команды. И так же, как и процедуры, макрокоманды без параметров встречаются относительно редко.
Рассмотрим еще один простой пример. Мы составили программу так, что во многих ее местах содержимое определенной ячейки памяти складывается с различными константами. Вместо того, чтобы много раз писать команду
или
нам хотелось бы воспользоваться для нее соответствующей макрокомандой. Однако во всех приведенных командах константы разные. Поэтому мы сделаем константу параметром макрокоманды. На Фиг. 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 позволяет программировать весьма естественным способом. Точно так же как пишется
вы можно написать команду для сопроцессора 8087
Это справедливыо не только для адресов, заданных символическими именами, но и для других способов адресации. На Фиг. 6.3 показано несколько примеров задания операнда с помощью адресации по базе и индексу. Так как макропроцессор воспринимает параметр как какой-то фрагмент текста, то параметр может быть образован любой символьной строкой, какую вы пожелаете.
Можно задать макрокоманду и с несколькими параметрами. Единственное, что ограничивает число параметров макрокоманды, это длина ассемблерной строки. Все, что следует за оператором MACRO интерпретируется макропроцессором как параметр. Для разделения символических имен в определении макрокоманды пользуются запятыми. Оператор MACRO с тремя параметрами будет выглядеть следующим образом:
Аналогично, при вызове макрокоманды вы должны задать значение каждого из параметров. Если вы хотите пропустить какой-то параметр, то ассемблер подставит вместо него символьную строку нулевой длины. Иногда это полезно, но часто приводит к неправильной трансляции. Если макрокоманда имеет более одного параметра, то при вызове макрокоманды относящийся к параметрам текст разделяется запятыми. Это в точности совпадает со способом задания нескольких параметров к любой из команд микропроцессора 8088, поэтому будет вполне естественным для вас. Вызов макрокоманды с тремя параметрами может выглядеть так:
В следующем примере вы увидите некоторые возможности множественности параметров.