Руководство по препроцессору FASM (fb2) читать постранично, страница - 7


 [Настройки текста]  [Cбросить фильтры]

операндами), или как унарный (с одним операндом) оператор.

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

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

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

macro declare_macro_AAA

{

 macro AAA

 {

  db 'AAA',0

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

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

Проблема в том, что когда макрос declare_macro_AAA обрабатывается препроцессором, первая найденная скобочка } считается завершением определения его, а не так как хотелось бы. Так же происходит и с другими символами и/или операторами (например, #, `, forward, local).

Но со временем, была добавлена новая директива. Она работает подобно EQU, но обрабатывается до любого другого препроцессинга. (За исключением предварительных операций, про которые говорится в разделе Общие понятия — они выполняются как бы до самого препроцессинга, но это уже внутренние детали, не слишком интересные). Директива эта называется FIX:

Синтаксис:

name1 fix name2

Видно, что синтаксис такой же как у EQU, но как я сказал, когда препроцессор обрабатывает часть кода, он смотрит, есть ли FIX, а потом уже делает всё остальное. Например код:

a equ 10

b fix 10

mov ax, a

mov bx, b

будет преобразован в:

mov ax, 10

mov bx, 10

Но при обработке такого кода:

equ fix =

a equ 10

mov ax, a

в первой строк директива FIX скажет препроцессору поменять все EQU на =. Далее, перед обработкой следующей строки, препроцессор проверит, нет ли там пофиксеных идентификаторов. Так что в нашей второй строке equ будет заменено на =, и строка примет вид a = 10. Так что никакой другой обработки этой строки не будет выполнено. А значит, и третья строка не будет преобразовываться препроцессором, так как идентификатор a не будет определён директивой EQU. Результат всего этого будет такой:

a = 10

mov ax, a

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

macro declare_macro_AAA

{

 macro AAA

 %_

  db 'aaa',0

 _%

}

%_ fix {

_% fix }

declare_macro_AAA

Здесь, препроцессор найдёт объявление макроса declare_macro_AAA и определит его, далее будет два FIX, и потом использование макроса declare_macro_AAA. Так что он преобразует это в:

macro declare_macro_AAA

{

 macro AAA

 %_

  db 'aaa',0

 _%

}

%_ fix {

_% fix }

macro AAA

%_

 db 'aaa',0

_%

и теперь уже содержимое нового макроса будет обработано препроцессором. Далее будут заменены аргументы FIXов, и получится:

macro declare_macro_AAA

{

 macro AAA

 %_

  db 'aaa',0

 _%

}

macro AAA

{

 db 'aaa',0

}

как мы и хотели.

Подобным образом можно пофиксить все остальные проблематичные вещи:

macro declare_macro_TEXT

{

 macro TEXT [arg]

 %_

  %forward

   db %x arg

 _%

}

%_ fix {

_% fix }

%forward fix forward

declare_macro_TEXT

%x fix `

TEXT abc,def

В этом примере нужно обратить внимание на один момент: строка %x fix ` должна находиться после declare_macro_TEXT. Если б она находилась до, то %x было бы пофиксено во время развёртывания макроса, и тогда `arg приняло бы вид 'arg', следовательно макрос TEXT был бы объявлен так:

macro TEXT [arg]

{

 forward

  db 'arg' ;строка не зависит от аргументов

}

Но, в нашем случае он будет:

macro TEXT [arg]

{

 forward

  db `arg  ;имена аргументов превращаются в строки

}

Этот пример показывает, как важно местонахождение FIX.

Иногда необходимо фиксить идентификаторы дважды:

macro m1

{

 macro m2

 %_

  macro m3 [arg]

  %%_

   db arg

  _%%

 _%

}

%%_ fix %_

_%% fix _%

%_ fix {

%_ fix }

m1

m2

m3

Символы фиксятся даже во время препроцессинга других FIX, так что код выше не будет работать, если порядок будет такой:

%_ fix {

%_ fix }

%%_ fix %_

_%% fix _%

В этом случае строка %%_ fix %_ была бы пофиксена сразу же после %_ fix {, так что все последующие %%_ сразу же преобразовались бы в }. То же самое и для _%% fix _%.

Я знаю, FIXы могут смутить, и хорошо бы понимать внутренние детали работы препроцессора, но они предоставляют очень большие возможности. Privalov делает FASM настолько мощным, на сколько это возможно, даже за счёт некоторого ущерба удобопонятности.

Заключение

Не забывайте читать документацию FASM. Практически всё, что есть в туториале, можно найти там. Может быть написано и немного сложнее для изучения, но лучше подойдёт в качестве справочной информации. Не так сложно запомнить — 99 % пользователей FASM научились его использовать по этой документации и при помощи форума.