Вперед Назад Содержание

3. Команды препроцессора

Команды GASP'а имеют прямой синтаксис, который хорошо приспособлен к соглашениям ассемблирования. Как правило, команда занимает строку, и может иметь до трех полей: необязательная метка, собственно команда и необязательные параметры команды. Вы можете писать команды в верхнем или нижнем регистре; в данном руководство все записывается в верхнем регистре. См.: "Подробности синтаксиса GASP'а": для дальнейшей информации.

3.1 Условное ассемблирование

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

Общая структура условных выражений известна из многих других аналогичных контекстов. " .AIF " отмечает начало условного выражения, и трансляция происходит в случае, когда условие истинно. Возможный " .AELSE " влечет трансляцию для обратного случая, а " .AENDI " помечает конец условной трансляции.

Вы можете вкладывать условные выражения со степенью вложенности до 100; GASP не допускает большую степень вложенности с большей степенью, потому что это может указывать на ошибку в Вашем макроопределении.

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

.AIF EXPRA CMP EXPRB .AIF "STRA" CMP "STRB"
Проверяемое условие находится на той же строке, что и команда препроцессора .AIF. Вы можете сравнивать две строки или два выражения.

Когда Вы сравниваете строки, возможно использование только двух операторов сравнения CMP: "EQ" (истина, если STRA и STRB равны), и "NE" (истина, если STRA и STRB отличаются).

Когда Вы сравниваете два выражения, оба выражения должны быть абсолютными (см.: "Арифметические выражения в GASP"). Вы можете использовать с выражениями следующие операторы сравнения CMP:

EQ

Равны ли EXPRA и EXPRB? (Для строк, совпадают ли STRA и STRB?)

NE

Являются ли EXPRA и EXPRB различными? (Для строк, являются STRA и STRB различными?)

LT

EXPRA меньше чем EXPRB? (Недопустимо для строк.)

LE

EXPRA меньше или равно EXPRB? (Недопустимо для строк.)

GT

EXPRA больше чем EXPRB? (Недопустимо для строк.)

GE

EXPRA большим чем или равным EXPRB? (Недопустимо для строк.)

.AELSE
Эта директива отмечает начало ассемблерного кода, который будет включен, если условие ложно. Необязателен, и возможен только внутри условного выражения (между .AIF и .AENDI).

.AENDI
Отмечает конец блока условной трансляции.

3.2 Повторяющиеся ассемблируемые участки

Две директивы препроцессора позволяют Вам последовательно выдавать несколько копий блока ассемблерного кода.

.AREPEAT AEXP .AENDR
Если Вы просто должны повторить один и тот же самый блок кода фиксированное число раз, заключите один экземпляр блока между " .AREPEAT " и " .AENDR ". Укажите число повторений как AEXP (это должно быть абсолютное выражение). Например, следующий код повторяет два ассемблерных оператора три раза по порядку:

.AREPEAT 3 Rotcl r2 Div1 r0, r1 .AENDR
.AWHILE EXPRA CMP EXPRB .AENDW .AWHILE STRA CMP STRB .AENDW
Чтобы повторить блок команд несколько раз в зависимости от некоторого условия, используйте .AWHILE. .AENDW отмечает конец повторяемого блока. Условное сравнение работает точно так же, как для .AIF, с теми же самыми операторами сравнения (См.: "Условная трансляция").

Так как операнды для операции сравнения должны быть абсолютными выражениями, .AWHILE чаще всего используется внутри определений макрокоманд. См.: "Определение собственных директив"

Вы можете использовать директиву препроцессора .EXITM, для преждевременного выхода из цикла (так же, как для выхода из макрокоманд). См.: "Определение собственных директив"

3.3 Переменные Препроцессора

Вы можете использовать переменные GASP'а для прдставления строк, регистров или результатов выражений.

Необходимо различать два вида переменных:

  1. Переменные, определенные при помощи " .EQU " или " .ASSIGN ". Чтобы вычислить значение такой переменной в выводе трансляции, нужно просто упомянуть имя. Например, в двух следующих строках определяется и используется переменная eg:
    eg .EQU FLIP-64 ... mov.l eg,r0
    Не следует использовать эти переменные в условных выражениях или циклах WHILE; GASP просто записывает значения этих переменных на выводе трансляции.
  2. Переменные для использования во время работы препроцессора. Вы можете определять их с помощью директив .ASSIGNC или .ASSIGNA. Чтобы вычислить значение этого вида переменной, напишите "\&" перед ее именем; например,
    Opcit .ASSIGNA 47 ... . AWHILE \$opcit GT 0 ... . AENDW
