Макрокоманды
А теперь вернемся к главе б и вспомним программу из листинга 6.1. Проанали- зируем ее текст, выявим повторяющиеся участки и составим для них макроопре- деления (листинг 14.1).
В листинге 14.1 в строках 2-7, 8-16,18-21, 23-28, 30-37, 39-43 описаны мак- роопределения. Описание их назначения приведено сразу после заголовка в теле каждого макроопределения. Если вынести эти макроопределения в отдельный файл, то впоследствии можно использовать их при написании других программ. Посмотрите на модернизированный исходный текст программы из листинга 6.1 в листинге 14.1 (строки 54-68). Если не обращать внимания на некоторые неяс- ные моменты, то сам сегмент кода стал внешне более читабельным, и даже можно сказать, что в его новых командах появился какой-то смысл. Откомпилируйте ли- стинг 14.1 и получите файл листинга. После этого сравните текст программы до и после обработки ассемблером. Вы увидите, что исходный текст изменился, — пос- ле строк программы, в которых были макрокоманды, появились фрагменты тек- ста. Содержимое этих фрагментов определяется содержимым макроопределений (шаблонов), заданных в начале программы. Видно, что путем ввода параметров для макрокоманды можно модернизировать содержимое фактического текста, за- мещающего макрокоманду. Функционально макроопределения похожи на процедуры. Сходство в том, что и те, и другие достаточно один раз где-то описать, а затем вызывать их специаль- ным образом. На этом сходство заканчивается и начинаются различия, которые в зависимости от целевой установки можно рассматривать и как достоинства, и как недостатки. * В отличие от процедуры, текст которой неизменен, макроопределение в про- цессе макрогенерации может меняться в соответствии с набором фактических параметров. При этом коррекции могут подвергаться как операнды команд, так и сами команды. Процедуры в этом отношении менее гибки. И При каждом вызове макрокоманды ее текст в виде макрорасширения вставля- ется в программу. При вызове процедуры процессор осуществляет передачу управления на начало процедуры, находящейся в некоторой области памяти в одном экземпляре. Код в этом случае получается более компактным, хотя быс- тродействие несколько снижается за счет необходимости осуществления пере- ходов. Макроопределение обрабатывается компилятором особым образом. Для того чтобы использовать описанное макроопределение, его нужно «активизировать» с помощью макрокоманды. Для этого в нужном месте исходного кода программы на основе текста заголовка макроопределения указывается следующая синтакси- ческая конструкция: имя_макрокоманды список_фактических_аргументов В результате применения данной синтаксической конструкции соответствую- щая строка исходного текста программы заменяется строками из тела макроопре- деления. Но это не простая замена. Обычно макрокоманда содержит некоторый список аргументов (список_фактических_аргументов), которыми корректируется макроопределение. Места в теле макроопределения, которые будут замещаться фактическими аргументами из макрокоманды, обозначаются с помощью так на- зываемых формальных аргументов. Таким образом, в результате применения мак- рокоманды в программе формальные аргументы в макроопределении замещаются соответствующими фактическими аргументами; в этом и заключается учет кон- текста. Процесс такого замещения называется макрогенерацией, а результатом этого процесса является макрорасширение. К примеру, рассмотрим самое короткое макроопределение в листинге 14.1 — сlеаr_rg. Как отмечено ранее, результаты работы макроассемблера можно узнать, просмотрев файл листинга после трансляции. Покажем несколько его фрагмен- тов, которые демонстрируют, как был описан текст макроопределения сlеаr_rg (стро- ки 24-27), как был осуществлен вызов макрокоманды сlеаr_rg с фактическим па- раметром ах (строка 74) и как выглядит результат работы макрогенератора, сформировавшего команду ассемблера хоr ах,ах (строка 75): clear_r macro rg ;очистка регистра rg хоr rg,rg епdm сlеаr_r ах 00ΘΕ 33 С0 хоr ах,ах В итоге мы получили то, что и требовалось, — команду очистки заданного реги- стра, в данном случае АХ. В другом месте программы вы можете выдать ту же мак- рокоманду, но уже с другим именем регистра. Если у вас есть желание, можете провести эксперименты с этой и другими макрокомандами. Каждый фактический аргумент макрокоманды представляет собой строку символов, для формирования которой применяются определенные правила. * Строка может состоять: ? из последовательности символов без пробелов, точек, запятых, точек с запя- той; ? из последовательности любых символов, заключенных в угловые скобки (), в которой можно указывать как пробелы, так и точки, запятые, точки с запятыми (мы упоминали об этом операторе выделения ассемблера при обсуждении директивы EQU). ® Для того чтобы указать, что некоторый символ внутри строки, представляю- щей фактический параметр, является собственно символом, а не чем-то иным, например, некоторым разделителем или ограничивающей скобкой, применя- ется специальный оператор !. Этот оператор ставится непосредственно перед нужным символом, и его действие эквивалентно заключению этого символа в угловые скобки. Таким образом, оператор ! также является оператором выде- ления, но одиночного символа. я Для вычисления в строке, представляющей фактический параметр в макроко- манде, некоторого константного выражения в начале этого выражения нужно поставить знак % (процент): % константное_выражение Значение константное_выражение вычисляется и подставляется в текстовом виде в соответствии с текущей системой счисления[13]. Теперь обсудим вопрос, как транслятор распознает формальные аргументы в те- ле макроопределения для их последующей замены фактическими аргументами? Прежде всего по их именам в заголовке макроопределения. В процессе генера- ции макрорасширения компилятор ассемблера ищет в тексте тела макроопределе- ния последовательности символов, совпадающие с теми последовательностями символов, из которых состоят формальные параметры. После обнаружения такого совпадения формальный параметр из тела макроопределения замещается соответ- ствующим фактическим параметром из макрокоманды. Этот процесс называется подстановкой аргументов. Здесь нужно отметить еще раз особо список формаль- ных аргументов в заголовке макроопределения. В общем случае он может содер- жать не только разделенные запятыми формальные элементы, но и некоторую до- полнительную информацию. Полный синтаксис формального аргумента следую- щий: ■ имя_формального_аргумента[:тип] Здесь тип может принимать значения: REQ — это значение говорит о том, что требуется обязательное явное задание фактического аргумента при вызове макрокоманды; т = — если аргумент при вызове макрокоманды не задан, то в соот- ветствующие места в макрорасширении по умолчанию будет вставлено значе- ние любая_строка (будьте внимательны: символы, входящие в операнд любая_ строка, должны быть заключены в угловые скобки). Однако распознать в теле макроопределения формальный аргумент ассемблер может не всегда. Это, например, может не произойти в случае, когда он является частью некоторого идентификатора. В этом случае последовательность символов формального аргумента отделяют от остального контекста с помощью специаль- ного оператора замены (символа &). Этот прием часто используется для задания модифицируемых идентификаторов и кодов операций. К примеру, определим мак- рос, который предназначен для генерации в программе некоторой таблицы, при- чем параметры этой таблицы можно задавать с помощью аргументов макроко- манды:
После трансляции текста программы, содержащей эти строки, получатся сле- дующие макрорасширения: tаbl_b db 10 duр (0) tаbl_w dw 10 duр (0) Символ & можно применять и для распознавания формального аргумента в стро- ке, заключенной в двойные кавычки (""). Например, пum_сhаr macro message ;подсчитать количество (пum) символов в строке jmр ml еlеm db "Строка &message содержит" ;число символов в строке message в коде ASCII пum db 2 duр (0) db " символов", 10,13 , ' S ' ;конец строки ;дпя вывода функцией 09h ml: ;вывести elem на экран endm В связи с последним фрагментом разберем ситуацию, когда тело макроопреде- ления содержит метку или имя в директиве резервирования и инициализации дан- ных. Если некоторая макрокоманда вызывается в программе несколько раз, то при макрогенерации один и тот же идентификатор будет определен несколько раз, что, естественно, транслятор посчитает ошибкой. Для выхода из подобной ситуации применяют директиву LOCAL, которая имеет следующий синтаксис: local список_идентификаторов Эту директиву необходимо указывать непосредственно за заголовком макро- определения. Результатом работы директивы LOCAL будет генерация в каждом эк- земпляре макрорасширения уникальных имен для всех идентификаторов, пере- численных в операнде список_идентификаторов. Эти уникальные имена имеют вид ??хххх, где хххх — шестнадцатеричное число. Для первого идентификатора в пер- вом экземпляре макрорасширения хххх = 0000, для второго — хххх = 0001 и т. д. Кон- троль правильности размещения и использования этих уникальных имен берет на себя транслятор ассемблера. Для того чтобы окончательно разобраться в деталях, введем и оттранслируем листинг 14.2. В нем помимо некоторых ранее рассмотрен- ных макрокоманд содержится макрокоманда num_char. Ее назначение — подсчи- тывать количество символов в строке, адрес которой передается этой макрокоман- де в качестве фактического параметра. Строка должна удовлетворять требованию, предъявляемому к строке, предназначенной для вывода на экран функцией 09h прерывания 21h, то есть заканчиваться символом $. Другой момент, который нашел отражение в этой программе, — использование символа & для распознава- ния формального аргумента в строке, заключенной в кавычки 11" (см. последний фрагмент).
Листинг 14.2. Второй пример создания и использования макрокоманд |
|
Макродирективы 305 В теле макроопределения можно размещать комментарии, и делать это особым образом. Если применить для обозначения комментария не один, как обычно, а два последовательных символа точки с запятой то при генерации макрорасшире- ния этот комментарий будет исключен. Если по какой-то причине необходимо присутствие комментария в макрорасширении, то его нужно задавать обычным образом, то есть с помощью одного символа точки с запятой, например: mes macro messsage ... ;этот комментарий будет включен в текст листинга ... ;;этот комментарий не будет включен в текст листинга епdm
Еще по теме Макрокоманды:
- Л.О. Доліненко, В.О. Доліненко, С.О. Сарновська. Цивільне право України, 2006
- ЦИВІЛЬНЕ ПРАВО УКРАЇНИ
- ПЕРЕДМОВА
- Частина І ПРОГРАМА КУРСУ «ЦИВІЛЬНЕ ПРАВО УКРАЇНИ»
- Розділ І. Загальні положення цивільного права
- Тема 1. Поняття цивільного права. Предмет та метод, система цивільного права. Функції та принципи цивільного права
- Тема 2. Цивільне законодавство України
- Тема 3. Поняття, елементи та види цивільних правовідносин
- Тема 4. Здійснення цивільних прав і виконання обов’язків
- Тема 5. Захист цивільних прав та інтересів
- Тема 6. Об’єкти цивільних прав
- Тема 7.ФІЗИЧНІ особи як суб’єкти цивільного права
- Тема 8. Юридичні особи