Chapter_12 (1110564), страница 2
Текст из файла (страница 2)
Более того, макроопределения, посвященные одной тематике можнообъединить в один текстовый файл и хранить его отдельно от программных модулей. По аналогии сбиблиотеками объектных модулей, такие файлы часто называются библиотеками макроопределений.Например, используемые нами макроопределения для организации ввода/вывода объединены в библиотеку макроопределений, которая хранится в текстовом файле с именем io.asm.
Как мы знаем,для того, чтобы вставить текст этого файла в программным модуль и, таким образом, сделать содержащиеся в этом файле макроопределения доступными для макрокоманд ввода/вывода, используетсядиректива Ассемблера с именем include.Итак, каждой макрокоманде должно быть поставлено в соответствие макроопределение с такимже именем, иначе в программе фиксируется синтаксическая ошибка (неописанной имя).
Макроассемблер допускает вложенность одного макроопределения внутрь другого (в отличие от процедур,вложенность которых на Ассемблере, как мы уже знаем, не допускается), однако это обычно не нужно и редко используется в практике программирования.Далее, как мы знаем, в макрокоманде на месте поля операндов может задаваться список фактических параметров.
Например, мы можем написать макрокоманду outint X,10 с двумя фактическими параметрами. Как видим, здесь просматривается большое сходство с механизмом процедур,например, в языке Паскаль, где в описании процедуры мог задаваться список формальных параметров, а в операторе процедуры – список фактических параметров. Однако на этом внешнее сходствомежду процедурами в Паскале и макроопределениями в Макроассемблере заканчивается, и начинаются различия в виде, способах передачи и обработки параметров.Каждый фактический параметр макрокоманды является строкой символов (возможно пустой).Хорошим аналогом являются строки типа String в Турбо-Паскале, однако, фактические параметрымакрокоманд, как правило, не заключаются в апострофы.
Фактические параметры, если их болееодного, разделяются запятыми или пробелами.1 Если фактический параметр расположен не в концесписка параметров и является пустой строкой, то его позиция просто выделяется запятыми, например:Mymacro X,,Y; Три фактических параметра, второй пустойMymacro ,A B; Три фактических параметра, первый пустойКак видим, в отличие от Паскаля, все параметры макроопределения одного типа – это (возможнопустые) строки символов, другими словами, всегда есть соответствие по типу между фактическими и формальными параметрами. Далее, в Макроассемблере, в противоположность языку Паскаль, не должно соблюдаться соответствие в числе параметров: формальных параметров может бытькак меньше, так и больше, чем фактических. Если число фактических и формальных параметров несовпадает, то Макропроцессор выходит из этого положения совсем просто. Если фактических параметров больше, чем формальных, то лишние (последние) фактические параметры не используются(отбрасываются), а если фактических параметров не хватает, по последние недостающие фактическиепараметры считаются заданными по умолчанию пустыми строками символов.1Как видим, запятая, пробел (и некоторые другие символы) являются служебными и не могут просто таквстречаться внутри строки-параметра.
При необходимости вставить служебный символ внутрь параметра макрокоманды используются особые приёмы, о которых мы будем говорить далее.4Рассмотрим теперь, как Макропроцессор обрабатывает (выполняет) макрокоманду. Сначала,как мы уже говорили, он ищет соответствующее макроопределение, затем начинает передавать фактические параметры (строки символов, возможно пустые) на место формальных параметров (имён). ВПаскале, как мы знаем, существуют два способа передачи параметров – по значению и по ссылке.
ВМакроассемблере реализован другой (третий) способ передачи фактических параметров макрокоманды в макроопределение, его нет в Паскале. Этот способ называется передачей по написанию (иногдаговорят – передачей по имени). При таком способе передачи параметров все имена формальных параметров в теле макроопределения заменяются соответствующими им фактическими параметрами(строками символов).1 Возможна замена формального параметра на фактический даже внутри текстовых строк, правда, для этого имя формального параметра необходимо выделить специальным макроограничителем &, например:Pmacro Xdb"Параметр X=&X"После передачи параметров начинается просмотр тела макроопределения и поиск в нём предложений, содержащих макросредства, например, макрокоманд.
Все предложения в макроопределении,содержащие макросредства, обрабатываются Макропроцессором так, что в результате получаетсянабор предложений на "чистом" языке Ассемблера (уже без макросредств), такой набор предложенийназывается макрорасширением. Последним шагом в обработке макрокоманды является подстановкаполученного макрорасширения на место макрокоманды, это действие называется макроподстановкой. На рис. 12.2 показана схема обработки макрокоманды.ПараметрыМакрокомандаМакроподстановкаМакроопределениеМакрорасширениеРис. 12.2.
Схема обработки макрокоманды.Из рассмотренного механизма обработки макрокоманд вытекает главное применение этого макросредства при программировании на Ассемблере. Как можно заметить, если нам необходимо выполнить в программе некоторое достаточно сложное действие, можно идти двумя путями. Вопервых, можно написать процедуру и вызывать её, передавая ей фактические параметры. Во-вторых,можно написать макроопределение, в теле которого реализовать нужное нам действие, и обращаться к этому макроопределению по соответствующей макрокоманде, также передавая необходимые параметры.В дальнейшем мы сравним эти два метода, а пока отметим, что написание макроопределений –это хороший способ повысить уровень языка программирования.
Действительно, макрокоманда посинтаксису практически ничем не отличается от обычных команд Ассемблера, но, в отличие от них,может задавать весьма сложное действие. Вспомним, например, макрокоманду inint для ввода целого значения. Соответствующее ей макроопределение по своим функциям похоже на процедуруRead языка Паскаль и реализует достаточно сложный алгоритм по преобразованию вводимых символов в значение целого числа. С точки же зрения программиста в языке Ассемблера как бы появляется новая машинная команда, предназначенная для ввода целых чисел.
Говорят, что при помощимакросредств можно расширить язык Ассемблера, как бы вводя в него новые команды, необходимые программисту. Таким образом, уровень языка Ассемблера, по существу, приближается к языкамвысокого уровня.Теперь пришло время написать наше собственное простое макроопределение и на его основепродолжить изучение работы Макропроцессора. Предположим, что в программе на Ассемблере приходится неоднократно выполнять оператор присваивания вида z:=x+y, где x,y и z – целочисленные операнды размером в слово. В общем случае (при произвольном задании операндов z,x и y – впамяти, на регистрах или в виде констант) для реализации этого оператора присваивания необходимытри команды Ассемблера, например:1Это несколько упрощённое описание действий Макропроцессора при передаче параметров, позже мысделаем в этом месте существенные уточнения.5mov ax,Xadd ax,Ymov Z,axЕстественно, что программисту было бы более удобно, если бы в языке Ассемблера существовала трёхадресная команда, которая реализовывала бы такой оператор присваивания.
Пусть это будет, например, команда с кодом операции Sum:Sum Z,X,Y; Z:=X+YУточним синтаксис нашей новой команды, т.е. зафиксируем допустимые форматы её операндов.Потребуем, чтобы первый операнд этой команды мог иметь форматы r16 и m16, а второй и третийоперанды – форматы i16,m16 и r16 (в любой комбинации). Такой команды, как мы знаем, в машинном языке нашем компьютере нет, но можно создать новую макрокоманду, которая работала бытак, как нам надо.1 Для этого можно написать, например, такое макроопределение:Sum macro Z,X,Ymov ax,Xadd ax,Ymov Z,axendmВот теперь, если в нашей программе есть, скажем, описания переменныхAdw?Bdw?Cdw?и надо выполнить присваивание C:=A+B, то программист может записать это действие в виде одногопредложения Ассемблера – макрокомандыSum C,A,BУвидев такую макрокоманду, Макропроцессор, просматривая текст программы снизу-вверх, найдёт соответствующее макроопределение с именем Sum.
Затем, после замены формальных параметров на фактические, Макропроцессор построит следующее макрорасширение:mov ax,Aadd ax,Bmov C,axЭто макрорасширение и будет подставлено в текст нашей программы вместо макрокомандыSum C,A,B (произойдёт макроподстановка полученного макрорасширения на место макрокоманды).Программист доволен: теперь исходный текст его программы значительно сократился, и программа стала более понятной. Таким образом, можно приблизить уровень языка Ассемблер (как мыговорили, это язык низкого уровня) к языку высокого уровня (например, Паскалю). В этом, как мыуже говорили, и состоит одно из назначений механизма макроопределений и макрокоманд – поднятьуровень языка, в котором они используются.
Кроме того, можно заметить, что с помощью макрокоманд мы как бы меняем архитектуру нашего компьютера, например, у нас появилась трёхадреснаякоманда сложения, которой нет в языке машины.Далее, однако, программист может заметить, что некоторые вызовы макрокоманды Sum работают не совсем хорошо. Например, на место макрокоманды с допустимым форматом параметровSum C,ax,B; формат m16,r16,m16будет подставлено макрорасширениеmov ax,axadd ax,Bmov C,ax1Любопытно отметить, что такой команды не было и в нашей учебной трёхадресной машине УМ-3, гдедопускался только прямой способ адресации, т.е.