Руководство по препроцессору FASM - страница 7

стр.

Пример расширенной инструкции >mov, которая позволяет перемещать данные между ячейками памяти:

>macro mov dest,src

>{

> if dest src eqtype [0] [0]

>  push src

>  pop dest

> else

>  mov dest,src

> end if

>}

>mov [var1], 5

>mov [var1], [var2]

преобразуется препроцессором в:

>if [var1] 5 eqtype [0] [0] ;не верно

> push 5

> pop [var1]

>else

> mov [var1],5

>end if

>if [var1] [var2] eqtype [0] [0] ;верно

> push [var2]

> pop [var1]

>else

> mov [var1], [var2]

>end if

и будет ассемблировано в:

> mov [var1], 5

> push [var2]

> pop [var1]

Хотя более удобно для восприятия реализовать макрос используя логический оператор И>&:

>macro mov dest,src

>{

> if (dest eqtype [0]) & (src eqtype [0])

>  push src

>  pop dest

> else

>  mov dest, src

> end if

>}

Пример с использованием >EQTYPE с четырьмя аргументами приведён для демонстрации возможностей, обычно проще использовать в таких случаях >&. Кстати, в качестве аргументов, возможно использовать некорректные выражения — достаточно, чтобы лексический анализатор распознал их тип. Но это не является документированным, так что не будем этот обсуждать.

7.3. Оператор IN

Бывают случаи, когда в условии присутствует слишком много >EQ:

>macro mov a,b

>{

> if (a eq cs) | (a eq ds) | (a eq es) | (a eq fs) | \

>    (a eq gs) | (a eq ss)

>  push b

>  pop a

> else

>  mov a, b

> end if

>}

Вместо применения множества логических операторов ИЛИ>|, можно использовать специальный оператор >IN. Он проверяет, присутствует ли идентификатор слева, в списке идентификаторов справа. Список должен быть заключён в скобочки >< и >>, а идентификаторы в нём разделяются запятыми,

>macro mov a,b

>{

> if a in

>  push b

>  pop a

> else

>  mov a, b

> end if

>}

Это так же работает для нескольких идентификаторов (как и >EQ):

>if dword [eax] in <[eax], dword [eax], ptr eax, dword ptr eax>

8. Структуры

В FASM, структуры практически тоже самое, что и макросы. Определяются они посредством директивы >STRUC:

Синтаксис:

>struc name arguments { тело структуры }

Отличае от макросов заключается в том, что в исходном тексте перед структурой должна находиться метка — имя объекта-структуры. Например:

>struc a {db 5}

>a

это не будет работать. Структуры распознаются только после меток, как здесь:

>struc a {db 5}

>name a

подобно макросу, это преобразуется препроцессором в:

>db 5

Смысл метки в следующем — она будет добавлена ко всем идентификаторам из тела структуры, которые начинаются с точки… Например:

>struc a {.local:}

>name1 a

>name2 a

будет:

>name1.local:

>name2.local:

Таким образом можно создавать структуры вроде тех, что есть в других языках:

>struc rect left,right,top,bottom ;аргументы как у макроса

>{

> .left   dd left

> .right  dd right

> .top    dd top

> .bottom dd bottom

>}

>r1 rect 0,20,10,30

>r2 rect ?,?,?,?

получим:

>r1.left   dd 0

>r1.right  dd 20

>r1.top    dd 10

>r1.bottom dd 30

>r2.left   dd ?

>r2.right  dd ?

>r2.top    dd ?

>r2.bottom dd ?

Поскольку, используемой структуре всегда должна предшествовать метка, препроцессор однозначно отличает их от макросов. Поэтому имя структуры может совпадать с именем макроса — в каждом случае будет выполняться нужная обработка.

Существуют хитрый приём, позволяющий не указывать аргументы, если они равны >0:

>struc ymmv arg

>{

> .member dd arg+0

>}

>y1 ymmv 0xACDC

>y2 ymmv

будет:

>y1.member dd 0xACDC+0

>y2.member dd +0

Как говорилось ранее, если значение аргумента не указанно, то в теле макроса или структуры вместо него ничего не подставляется. В этом примере >+ используется или как бинарный (то есть с двумя операндами), или как унарный (с одним операндом) оператор.

ПРИМЕЧАНИЕ: часто используется так же макрос или структура >struct, которая определяется для расширения возможностей при определении структур. Не путайте >struct и >struc.

9. Оператор FIX и макросы внутри макросов

В стародавние времена, в FASMе отсутствовала одна полезная возможность — создавать макросы внутри других макросов. Например, что бы при развёртывании макроса был бы определён новый макрос. Что-то вроде гипотетичного:

>macro declare_macro_AAA

>{

> macro AAA

> {

>  db 'AAA',0

> } ;завершаем определение AAA

>} ;завершаем определение declare_macro_AAA

Проблема в том, что когда макрос >declare_macro_AAA обрабатывается препроцессором, первая найденная скобочка