Макроопределение может содержать ссылку на другое макроопределение.
Рассмотрим простое макроопределение dos21, которое заносит в регистр ah номер функции dos и выполняет int 21h:
dos21 macro dosfunc
mov ah,dosfunc
int 21h
endm
Для использования данной макрокоманды при вводе с клавиатуры необходимо закодировать:
lea dx,namepar
dos21 0ah
Предположим, что имеется другое макроопределение, использующее функцию 02 в регистре ah для вывода символа:
disp macro char
mov ah,02
mov dl,char
int 21h
endm
Для вывода на экран, например, звездочки достаточно закодировать макрокоманду disp '*'. Можно изменить макроопределение disp, воспользовавшись макрокомандой dos21:
disp macro char
mov dl,char
dos21 02
endm
Теперь, если закодировать макрокоманду disp в виде disp '*', то ассемблер сгенерирует следующие команды:
mov dl,'*'
mov ah,02
int 21h
Директива local.
В некоторых макрокомандах требуется определять элементы данных или метки команд. При использовании такой макрокоманды в программе более одного раза происходит также неоднократное определение одинаковых полей данных или меток. В результате ассемблер выдаст сообщения об ошибке из-за дублирования имен. Для обеспечения уникальности генерируемых в каждом макрорасширении имен используется директива local, которая кодируется непосредственно после директивы macro, даже перед комментариями. Общий формат имеет следующий вид:
local dummy-1,dummy-2,;Формальные параметры
(слайд №15)
Использование библиотеки макроопределений.
Определение таких макрокоманд, как INIT1 и INIT2 и одноразовое их использование в программе кажется бессмысленным. Лучшим подходом здесь является каталогизация собственных макрокоманд в библиотеке, используя любое описательное имя, например, MACRO.LIB:
INIT MACRO CSNAME,DSNAME,SSNAME
.
.
ENDM
PROMPT MACRO MESSGE
.
.
ENDM
Теперь для использования любой из каталогизированных макрокоманд вместо MACRO определения в начале программы следует применять директиву INCLUDE:
INCLUDE <путь>MACRO.LIB
.
.
INIT CSEG,DATA,STACK
В этом случае ассемблер обращается к файлу MACRO.LIB (в нашем примере) по указанному пути и включает в программу оба макроопределения INIT и PROMPT.
Хотя в нашем примере требуется только INIT. Ассемблерный листинг будет содержать копию макроопределения
Так как транслятор с ассемблера является двухпроходовым, то для обеспечения обработки директивы INCLUDE только в первом проходе (а не в обоих) можно использовать следующую конструкцию:
IF1
INCLUDE <путь>MACRO.LIB
ENDIF
IF1 и ENDIF являются условными директивами. Директива IF1 указывает ассемблеру на необходимость доступа к библиотеке только в первом проходе трансляции. Директива ENDIF завершает IF-логику. Таким образом, копия макроопределений не появится в листинге - будет сэкономлено и время и память.
Расположение директивы INCLUDE не критично, но она должна появиться ранее любой макрокоманды из включаемой библиотеки.
(слайд №16)
Директива очистки.
Директива INCLUDE указывает ассемблеру на включение всех макроопределений из специфицированной библиотеки. Например, библиотека содержит макросы INIT, PROMPT и DIVIDE, хотя программе требуется только INIT. Директива PURGE позволяет "удалить" нежелательные макросы PROMPT и DIVIDE в текущем ассемблировании:
IF1
INCLUDE <путь>MACRO.LIB;Включить всю библиотеку
ENDIF
PURGE PROMRT,DIYIDE;Удалить ненужные макросы
...
INIT CSEG,DATA,STACK;Использование оставшейся макрокоманды
Директива PURGE действует только в процессе ассемблирования и не оказывает никакого влияния на макрокоманды, находящиеся в библиотеке.
Конкатенация (&).
Символ амперсанд (&) указывает ассемблеру на сцепление (конкатенацию) текста или символов. Следующая макрокоманда MOVE генерирует команду MOVSB или MOVSW:
MOVE MACRO TAG
REP MOVS&TAG
ENDM
Теперь можно кодировать макрокоманду в виде MOVE B или MOVE W. В результате макрорасширения ассемблер сцепит параметр с командой MOVS и получит REP MOVSB или REP MOVSW.
Директивы повторения: REPT, IRP, IRPC.
Директивы повторения заставляют ассемблер повторить блок операторов, завершаемых директивой ENDM. Эти директивы не обязательно должны находиться в макроопределении, но если они там находятся, то одна директива ENDM требуется для завершения повторяющегося блока, а вторая ENDM – для завершения макроопределения.
(слайд №17)
REPT: Повторение.
Операция REPT приводит к повторению блока операторов до директивы ENDM в соответствии с числом повторений, указанным в выражении:
REPT выражение
В следующем примере происходит начальная инициализация значения N=0 и затем повторяется генерация db n пять раз:
n = 0
rept 5
n = n + 1
db n
endm
В результате будут сгенерированы пять операторов db от db 1 до db 5. Директива rept может использоваться таким образом для определения таблицы или части таблицы. Другим примером может служить генерация пяти команд movsb, что эквивалентно rep movsb при содержимом cx равном 05:
rept 5
movsb
endm
IRP: Неопределенное повторение.
Операция IRP приводит к повторению блока команд до директивы endm. Основной формат:
IRP dummy,
Аргументы, содержащиеся в угловых скобках, представляют собой любое число правильных символов, строк, числовых или арифметических констант.
Ассемблер генерирует блок кода для каждого аргумента. В следующем примере ассемблер генерирует DB 3, DB 9, DB 17, DB 25 и DB 28:
IRP N,<3, 9, 17, 25, 28>
DB N
ENDM
IRPC: Неопределенное повторение символа.
Операция IRPC приводит к повторению блока операторов до директивы ENDM. Основной формат:
IRPC dummy,string
Ассемблер генерирует блок кода для каждого символа в строке "string". В следующем примере ассемблер генерирует DW 3, DW 4... DW 8:
IRPC N,345678
DW N
ENDM
(слайд №18)
Условные директивы.
Ассемблер поддерживает ряд условных директив. Условные директивы наиболее полезны внутри макроопределений, но не ограничены только этим применением. Каждая директива IF должна иметь спаренную с ней директиву ENDIF для завершения IF-логики и возможную директиву ELSE для альтернативного действия:
IFxx (условие)
.
.
ELSE (не обязательное действие)
.
.
ENDIF (конец IF-логики)
Обработка данных директив макроассемблером заключается в вычислении логического выражения – условия и включения в объектный модуль либо блок до директивы ELSE, если условие истинно, либо блок до директивы ENDIF, если условие ложно.
Отсутствие директивы ENDIF вызывает сообщение об ошибке: "Undeterminated conditional" (незавершенный условный блок). Если проверяемое условие истинно, то ассемблер выполняет условный блок до директивы ELSE или при отсутствии ELSE - до директивы ENDIF. Если условие ложно, то ассемблер выполняет условный блок после директивы ELSE, а при отсутствии ELSE вообще обходит условный блок.
(слайд №19)
Ниже перечислены различные условные директивы:
IF выражение | Если выражение не равно нулю, ассемблер обрабатывает операторы в условном блоке. |
IFE выражение | Если выражение равно нулю, ассемблер обрабатывает операторы в условном блоке. |
IF1 (нет выражения) | Если осуществляется первый проход ассемблирования то обрабатываются операторы в условном блоке. |
IF2 (нет выражения) | Если осуществляется второй проход операторы ассемблирования, то обрабатываются в условном блоке. |
IFDEF идентификатор | Если идентификатор определен в программе или объявлен как EXTRN, то ассемблер обрабатывает операторы в условном блоке. |
IFNDEF идентификатор | Если идентификатор не определен в программе или не объявлен как EXTRN, то ассемблер обрабатывает операторы в условном блоке. |
IFB <аргумент> | Если аргументом является пробел, ассемблер обрабатывает операторы в условном блоке. Аргумент должен быть в угловых скобках. |
IFNB <аргумент> | Если аргументом является не пробел, то ассемблер обрабатывает операторы в условном блоке. Аргумент должен быть в угловых скобках. |
IFIDN <арг-1>,<арг-2> | Если строка первого аргумента идентична строке второго аргумента, то ассемблер обрабатывает операторы в условном блоке. Аргументы должны быть в угловых скобках. Учитывает различие строчных и прописных букв. |
IFIDNI <арг 1>, <арг 2> | Если строка первого аргумента идентична строке второго аргумента, то ассемблер обрабатывает операторы в условном блоке. Аргументы должны быть в угловых скобках. Игнорирует различие строчных и прописных букв. |
IFDIF <арг-1>,<арг-2> | Если строка первого аргумента отличается от строки второго аргумента, то ассемблер обрабатывает операторы в условном блоке. Аргументы должны быть в угловых скобках.Учитывает различие строчных и прописных букв. |
IFDIFI <арг-1>,<арг-2> | Если строка первого аргумента отличается от строки второго аргумента, то ассемблер обрабатывает операторы в условном блоке. Аргументы должны быть в угловых скобках. Игнорирует различие строчных и прописных букв. |
(слайд №20)
Ниже приведен простой пример директивы IFNB (если не пробел). Для DOS INT 21H все запросы требуют занесения номера функции в регистр AH, в то время как лишь некоторые из них используют значение в регистре DX. Следующее макроопределение учитывает эту особенность:
DOS21 MACRO DOSFUNC,DXADDRES
MOV AH,DOSFUNC
IFNB
MOV DX,OFFSET DXADDRES
ENDIF
INT 21H
ENDM
Использование DOS21 для простого ввода с клавиатуры требует установки значения 01 в регистр AH:
DOS21 01
Ассемблер генерирует в результате команды MOV AH,01 и INT 21H. Для ввода символьной строки требуется занести в регистр AH значение 0AH, а в регистр DX - адрес области ввода:
DOS21 0AH,IPFIELD
Ассемблер генерирует в результате обе команды MOV и INT 21H.