Форум программистов, компьютерный форум, киберфорум
Assembler, MASM, TASM
Войти
Регистрация
Восстановить пароль
Блоги Сообщество Поиск  
 
 
Рейтинг 4.63/2256: Рейтинг темы: голосов - 2256, средняя оценка - 4.63
Ушел с форума
Автор FAQ
 Аватар для Mikl___
16377 / 7689 / 1080
Регистрация: 11.11.2010
Сообщений: 13,769
18.12.2013, 14:19  [ТС]
ГЛАВА 21
МАКРОЯЗЫК
(часть 1/3)

Нередко бывает полезным предварительное (до начала трансляции) преобразование текста программы. Например, может потребоваться, чтобы какой-то фрагмент программы был продублирован несколько раз или чтобы в зависимости от некоторых условий в тексте программы были сохранены одни фрагменты и удалены другие. Подобную возможность предоставляют так называемые макросредства. Расширение языка Ассемблера за счет этих средств называют макроязыком.
Программа, написанная на макроязыке, транслируется в два этапа.
  • Сначала она переводится на «чистый» ассемблер, то есть преобразуется к такому виду, где нет никаких макросредств. Этот этап называется этапом макрогенерации, его осуществляет специальный транслятор макрогенератор.
  • На втором этапе полученная программа переводится в машинный код. Это этап ассемблирования, его осуществляет ассемблер.
Трансляция программы, написанная на макроязыке, занимает больше времени, чем трансляция программы на чистом языке ассемблера. Но макроязык предоставляет больше возможностей, поэтому писать большие программы проще на макроязыке.
Стандартные функции могут быть определены в библиотеке макрокоманд и доступны при дальнейшем программировании. Число операций повторного кодирования уменьшается, уменьшается и количество ошибок.
Блоки повторения
Иногда в программе приходится выписывать несколько раз подряд один и тот же (или почти один и тот же) фрагмент, и хотелось бы, чтобы мы сами выписывали этот фрагмент только раз, а макрогенератор размножал его нужное количество раз. Такая возможность предусмотрена в языке ассемблер, и реализуется она с помощью блоков повторения (repeat blocks).
Структура блока повторения<заголовок>
<тело блока>
ENDM

<тело блока>— любое число любых предложений (в частности, ими могут быть снова блоки повторения), ENDM —директива, указывающая на конец тела и всего блока повторений. Встречая в исходном тексте программы такой блок, макрогенератор подставляет вместо него в окончательную программу несколько копий тела.
При дублировании тело может выписываться без всяких изменений, а может копироваться с модификациями. Как именно будет происходить дублирование, сколько копий будет создано зависит от заголовка блока. Имеются три разновидности заголовка, поэтому различают три варианта блока повторения: REPT–блоки, IRP–блоки и IRPC–блоки.

REPT–блоки
Этот тип блоков повторения записывается следующим образом:
Структура REPT блокаREPT k
<тело блока>
ENDM
k — константное выражение с неотрицательным значением. Это выражение должно быть таким, чтобы можно было вычислить его сразу (например, в нем не должно быть ссылок вперед). Вычислив значение k, макрогенератор создаст k точных копий тела блока и подставляет их в окончательный текст программы:
До макрогенерации После макрогенерации
REPT 3
SHR AX,1
ENDM
SHR AX,1
SHR AX,1
SHR AX,1


До макрогенерации После макрогенерации
N EQU 6
REPT N-4
DB 0,1
DW ?
ENDM
N EQU 6
DB 0,1
DW ?
DB 0,1
DW ?
В блоках повторения довольно часто используется директива присваивания (=). Для описания 100-байтового массива X, элементы которого имеют начальные значения от 0 до 99, можно так (справа указан фрагмент окончательной программы, который фактически эквивалентен директиве
Assembler
1
X DB 0,1,...,99)
До макрогенерации После макрогенерации
X DB 0
K=0
REPT 99
K=K+1
DB K
ENDM
X DB 0
K=0
K=K+1
DB K
K=K+1
DB K
...;99 таких пар