GASP обрабатывает параметры макросов почти таким же образом, но для их вычисления предпочтительнее использовать префикс " \ ", чем " \& ". См.: "Определение собственных директив"

PVAR .EQU EXPR
Присваивает переменной препроцессора PVAR значение выражения EXPR. Не имеется никаких ограничений на переопределение; используйте .EQU с одной и той же переменной PVAR столько раз, сколько потребуется.

PVAR .ASSIGN EXPR
Почти то же, что и " .EQU ", кроме того, что запрещено переопределение PVAR с использованием " .ASSIGN ", если она уже имеет значение.

PVAR .ASSIGNA AEXPR
Определяет переменную с числовым значением для использования во время работы препроцессора. AEXPR должно быть абсолютным выражением. Возможно переопределение переменных с помощью .ASSIGNA.

PVAR .ASSIGNC "STR"
Определяет переменную со значением строки, для использования во время работы препроцессора. Возможно переопределение переменных с помощью .ASSIGNC.

PVAR .REG (REGISTER)
Используйте .REG чтобы определить переменную, которая должна представлять некоторый регистр. В частности, REGISTER нельзя вычислить как выражение. .REG можно использовать для переопределения регистровых переменных.

Для всех этих директив имя переменной должно находиться в позиции метки, т.е. в левом поле. При желании вы можете ставить двоеточие после имени переменной; первый пример выше мог бы начинаться с " eg: " с тем же самым результатом.

3.4 Определение собственных директив

Команды .MACRO и .ENDM позволяют вам определять макрокоманды, генерирующие ассемблерный вывод. Вы можете использовать эти макрокоманды с синтаксисом, аналогичным встроенным в GASP или ассемблерным директивам. Например, следующий фрагмент определяет макрокоманду "SUM", которая складывает значения в последовательных регистрах:

.MACRO SUM FROM=0, TO=9 ! \FROM \TO mov r\FROM,r10 COUNT .ASSIGNA \FROM+1 .AWHILE \&COUNT LE \TO add r\&COUNT,r10 COUNT .ASSIGNA \&COUNT+1 .AENDW .ENDM
При таком определении " SUM 0,5 " сгенерирует следующий текст на ассемблере вывод:

! 0 5 mov r0,r10 add r1,r10 add r2,r10 add r3,r10 add r4,r10 add r5,r10
.MACRO MACNAME .MACRO MACNAME MACARGS ...
Начинает определение макрокоманды MACNAME. Если ваша макрокоманда требует параметры, укажите их имена после имени макрокоманды, отделив их запятыми или пробелами. Вы можете также задавать значение по умолчанию для любого параметра, написав =DEFLT после его имени. Например, возможны следующие .MACRO операторы:

.MACRO COMM
Начинает определение макрокоманды "COMM", не имеющей параметров.

.MACRO PLUS1 P, P1 .MACRO PLUS1 P P1
Оба оператора начинают определение макрокоманды "PLUS1", имеющей два параметра; внутри определения макрокоманды следует писать "\P" или "\P1" для получения значений параметров.

.MACRO RESERVE_STR P1=0 P2
Начинает определение макрокоманды "RESERVE_STR" с двумя параметрами. Первый параметр имеет значение по умолчанию, второй - не имеет. После окончания определения вы можете вызывать макрокоманду так: RESERVE_STR A, B ("\P1" присваивается A и "\P2" присваивается B) или так: RESERVE_STR ,B ("\P1" присваивается значение по умолчанию, а "\P2" присваивается B)

Когда Вы вызываете макрокоманду, Вы можете указывать значения параметров как позицией, так и ключевым словом. Например, SUM 9,17 эквивалентно SUM TO=17, FROM=9. Параметры макроопределения - переменные препроцессора, аналогичные переменным, определяемым при помощи .ASSIGNA или .ASSIGNC; в частности, Вы можете использовать их в условных выражениях и при управлении циклом. (Единственое различие - префикс, который требуется для вычисления значения переменной: для параметра макроса следует писать \ARGNAME, а для переменной препроцессора - "\&VARNAME".)

NAME .MACRO NAME .MACRO (MACARGS ...)
Альтернативная форма введения макроопределения: укажите имя макроса в позиции метки, а параметры (если имеются) - между круглыми скобками после имени. Правила использования значений по умолчанию работают так же, как и для другого синтаксиса макроопределения.

.ENDM
Отмечает конец макроопределения.

.EXITM
Немедленный выход из текущего макроопределения, цикла .AREPEAT или цикла .AWHILE.

