Продолжая использовать наш сайт, вы даете согласие на обработку файлов cookie, которые обеспечивают правильную работу сайта. Благодаря им мы улучшаем сайт!
Принять и закрыть

Читать, слущать книги онлайн бесплатно!

Электронная Литература.

Бесплатная онлайн библиотека.

Читать: Flat Assembler 1.64. Мануал программера - Tomasz Grysztar на бесплатной онлайн библиотеке Э-Лит


Помоги проекту - поделись книгой:

MACRO fix tmacro

ENDM fix }

определяет альтернативный синтаксис определения макросов, который выглядит как:

MACRO stoschar char

mov al,char

stosb

ENDM

Имейте в виду, что таким образом заданное определение должно быть создано с применением директивы «fix», так как перед тем, как процессор ищет знак «}» во время определения макроса, обрабатываются только символьные константы высшего приоритета! Может возникнуть проблема, если требуется выполнить некоторые дополнительные задания в конце такого определения, но есть еще одно свойство, которое в таких случаях поможет вам. А именно возможно поместить любую директиву, инструкцию или макроинструкцию сразу после символа «}», который заканчивает макроинструкцию и она будет обработана так же, как если бы была на следующей строке.

2.3.4 Структуры

«struc» — это специальный вариант директивы «macro», который используется для определения структур данных. Макроинструкции, определенные директивой «struc», когда используются, должны предваряться меткой (как директивы определения данных). Эта метка будет также присоединена к началу каждого имени, начинающегося с точки, в содержании макроинструкции. Макроинструкция, определенная с использованием директивы «struc», может иметь такое же имя, как макросы, определенные с использованием директивы «macro». Структурная макроинструкция не будет мешать обычному макросу, выполняющемуся без метки перед ним и наоборот. Все правила и свойства, касающиеся стандартных макросов, применимы к структурным макроинструкциям.

Вот пример структуры:

struc point x,y

{

 .x dw x

 .y dw y

}

Например «my point 7,11» определит структуру, помеченную «my», содержащую две переменные: «my.x» со значением 7 и «my.y» со значением 11.

Еслигде-то в определении структуры находится имя, состоящие из одной лишь точки, оно заменяется на имя метки для данного примера структуры и эта метка таким образом не будет определена автоматически, позволяя полностью задать определение. Следующий пример использует это свойство, чтобы расширить определение директивы «db» с возможностью вычисления размера определяемых данных:

struc db [data]

{

 common

 . db data

 .size = $ —.

}

Таким образом строка «msg db 'Hello!',13,10» определит так же константу «msg.size», равную размеру определяемых данных в байтах.

Определение структур данных, адресованных регистрами или абсолютными значениями может быть сделано структурными макроинструкциями с использованием директивы «virtual» (смотрите 2.2.3).

«restruc» удаляет последнее определение структуры, так же как «purge» делает с макросами и «restore» с символьными константами. Директива имеет тот же синтаксис — за ней должно следовать одно или несколько имен структурных макросов, разделенных запятыми.

2.3.5 Повторение макроинструкций

Директива «rept» — это специальный вид макроинструкций, который делает заданное число дубликатов блока, заключенного в фигурные скобки. Простой синтаксис — число, следующее за «rept» (это не может быть выражение, так как препроцессор не совершает вычисления, если вам нужны повторения, базирующиеся на выражениях, вычисленных ассемблером, используйте одну из директив, обрабатываемых ассемблером, смотрите 2.2.2), и блок кода, заключенный между знаками «{» и «}». Простейший пример:

rept 5 { in al,dx }

создает пять дубликатов строки «in al,dx». Блок инструкций определяется таким же образом, как для стандартных макросов, и допускаются все специальные операторы и директивы, которые могут использоваться только внутри макроинструкций. Если заданное число равно нулю, блок просто пропускается, как если бы вы определили макрос, но не использовали его. За количеством повторений может следовать имя символа-счетчика, который символьно будет заменяться на номер текущего повторения. Таким образом:

rept 3 counter

{

 byte#counter db counter

}

Сгенерирует строки:

byte1 db 1

byte2 db 2

byte3 db 3

Механизм повторения, применяемый к блокам «rept» такой же, как тот, что используется для обработки множественных групп аргументов макросов, то есть директивы, такие как «forward», «common» и «reverse» могут использоваться их обычном значении.

Итак, такой макрос:

