Руководство по препроцессору FASM - страница 4
> call behind?00000001
> db 'aaaaa', 0
>behind?00000001:
> call behind?00000002
> db 'bbbbbbbb', 0
>behind?00000002:
> call something
Заметьте, Вы не сможете напрямую обратиться к метке содержащей >?
так как это специальный символ в FASM, поэтому он и используется в локальных метках. К примеру, >aa?bb
рассматривается как идентификатор >aa
, специальный символ >?
и идентификатор >bb
.
Если Вам нужно несколько локальных меток — не проблема, их можно указать в одной директиве >LOCAL
, разделив запятыми >,
:
>macro pushstr string ; делает то же, что и предыдущий макрос
>{
> local addr, behind
> push addr
> jmp behind
> addr db string,0
> behind:
>}
Всегда хорошо бы начинать все локальные метки макросов с двух точек >..
— это значит, что они не будут менять текущую глобальную метку. К примеру:
>macro pushstr string
>{
> local behind
> call behind
> db string, 0
> behind:
>}
>MyProc:
> pushstr 'aaaa'
>.a:
будет преобразовано в:
>MyProc:
> call behind?00000001
> db 'aaaa', 0
>behind?00000001:
>.a:
в результате получим метку >behind?00000001.a
вместо >MyProc.a
. Но если в примере выше >behind
заменить на >..behind
, текущая глобальная метка не изменится и будет определена метка >MyProc.a
:
>macro pushstr string
>{
> local ..behind
> call ..behind
> db string,0
> ..behind:
>}
>MyProc:
> pushstr 'aaaa'
>.a:
5.4. Оператор объединения #
У макроязыка FASMа есть ещё одна возможность — манипуляции с идентификаторами. Делается это оператором >#
, который объединяет два идентификатора в один. К примеру, >a#b
становится >ab
, а >aaa bbb#ccc ddd
— >aaa bbbccc ddd
.
Оператор >#
может быть использован только внутри тел макросов, а объединение символов происходит после замены аргументов макроса параметрами. Так что его можно использовать для создания новых идентификаторов из переданных в макрос параметров:
>macro string name, data
>{
> local ..start
> ..start:
> name db data,0
> sizeof.#name = $ —..start
>}
>string s1,'нудные макросы'
>string s2,<'а вот и я',13,10,'заставлю тебя их видеть во сне'>
получим:
>..start?00000001:
>s1 db 'нудные макросы',0
>sizeof.s1 = $ —..start?00000001
>..start?00000002:
>s2 db 'а вот и я',13,10,'заставлю тебя их видеть во сне',0
>sizeof.s2 = $ —..start?00000002
так что для всех строк, создаваемых этим макросом будет определён идентификатор >sizeof.имя строки
, равный количеству байт строки.
Оператор >#
способен так же объединять символьные строки:
>macro debug name
>{
> db 'name: '#b,0
>}
>debug '1'
>debug 'foobar'
>будет:
>db 'name: 1',0
>db 'name: foobar',0
Это полезно при передаче аргументов из макроса в макрос:
>macro pushstring string
>{
> local ..behind
> call ..behind
> db string,0
> ..behind:}
>macro debug string
>{
> push MB_OK
> push 0 ;empty caption
> pushstring 'debug: '#string ;принимает один аргумент
> push 0 ;нет окна-предка
> call [MessageBox]
>}
Обратите внимание, нельзя использовать >#
совместно с идентификаторами, определёнными >local
, так как >local
обрабатывается препроцессором раньше, чем >#
. Из-за этого подобный код работать не будет:
>macro a arg
>{
> local name_#arg
>}
>a foo
5.5. Оператор `
Существует оператор, преобразующий идентификатор в символьную строку. Он так же может быть использован только внутри макросов:
>macro proc name
>{
> name:
> log `name ;log - макрос, принимающий параметр-строку
>}
>proc DummyProc
получим:
>DummyProc:
> log 'DummyProc'
Пример посложнее, с использованием >#
>macro proc name
>{
> name:
> log 'начинается подпрограмма: '#`name
>}
>proc DummyProc
>retn
>proc Proc2
>retn
будет:
>DummyProc:
>log 'начинается подпрограмма: DummyProc'
>retn
>Proc2:
>log 'начинается подпрограмма: Proc2'
>retn
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