\@
GASP считает, сколько раз макрос вычислил значение этой псевдопеременной; Вы можете скопировать это число в ваш вывод с помощью \@, но только внутри макроопределения.

LOCAL NAME [, ...]
Предупреждение: использование LOCAL возможно, только если Вы выбираете альтернативный синтаксис макрокоманд при помощи опций -a или --alternate. См.: "Альтернативный синтаксис макрокоманд"

Производит замену каждого из параметров NAME на строку, уникально формируемую при каждом новом вызове макроопределения. При использовании NAME в дальнейшем выполняется замена на эту строку. Строка замены уникальна при трансляции, и различна для каждого отдельного макрорасширения. LOCAL позволяет Вам писать макрокоманды, определяющие символы, избегая конфликта в именах, определяемых в разных макрорасширениях данного макроопределения.

3.5 Вывод данных

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

Вы можете использовать метки как обычно, чтобы отметить области данных.

Инициализированные данные

В GASP имеются директивы для инициализированных данных, и они расширяют стандартные директивы GNU ассемблера до следующих:

.DATA EXPR, EXPR, ... .DATA.B EXPR, EXPR, ... .DATA.W EXPR, EXPR, ... .DATA.L EXPR, EXPR, ...
Вычисляются арифметические выражения EXPR, и генерируется соответствующая директива ассемблера as (помеченная LAB). .DATA генерирует .long; .DATA.B генерирует .byte; .DATA.W генерирует .short; .DATA.L генерирует .long.

Например, foo .DATA 1,2,3 генерирует foo: .long 1,2,3.

.DATAB REPEAT, EXPR .DATAB.B REPEAT, EXPR .DATAB.W REPEAT, EXPR .DATAB.L REPEAT, EXPR
Заставляет "as", сгенерировать REPEAT копий значения выражения EXPR (используя директиву as .fill). .DATAB.B повторяет 1-байтные значения; .DATAB.W повторяет 2-байтные значения; и .DATAB.L повторяет 4-байтные значения. .DATAB без суффикса действует так же, как и .DATAB.L.

REPEAT должно быть абсолютным выражением с положительным значением.

.SDATA "STR" ...
Строковые данные. Генерирует последовательность байтов точно в том порядке, как Вы указываете их (в частности не добавляется никакого признака конца строки). См: "Строковые и числовые константы", для подробного описания того, как писать строки. .SDATA конкатенирует множество аргументов, упрощая перевод строки из одного представления в другое. Можно для ясности использовать запятые, чтобы разделить параметры , если Вам это будет удобнее.

.SDATAB REPEAT, "STR" ...
Повторяет строковые данные. Первый параметр определяет количество генерируемых копий строки; остальные задают строку таким же образом, как для .SDATA.

.SDATAZ" STR " ...
Данные в виде строк, оканчивающихся на ноль. Действует так же, как и .SDATA, за исключением того, что .SDATAZ дописывает нулевой байт в конец строки.

.SDATAC " STR " ...
Данные в виде строк с префиксом, содержащим длину. Действует так же, как и .SDATA, за исключением того, что .SDATAC перед строкой записывает ее длину в виде байта. Например, .SDATAC "HI" генерирует .byte 2,72,73. Поскольку поле длины является байтом, Вы можете использовать " .SDATAC " только для строк с длиной меньше чем 256 байт.

Неинициализированные данные

Используйте директивы .RES, .SRES, .SRESC и .SRESZ для резервирования памяти без ее инициализации. Эти директивы GASP'а соответствуют использованию директивы GNU as .space.

.RES COUNT .RES.B COUNT .RES.W COUNT .RES.L COUNT
Резервирует участок памяти для COUNT неинициализированных элементов данных. Суффикс определяет размер каждого элемента: .RES.B резервирует COUNT байт, .RES.W резервирует COUNT пар байтов, .RES.L резервирует COUNT четверок байтов. .RES без суффикса эквивалентен .RES.L.

.SRES COUNT .SRES.B COUNT .SRES.W COUNT .SRES.L COUNT
.SRES - синоним для .RES.

.SRESC COUNT .SRESC.B COUNT .SRESC.W COUNT .SRESC.L COUNT
Подобно .SRES, но резервирует место для COUNT + 1 элементов.

.SRESZ COUNT .SRESZ.B COUNT .SRESZ.W COUNT .SRESZ.L COUNT
Подобно .SRES, но резервирует место для COUNT + 1 элементов.

Управление листингом.

Директивы GASP'а управления печатью листинга соответствуют аналогичным директивам GNU as.

.PRINT LIST .PRINT NOLIST
Управление печатью листинга. Эта директива генерирует директиву GNU "as" .list или .nolist, согласно параметру.

