Руководство по препроцессору FASM - страница 5
Для работы с групповыми аргументами применяются специальные директивы препроцессора. Они могут быть использованы только внутри тела макроса имеющего групповой аргумент. Первая такая директива — это >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
7. Условный препроцессинг
В действительности, FASM не имеет директив для условного препроцессинга. Но директива ассемблера >if
может быть использована совместно с возможностями препроцессора для получения тех же результатов, что и при условном препроцессинге. (Но в этом случае увеличивается расход памяти и времени).
Как известно, оператор >if
обрабатывается во время ассемблирования. Это значит, что условие в этом операторе проверяется после обработки исходного текста препроцессором. Именно это обеспечивает работу некоторых логических операций.
Я не буду рассказывать о деталях времени ассемблирования (логических операциях вроде