rept 7 num { reverse display `num }

покажет символы от 7 до 1 как текст. Директива «local» работает так же, как внутри макросов с несколькими группами аргументов, то есть:

rept 21

{

 local label

 labename = "note" loop label

}

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

rept 8 n:0 { pxor xmm#n,xmm#n }

Сгенерирует код, очищающий содержимое регистров SSE. Вы можете определить несколько счетчиков, разделенных запятыми, и каждый может иметь свою базу.

«irp» итерирует один аргумент через данный список параметров. Синтаксис такой: за «irp» следует имя аргумента, далее запятая и далее список параметров. Параметры определяются таким же образом, как в вызове стандартного макроса, то есть они должны разделяться запятыми и каждый может быть заключен между знаками «<» и «>». Так же за именем аргумента может следовать «*» для обозначения того, что он не может иметь пустое значение. Такой блок:

irp value, 2,3,5

{ db value }

сгенерирует строки:

db 2

db 3

db 5

«irps» итерирует через данный список символов, за директивой должно следовать имя аргумента, далее запятая и далее последовательность любых символов. Каждый символ в последовательности, независимо от того, символы ли это имен, знаки символов или строки в кавычках, становится значением аргумента на одну итерацию. Если за запятой никаких символов не следует, то итераций не производится вообще. Этот пример:

irps reg, al bx ecx

{ xor reg,reg }

сгенерирует строки:

xor al,al

xor bx,bx

xor ecx,ecx

Блоки, определенные директивами «irp» и «irps», обрабатываются так же, как макросы, то есть операнды и директивы, специфичные для макросов могут в них свободно использоваться.

2.3.6 Условный препроцессинг

При применении директивы «match» некоторый блок кода обрабатывается препроцессором и передаётся ассемблеру, только если заданная последовательность символов совпадает с образцом. Образец идет первым, заканчивается запятой, далее идут символы, которые должны подходить под образец, и далее блок кода, заключенный в фигурные скобки, как макроинструкция.

Есть несколько правил для построения выражения для сравнения, первое — это любые символьные знаки и строки в кавычках должны соответствовать абсолютно точно. В этом примере:

match +,+ { include 'first.inc' }

match +,- { include 'second.inc' }

Первый файл будет включен, так как «+» после запятой соответствует «+» в образце, а второй файл не будет включен, так как совпадения нет.

Чтобы соответствовать любому другому символу буквально, он должен предварятья знаком «=» в образце. Также чтобы привести в соответствие сам знак «=», или запятую должны использоваться конструкции «==» и «=,». Например, образец «=a==» будет соответствовать последовательности «a=».

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

match a-b, 0–7

{ dw a,b-a }

сгенерирует инструкцию «dw 0, 7–0». Каждое имя всегда ставится в соответствие как можно меньшему количеству символов, оставляя оставшиеся, то есть:

match a b, 1+2+3 { db a }

имя «a» будет соответствовать символу «1», оставляя последовательность «+2+3» в соответствие с «b». Но, таким образом:

match a b, 1 { db a }

для «b» ничего не остается, и блок вообще не будет обработан.

Блок кода, определенный директивой «match» обрабатывается так же, как любая макроинструкция, поэтому здесь могут использоваться любые операторы, специфичные для макроинструкций.

Что делает директиву «match» очень полезной, так это тот факт, что она заменяет символьные константы на их значения в поставленной в соответствие последовательности символов (то есть везде после запятой до начала блока кода) перед началом сопоставления. Благодаря этому директива может использоваться, например, для обработки некоторого блока кода в зависимости от выполнения условия, что данная символьная константа имеет нужное значение, например:

match =TRUE, DEBUG { include 'debug.inc' }

здесь файл будет включен, только если символьная константа «DEBUG» определена со значением «TRUE».

2.3.7 Порядок обработки

При сочетании разных свойств препроцессора важно знать порядок, в котором они обрабатываются. Кат уже было отмечено, высший приоритет имеет директива «fix» и замены, ею определенные. Это полностью делается перед совершением любого другого препроцессинга, поэтому такой кусок кода:

V fix {

  macro empty

   V

V fix }

   V

делает допустимое определение пустого макроса. Можно сказать, что директива «fix» и приоритетные константы обрабатываются на отдельной стадии, и весь остальной препроцессинг делается на результирующем коде.

Стандартный препроцессинг, который начинается после, на каждой строке начинается с распознавания первого символа. Сначала идет проверка на директивы препроцессора, и если ни одна из них не опознана, препроцессор проверяет, является ли первый символ макроинструкцией. Если макроинструкция не найдена, препроцессор переходит ко второму символу на строке, и снова начинает с проверки на директивы, список которых в этом случае ограничивается лишь «equ», так как только она может оказать вторым символом на строке. Если нет директивы, второй символ проверяется на структурную макроинструкцию, и если ни одна из этих проверок не дала положительного результата, символьные константы заменяются на их значения, и строка передается ассемблеру.

Продемонстрируем это на примере. Пусть «foo» — это макрос, а «bar» — это структура. Эти строки:

foo equ

foo bar

обе будут интерпретированы как вызовы макроса «foo», так как значение первого символа берет верх над значением второго.

Макроинструкции генерируют новые строки от их блоков определения, заменяя параметры на их значения и далее обрабатывая операторы «#» и «`». Оператор конверсии имеет высший приоритет, чем оператор сцепления.

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



Поделиться книгой:

На главную
Назад