Руководство по препроцессору 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 обрабатывается во время ассемблирования. Это значит, что условие в этом операторе проверяется после обработки исходного текста препроцессором. Именно это обеспечивает работу некоторых логических операций.

Я не буду рассказывать о деталях времени ассемблирования (логических операциях вроде