6. Макросы с групповыми аргументами

6.1. Определение макросов с групповым аргументом

У макросов могут быть так называемые групповые аргументы. Это позволяет использовать переменное количество аргументов. При определении макроса, групповой аргумент заключается в квадратные скобочки

[
и
]
:

Синтаксис:

macro name arg1, arg2, [grouparg]

{

; тело макроса

}

Среди аргументов в определении макроса, групповой аргумент должен быть последним. Групповой аргумент может содержать несколько значений:

macro name arg1,arg2,[grouparg] {}

name 1,2,3,4,5,6

В этом примере значение

arg1
будет
1
,
arg2
2
, а
grouparg
3,4,5,6
.

6.2. Директива COMMON

Для работы с групповыми аргументами применяются специальные директивы препроцессора. Они могут быть использованы только внутри тела макроса имеющего групповой аргумент. Первая такая директива — это

COMMON
. Она означает, что после неё имя группового аргумента будет замещаться всеми аргументами сразу:

macro string [grp]

{

 common

 db grp,0

}

string 'aaaaaa'

string 'line1',13,10,'line2'

string 1,2,3,4,5

получим:

db 'aaaaaa',0

db 'line1',13,10,'line2',0

db 1,2,3,4,5,0

6.3. Директива FORWARD

Аргументы можно обрабатывать и по-отдельности. Для этого служит директива

FORWARD
. Часть тела макроса после этой директивы обрабатывается препроцессором для каждого аргумента из группы:

macro a arg1,[grparg]

{

 forward

 db arg1

 db grparg

}

a 1,'a','b','c'

a -1, 10, 20

будет:

db 1

db 'a'

db 1

db 'b'

db 1

db 'c'

db -1

db 10

db -1

db 20

Директива

FORWARD
работает по умолчанию для макросов с групповыми аргументами, так что предыдущий пример можно сделать так:

macro a arg1,[grparg]

{

 db arg1

 db grparg

}

6.4. Директива REVERSE

REVERSE
— это аналог
FORWARD
, но обрабатывает группу аргументов в обратном порядке — от последнего к первому:

macro a arg1,[grparg]

{

 reverse

 db arg1

 db grparg

}

a 1,'a','b','c'

получим:

db 1

db 'c'

db 1

db 'b'

db 1

db 'a'

6.5. Комбинирование директив управления группами

3 вышеупомянутые директивы могут разделять тело макроса на блоки. Каждый блок обработается препроцессором после предыдущего. Например:

macro a [grparg]

{

 forward

 f_#grparg: ;оператор объединения

 common

 db grparg

 reverse

 r_#grparg:

}

a 1,2,3,4

будет:

f_1:

f_2:

f_3:

f_4:

db 1,2,3,4

r_4:

r_3:

r_2:

r_1:

6.6. Директива LOCAL в макросах с групповыми аргументами

У локальных меток в макросах есть ещё одно полезное свойство. Если директива

LOCAL
находится внутри блока
FORWARD
или
REVERSE
, то уникальное имя метки сгенерируется для каждого аргумента из группы, и в последующих блоках
FORWARD
и/или
REVERSE
для каждого аргумента будет использована соответствующая ему метка:

macro string_table [string]

{

 forward      ;таблица указателей на строки

 local addr    ;локальная метка для строки

 dd addr     ;указатель на строку

 forward      ;строки

 addr db string,0 ;создаём и завершаем нулём

}

string_table 'aaaaa','bbbbbb','5'

получим:

dd addr?00000001

dd addr?00000002

dd addr?00000003

addr?00000001 db 'aaaaa',0

addr?00000002 db 'bbbbbb',0

addr?00000003 db '5',0

Другой пример с блоком

REVERSE
:

macro a [x]

{

 forward

 local here

 here db x

 reverse

 dd here

}

a 1,2,3

будет:

here?00000001 db 1

here?00000002 db 2

here?00000003 db 3

dd here?00000003

dd here?00000002

dd here?00000001

Как видно, метки используется с соответствующими аргументами и в

FORWARD
и в
REVERSE
блоках.

6.7. Макросы с несколькими групповыми аргументами

Возможно использовать и несколько групповых аргументов. В этом случае определение макроса не будет выглядеть как:

macro a [grp1],[grp2]

так как тут не ясно какой аргумент какой группе принадлежит. Исходя из этого делают так:

Синтаксис:

macro a [grp1,grp2]

В этом случае каждый нечётный аргумент относится к группе

grp1
, а каждый чётный — к
grp2
:

macro a [grp1,grp2]

{

 forward

 l_#grp1:

 forward

 l_#grp2:

}

a 1,2,3,4,5,6

будет:

l_1:

l_3:

l_5:

l_2:

l_4:

l_6:

Или ещё:

macro ErrorList [name,value]

{

 forward

 ERROR_#name = value

}

ErrorList \

 NONE,0,\

 OUTOFMEMORY,10,\

 INTERNAL,20

получим:

ERROR_NONE = 0

ERROR_OUTOFMEMORY = 10

ERROR_INTERNAL = 20

Конечно же, может быть больше 2х групп аргументов:

macro a [g1,g2,g3]

{

 common

 db g1

 db g2

 db g3

}

a 1,2,3,4,5,6,7,8,9,10,11

будет:

db 1,4,7,10

db 2,5,8,11

db 3,6,9

Загрузка...