WHILE-блоки
WHILE-блоки, также как и REPT-блоки, применяются для повторения определенного количества раз некоторой последовательности строк. В отличие от директивы REPT, которая автоматически уменьшает на единицу значение константного выражения и повторяет тело блока до тех пор пока значение константного выражения не станет равным нулю, директива WHILE требует чтобы уменьшение константного выражения происходило внутри тела блока.
структура WHILE-блокаWHILE k
<тело блока>
ENDM
макрос демонстрирует резервирование памяти длиной len байтов с использованием директивы WHILE:
Assembler
1
2
3
4
WHILE len
DB 0
len=len-1
ENDM
IRP–блоки
Блоки повторения этого типа имеют следующий вид
Структура IRP блокаIRP p,<v1,...,vk>
<тело блока>
ENDM
Запись в уголках <v1,...,vk> это явно указываемые символы, а не метасимволы. p — некоторое имя, оно играет роль формального (фиктивного) параметра и используется в предложениях тела макроса. vi — это фактические параметры; это любые тексты (возможно, и пустые), но, чтобы не было путаницы, они должны быть сбалансированы по кавычкам и не должны содержать запятые, точки с запятой и уголки вне кавычек (если это ограничение надо нарушить, то следует воспользоваться микрооператорами). Параметры vi перечисляются через запятую, а вся их совокупность обязательно заключается в угловые скобки.
Встречая такой блок макрогенератор заменяет его на k копий тела (по одной на фактический параметр), причем в i-той копии все вхождения имени p заменяются на vi:
До макрогенерации После макрогенерации
IRP REG,<AX,BX,CX>
PUSH REG
ENDM
PUSH AX
PUSH BX
PUSH CX
Формальный параметр локализуется в теле блока (им нельзя пользоваться вне блока) и может быть любым именем. Если оно совпадает с именем другого объекта программы, то в теле блока оно обозначает именно параметр, а не объект. Имя BX обозначает параметр, а не регистр, поэтому по данному блоку будет построен следующий фрагмент окончательной программы:
До макрогенерации После макрогенерации
IRP BX,<1,5>
ADD AX,BX
ENDM
ADD AX,1
ADD AX,5
Замена формального параметра на фактические — это чисто текстуальные подстановки, без учета смысла: просто один участок p заменяется на другой vi. При этом параметром p можно обозначить любую часть предложения (в частности, участки комментария) или даже целиком все предложение (однако два и более предложения он не может обозначать), лишь бы после замены p на vi получались правильные предложения:
До макрогенерации После макрогенерации
IRP Q,<DEC WORD PTR,L: INC>
Q W
JMP M2
ENDM
DEC WORD PTR W
JMP M2
L: INC W
JMP M2
В теле блока повторения заменяется только формальный параметр, другие имена (например, имена констант переносятся в копии тела без изменений:
До макрогенерации После макрогенерации
N EQU 1
IRP P,<A,>
P EQU N
ENDM
N EQU 1
A EQU N;но не A EQU 1
B EQU N

IRPC–блоки
Блоки этого типа записываются следующим образом:
Структура IRPC блокаIRPC p,s1...sk
<тело блока>
ENDM
p — формальный параметр, si — символы. Это могут быть любые символы, кроме пробелов и точек с запятой (считается, что с точки с запятой начинается комментарий, а пробел заканчивает операнд; если надо указать точку с запятой или пробел, то всю последовательность символов следует заключить в угловые скобки). Встречая IRPC–блок, макрогенератор заменяет его на k копий тела блока (по одной на каждый символ), причем в i-ой копии все вхождения p будут заменены на символ si.
До макрогенерации После макрогенерации
IRPC D,17W
ADD AX,D
ENDM
ADD AX,1
ADD AX,7
ADD AX,W

Макрооператоры
При использовании блоков повторения (и макросов) возникает ряд проблем с записью формальных и фактических параметров. Эти проблемы решаются с помощью макрооператоров — операторов, разрешенных к применению только в конструкциях макроязыка.

Макрооператор &
Рассмотрим следующий блок повторения и построенные по нему копии:
До макрогенерацииПосле макрогенерации
IRP W,<VAR1, VAR6>
W DW ?
ENDM
VAR1 DW ?
VAR6 DW ?
Параметр W обозначает имя переменной целиком. Но фактические имена (VAR1 и VAR6) различаются лишь последним символом, поэтому было бы разумно объявить параметром только этот символ, а не все имя. Но если так сделать, то получится неоднозначность — непонятно когда W обозначает формальный параметр, а когда просто букву W (почему в VARW надо W заменять на 1 и 6, а в DW не надо?)
Assembler
1
2
3
IRPC W,16
VARW DW ?
ENDM
В предыдущих примерах формальные параметры легко выделялись из окружающего текста благодаря ограничителям (пробелам, запятым), стоящим слева и справа от параметра. Но если рядом с параметром стоит имя или число, то границы параметра становятся неопределяемыми. В подобной ситуации следует между параметром и соседним с ним числом или именем поставить символ & (A&W, 1&W&B и тому подобное). Первый блок повторения должен быть записан так:
Assembler
1
2
3
IRPC W,16
VAR&W DW ?
ENDM
Знак & указывает границу формального параметра, выделяет его из окружающего текста, но в окончательный текст программы не попадает. Если & поставить не около параметра, то он будет пропущен.
Макрооператор & используется не только тогда, когда формальный параметр сливается с соседними именами и числами, но и когда его надо указать внутри строк. Макрогенератор игнорирует вхождение формального параметра в строки. Чтобы обратить внимание макрогенератора на эти вхождения, перед параметром в строках ставят знак &, а если не ясна правая граница параметра, то & надо указывать и после параметра:
До макрогенерации После макрогенерации
IRPC A,”<
DB ‘A,&A,&A&B’
ENDM
DB ‘A,”,”B’
DB ‘A,<,<B’
Если рядом поставить несколько знаков &, то макрогенератор удалит только первый из них — это дает возможность создавать вложенные блоки повторений. Встретив в тексте исходной программы блок повторения, макрогенератор сначала создаст первую копию тела внешнего блока, в котором все вхождения формального параметра P1 будут заменены на символ A. При этом из двух стоящих подряд в команде INC знаков & будет удален только один, оставшийся знак & будет отделять формальный параметр внутреннего блока от стоящей слева буквы A. В полученной копии остались конструкции макроязыка, поэтому макрогенератор продолжит свою работу. После обработки внутреннего блока получится уже окончательный текст. Далее будет создана вторая копия внешнего блока, которая будет обработана аналогично:
До макрогенерации После первой макрогенерации После второй макрогенерации
IRPC P1,AB
IRPC P2,HL
INC P1&&P2
ENDM
ENDM
IRPC P2,HL
INC A&P2
ENDM
IRPC P2,HL
INC B&P2
ENDM
INC AH
INC AL
INC BH
INC BL

Макрооператор <>
Фактические параметры IRP-блока не должны содержать запятые, точки с запятой и уголки, второй операнд IRPC-блока не должен содержать пробелы и точки с запятой. Эти ограничения введены чтобы не возникало неоднозначности — если внутри фактического параметра IRP-блока указать запятую (например: 1,2), тогда будет непонятно, что означает эта запись — два параметра разделенных запятой или один параметр, содержащий внутри себя запятую. Если необходимо нарушить указанные ограничения, тогда весь фактический параметр IRP-блока или всю последовательность символов в IRPC-блоке надо заключить в угловые скобки (например: <1,2>), причем весь текст внутри этих скобок должен быть сбалансирован по уголкам:
До макрогенерации После макрогенерации
IRP VAL,<<1,2>,3>
DB VAL
ENDM
DB 1,2
DB 3
Считается, что внешние угловые скобки не относятся к параметру или последовательности, а лишь указывают их границы:
До макрогенерации После макрогенерации
IRPC S,<A;B>
DB ‘&S’
ENDM
DB A
DB ;
DB B

Макрооператор !
Для задания внутри фактического параметра непарного уголка или непарной кавычки, а также для задания других спецсимволов (вне и внутри угловых скобок) предусмотрен макрооператор: !<символ>
Символ "!" не переносится в окончательный текст, но следующий за ним символ трактуется как обычный символ, а не как символ, играющий какую-то специальную роль:
До макрогенерации После макрогенерации
IRP X,<A!>B, Привет!, компьютер!!>
DB ‘&X’
ENDM
DB ‘A>B’
DB ‘Привет, компьютер!’
Макрооператор "!" можно использовать только при записи фактических параметров IRP-блоков и макросов. В последовательности символов IRPC-блока знак ! рассматривается как обычный символ, а не как макрооператор. Указывать в этой последовательности уголки можно сколько угодно раз, если эта последовательность не начинается с открывающей угловой скобки, а если начинается — пока нет баланса угловых скобок.

Макрооператор %
Макрооператор используемый при записи фактических параметров IRP-блоков и макросов: %<константное выражение>
Встретив такую конструкцию в фактическом параметре, макрогенератор вычисляет указанное выражение и подставляет его значение вместо всей этой конструкции. Вложенности макрооператоров % не допускается. В конструкции %5-%K будет зафиксирована ошибка «неописанное имя %K».
До макрогенерацииПосле макрогенерации
K EQU 4
IRP A,<K+1,%K+1,W%K+1>
DW A
ENDM
DW K+1
DW 5
DW W5
Концом константного выражения считается первый символ (запятая, угловая скобка или знак равенства), который не может по синтаксису входить в константные выражения (например, если константа K=4 параметр %K-1+K= K будет преобразован в 7=K). В последовательности символов IRPC-блока знак % рассматривается как обычный символ, а не как макрооператор.

Макрооператор ;;
Если в теле блока повторения или макроса имеются комментарии (в конце каких-то предложений или как самостоятельные предложения), то они переносятся во все копии блока. Если комментарий полезен при описании самого блока повторения, но совершенно не нужен в его копиях — тогда комментарий начинают с двух точек с запятой — такие комментарии не копируются:
До макрогенерации После макрогенерации
IRP R,<AX,BX>
;;восстановление регистров
;восстановить R
POP R;;из стека в R
ENDM
;восстановить AX
POP AX
;восстановить BX
POP BX

Макросы
С помощью блока повторения один раз описывается некоторый фрагмент программы, который затем многократно копируется макрогенератором. Но блоки повторения можно использовать, только если эти копии расположены рядом друг с другом. Если фрагмент программы должен повторяться в разных местах программы используются макросы — специальным образом описанный фрагмент программы, которому дали имя, а затем в нужных местах программы выписывается ссылка на этот макрос с указанием его имени. Когда макрогенератор просматривает текст программы и встречает такую ссылку, то он вместо нее подставляет в окончательный текст программы сам макрос — соответствующий фрагмент программы. Так делается для каждой ссылки на макрос, в каком бы месте программы она не встретилась.
Терминология:
  • макроопределение — описание макроса,
  • ссылка на макрос — макрокоманда,
  • процесс замены макрокоманды на макрос — макроподстановка,
  • результат макроподстановки — макрорасширение.

Макроопределения
Описание макроса имеет следующий вид:
<имя макроса> MACRO <формальные параметры через запятую>
<тело макроса>
ENDM
Первая строка макроопределения — это директива MACRO, которую принято называть заголовком макроса. В ней, во-первых, указывается имя, которое дается макросу, во-вторых, через запятую перечисляются формальные параметры макроса. Необходимость в параметрах вызвана тем, что в общем случае макрос должен копироваться не в неизменном виде, а с некоторыми модификациями; параметры и обозначают те величины, которые влияют на модификации. Формальным параметрам можно давать любые имена, эти имена локализуются в теле макроса; если имя параметра совпало с именем другого объекта программы, то внутри макроопределения под этим именем понимается параметр, а не объект.
Тело макроса — это тот фрагмент программы, который и будет затем многократно копироваться. Тело может состоять из любого числа любых предложений, в которых можно использовать формальные параметры макроса. Как и в блоках повторения, формальные параметры могут обозначать любые части предложений тела. Если рядом с параметром надо указать имя или число, или если параметр надо указать внутри строки, то следует использовать макрооператор &. В теле макроса можно использовать комментарии, начинающиеся с двух точек с запятой.
Завершает макроопределение директива ENDM (end of macro). В этой директиве, в отличие от блока повторения, не надо повторять имя макроса. Если перед директивой ENDM указать имя макроса, то это предложение будет рассматриваться как рекурсивный вызов макроса.
Макроопределения могут быть размещены в любом месте текста программы, по ним в машинную программу ничего не записывается. Но макроопределение должно быть записано до первой ссылки на этот макрос — действует правило ассемблера: “Сначала опиши макрос и только затем обращайся к нему”.

Макрокоманды
В тех местах программы, где макрогенератор должен подставить макрос, выписывается обращение к макросу в виде макрокоманды, которая записывается следующим образом:
<имя макроса><фактические параметры через запятую или пробел>
Конкретные примеры:
SUM A,ES:B
вариант: SUM A ES:B
VAR Z,W,?
вариант: VAR Z W,?
Макрокоманды очень похожи на обычные команды и директивы. Но вместо названия команды или директивы, являющегося служебным словом, в макрокоманде указывается имя макроса, которое придумал автор программы. В макрокоманде параметры могут отделяться как запятыми, так и пробелами.
В качестве фактического параметра может быть указан любой текст (в том числе и пустой), но он должен быть сбалансирован по кавычкам и угловым скобкам и в нем не должно быть запятых, пробелов и точек с запятой вне этих кавычек и скобок. Поскольку запятыми и пробелами отделяется один параметр от другого, а с точек с запятой начинается комментарий, то их использование внутри фактического параметра приведет к неоднозначности.
При записи параметров макрокоманд можно использовать те же макрооператоры <>, ! и %, что и при записи фактических параметров блоков повторения. Если в фактическом параметре надо указать запятую, пробел или точку с запятой, то параметр следует заключить в уголки:
Assembler
1
2
SUM <WORD PTR [SI]>,A
VAR C W <1,2>
Уголки не считаются относящимися к параметру, а лишь указывают его границы. Число фактических параметров, указываемых в макрокоманде, должно равняться числу формальных параметров макроса, причем i-ый фактический параметр соответствует i-му формальному параметру. Но, если фактических параметров указано больше, чем надо, то лишние фактические параметры игнорируются, а если меньше, то считается, что в качестве недостающих фактических параметров заданы пустые тексты.

Макроподстановки и макрорасширения
Когда макрогенератор, просматривая исходный текст программы, встречает макрокоманду, то он выполняет макроподстановку: находит описание макроса с указанным именем, берет его тело, заменяет в этом теле все формальные параметры на соответствующие фактические параметры и полученный таким образом текст (он называется макрорасширением) подставляет в программу вместо макрокоманды:
Макроопределениемакрокомандамакрорасширение
SUM MACRO X,Y
MOV AX,Y
ADDX,AX
ENDM
SUM A,ES:B
MOV AX,ES:B
ADD A,AX
VAR MACRO NM,TP,VL
NM D&TP VL
ENDM
VAR,W,<1,2>DW 1,2
4
Закрытая тема Создать тему
Новые блоги и статьи
Hyper-V: Компьютер должен поддерживать доверенный платформенный модуль 2.0.
Maks 31.08.2026
При установке Windows 11 на виртуальную машину Hyper-V 2-го поколения вылезла такая ошибка: Решение: в параметрах виртуальной машины, в разделе "Безопасность" (Security) активировать флаг. . .
Архитектура биовида Стива в Майнкрафте: Зачем бонобо кубический каннибализм
anaschu 30.08.2026
Кубический Вагинокапитализм в Minecraft: Математический инвариант ОДУ и рок Стивов-бонобо Главная задача разработанной «Модели Всего» — наглядно продемонстрировать наличие системной «судьбы». . .
Оттачиваю умение писать js программы.
russiannick 30.08.2026
Проектом выходного дня стало написание Книги шифров Виженера. Итогом стала версия 200, синий туман. Синий туман назван так, потому что замораживает текст под собой. Нажатие синих кнопок управляют. . .
мат медиц модель 30. презентация проекта
anaschu 27.08.2026
хоп хоп хоп хидахоп, а я кладую))
Как у меня протекала болезнь
zorxor 27.08.2026
Здравствуйте, друзья! Эта запись блога предназначена именно для вас - для моих дорогих друзей, которые знали меня лично. Чтобы ответить на вопрос - а что же со мной произошло на самом деле? Я учился. . .
Нашел вот забавное видео о измерениях. Лучшее что я видел на эту тему
kumehtar 26.08.2026
ILETXiw9bMQ Основная суть и тезисы по измерениям: 0D (Нулевое измерение): точка, не имеющая длины, ширины, высоты или объема. Объект не может перемещаться в 0D. 1D (Первое измерение):. . .
[EasyBuilder Pro] Памятка по разработке для панелей Weintek
ФедосеевПавел 26.08.2026
Памятка по разработке для панелей Weintek ВВЕДЕНИЕ Ранее, при реализации проектов основное внимание уделял разработке управляющей программы для контроллера, а панели оператора доставалось время. . .
Модель по догадкам
anaschu 25.08.2026
Прошло две недели. Я уже рассказывал, как разговаривал с сотрудниками у сортировки и как понял, что главная ветка — не про приёмку, а про отбор. Но тогда я думал, что понял механику. На этой неделе я. . .
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2026, CyberForum.ru