.FORM LIN=LN .FORM COL=COLS .FORM LIN=LN COL=COLS
Определяет размер страницы для распечаток трансляции: LN - число строк, COL - число столбцов. Вы можете определять каждый размер страницы независимо или оба вместе. Число строк по умолчанию равно 60; число столбцов - 132. (Значения, которые возможно были определены в предыдущих вызовах .FORM, не принимаются как новые значения по умолчанию.) Генерируется директива ассемблера .psize.

.HEADING STRING
Строка STRING становится заголовком ваших листингов. Генерирует .title "STRING".

.PAGE
Переход на новую страницу. Генерирует .eject.

3.6 Разные команды

.ALTERNATE
Использовать далее альтернативный синтаксис макроопределений. См.: "Аьтернативный синтаксис макросов"

.ORG
Эта команда распознается, но еще не обрабатывается. GASP генерирует сообщение об ошибке для программ, которые используют .ORG.

.RADIX S
GASP воспринимает числа в системе счисления с основаниями два, восемь, десять и шестнадцать. Вы можете явно задавать основание в любой числовой константе (См.: "Строковые и числовые константы"). Если число записано без явного указания основания системы счисления, то его определяет последняя команда .RADIX S. S - одиночный символ, один из следующих:

.RADIX B
Основание 2.

.RADIX Q
Основание 8.

.RADIX D
Основание 10. Это основание первоначально задается по умолчанию.

.RADIX H
Основание 16.

Параметр S может быть и маленькой буквой (любой из " bqdh ") с тем же эффектом.

.EXPORT NAME .GLOBAL NAME
Объявляет глобальную переменную NAME (генрирует .global NAME). Две директивы являются синонимами.

.PROGRAM
GASP игнорирует эту директиву.

.END
Этой директивой должен быть помечен конец каждого обрабатываемого файла. GASP выдает предупреждение, если достигает конца файла, не найдя эту команду.

.INCLUDE " STR "
Обрабатывает файл с именем STR, как будто его содержимое появилось в месте, где находится директива .INCLUDE. GASP налагает максимальное ограничение на вложенное включение файлов, равное 30, для проверки отсутствия ошибок.

.ALIGN SIZE
Вычисляет абсолютное выражение SIZE, и генерирует команду .align SIZE с использованием результата.

3.7 Подробности синтаксиса GASP'а

Поскольку GASP предназначен для работы с ассемблерным кодом, синтаксис его конструкций не несет в себе никаких неожиданностей для программиста на ассемблере.

Пропуски (пробелы или знаки табуляции, но не символы перевода строки) разделяют строку на поля; в строке должно быть не более трех полей. Количество подряд идущих пропусков не имеет значения; Вы можете выстраивать в столбцы соответствующие поля на разных строках, если хотите, но GASP не требует этого.

Первое поле (если оно имеется) - необязательная "метка"; это поле должно быть крайним слева в строке (перед ним не должно быть пропусков). Вы можете ставить двоеточие после метки, если хотите; GASP не требует двоеточия, но и не запрещает его наличия (но не будет включать его в имя метки).

Второе поле, которому должны предшествовать несколько пропусков, содержит директиву ассемблера или директиву GASP'а.

Все дальнейшие поля в строке - "параметры" директивы; они отделяются от друг друга с помощью запятых или пропусков.

Специальные синтаксические маркеры

GASP распознает несколько специальных маркеров: ограничитель комментариев, продолжение оператора на следующей строке, отделение символов от других знаков, и "дословное" копирование текста на вывод. (Еще один специальный маркер, \@ , воспринимается только внутри макроопределений. См.: "Определение собственных директив")

Остаток любой строки исходного текста GASP'а может быть комментарием. Комментарий начинается с первого не заключенного в кавычки символа комментария ("!" по умолчанию), или помеченного "\" или удвоенного символа комментария ("\!" или "!!" по умолчанию), и продолжается до конца строки. Вы можете задавать символ комментария с помощью опции " -c " (См.: "Параметры командной строки"). Два вида маркеров комментария имеют несколько различную интерпретацию:

"!" Одиночный символ комментария генерирует ассемблерный комментарий в выводе. Внутри него GASP вычисляет все переменные препроцессора (параметры макро и переменные, определенные с помощью .ASSIGNA или .ASSIGNC). Например, макрокоманда, которая начинается подобно этой

.MACRO SUM FROM=0, TO=9 ! \FROM \TO
выдаст в первой строке вывода комментарий, cодержащий значения, используемые Вами при вызове макрокоманды.

