}
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
Для работы с групповыми аргументами применяются специальные директивы препроцессора. Они могут быть использованы только внутри тела макроса имеющего групповой аргумент. Первая такая директива — это 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. Комбинирование директив управления группами