"\!" "!!"
Помеченный "\" или двойной символ комментария отмечает начало комментария исходного текста GASP'а. GASP не копирует такие комментарии на вывод.

Чтобы продолжить оператор на следующей строке файла, начните ее символом "+".

Иногда Вам может потребоваться запретить GASP'у обработку некоторой части текста. Чтобы "дословно" скопировать из исходного текста GASP'а на вывод, поставьте "\(" перед копируемой строкой и ")" в конце. Например, чтобы получить "\!" на выводе, можно записать "\(\!)".

Чтобы отделить переменную препроцессора от текста, следующего сразу после ее значения, пишите одиночную кавычку ("'"). Например, ".SDATA "\P'1" " выдает строку, сформированную дописыванием к значению P цифры "1". (Этого нельзя достичь, записывая просто " \P1 ", поскольку " P1 " также является возможным именем для переменной препроцессора.)

Строковые и числовые константы

В GASP'е имеются два способа записи строковой константы: как строковый литерал, и как числовое байтовое значение. Строковый литерал следует заключать в двойные кавычки ("STR"). Отдельное числовое значение байта задается абсолютным выражением, заключенным в угловые скобки (<EXPR>). Директивы для вывода строк позволяют Вам определять любой количество значений любого вида и в любом порядке и конкатенировать результат. (Альтернативный режим синтаксиса предоставляет несколько других вариантов записи. (См.: Альтернативный синтаксис макросов)

Числовые константы можно записывать или с данным, или с текущим основанием. Текущее основание равно 10 по умолчанию, а изменяется при помощи директивы .RADIX.

Чтобы записать константу с данным основанием, используйте образец "S'DDD": символ-спецификатор основания S, одиночная кавычка и цифры DDD. Спецификатор основания соответствует тем, которые Вы можете указывать в директиве .RADIX: B для основания 2, Q для 8, D для 10 и H для 16. (Символ может быть как строчной, так и заглавной буквой.)

Символы

GASP распознает имена символов, которые начинаются с любой буквы алфавита, "_" или "$", и состоит из тех же самых символов и цифр. Имена меток подчиняются тем же самым правилам.

Арифметические выражения в GASP

Имеются два вида выражений, в зависимости от их результата: абсолютные выражения, которые можно свести к константе (то есть они не включают значений, неизвестных для GASP'а), и аддитивные выражения, которые можно свести к форме

ADDSYM+CONST-SUBSYM
где ADDSYM и SUBSYM - ассемблерные символы неизвестного значения, а CONST - константа.

Арифметика для выражений GASP следует правилам, очень похожим на те, что приняты в языке C. Вы можете использовать круглые скобки, чтобы изменить приоритет операций; иначе, арифметические примитивы имеют уменьшающийся приоритет в следующем порядке:

  1. Унарный "+" (тождество), "-" (арифметическое отрицание), "~" (поразрядное отрицание). Параметр должен быть абсолютным выражением. *
  2. "*" (умножение) и "/" (деление). Оба параметра должны быть абсолютными выражениями.
  3. "+" (сложение) и "-" (вычитание). По крайней мере один параметр должен быть абсолютным.
  4. "&" (поразрядное И). Оба параметра должны быть абсолютными.
  5. "|" (поразрядное ИЛИ) и "~" (поразрядное исключающее ИЛИ; "^" в C). Оба параметры должны быть абсолютными.

Строковые примитивы

Вы можете использовать эти примитивы для манипуляций со строками (в поле параметра оператора GASP'а):

.LEN ("STR")

Вычисляет длину строки "STR" как абсолютное выражение. Например, .RES.B .LEN ("sample") резервирует шесть байтов памяти.

.INSTR ("STRING", "SEG", IX)

Ищет в STRING первую подстроку SEG после позиции IX. Например, .INSTR ("ABCDEFG", "CDE", 0) дает абсолютный результат "2".

Если SEG не входит в STRING как подстрока после позиции IX, то возвращается -1.

.SUBSTR ("STRING", START, LEN)

Подстрока STRING, начинающаяся с байта номер START длины LEN байтов.

3.8 Альтернативный синтаксис макросов

Если Вы указываете -a или --alternate в командной строке GASP'а , препроцессор использует несколько другой синтаксис. Этот синтаксис напоминает синтаксис макроассемблера Phar Lap, но он не является полной эмуляцией Phar Lap или аналогичных ассемблеров. В частности, GASP не поддерживает директивы типа DB и IRP, даже в альтернативном режиме синтаксиса.

Конкретно, использование опций -a или --alternate приводит к следующим изменениям:


Вперед Назад Содержание