Макропроцессоры, встроенные в трансляторы 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Макропроцессоры, встроенные в трансляторы



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

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

Подобный подход имеет несколько преимуществ. Он позволяет избежать дополнительного прохода по программе (записи ее в промежуточный файл и последующего чтения) и в результате может быть более эффективным, чем использование макропроцессора. Некоторые таблицы, требующиеся и макропроцессору, и транслятору, могут быть объединены. Напримертаблица ОВТАВ в ассемблере и таблица NAMTAB в макропроцессоре могут быть реализованы в виде одной таблицы. Кроме того, многие вспомогательные программы и функции могут использоваться как транслятором, так и макропроцессором. Сюда относятся операции сканирования входной строки, поиска по таблицам, преобразование числовых констант из внешнего во внутреннее представление. В рамках этого подхода облегчается привязка диагностических сообщений к предложению исходной программы, вызвавшей ошибку (т. е. к соответствующему предложению макроинициализации). При использовании макропроцессора подобная ошибка может быть отнесена только к соответствующему предложению макрорасширения. Программист будет в этом случае самостоятельно искать исходную причину ошибки.

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

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

Сканирование лексем, о котором только что шла речь, концептуально очень просто. Однако многие существующие языки программирования имеют особенности, доставляющие определенные трудности и на этом этапе. Классическим примером является предложение Фортрана

DO 100 I = 1, 20

Это оператор цикла DO, где DO распознано как ключеное слово, 100 метка предложения, 1-имя переменной и т. д. Поскольку пробелы никак не учитываются в предложениях Фортрана (кроме символьных констант), похожее предложение

DO 100 I = l

имеет совершенно другой смысл. Это оператор присваивания переменной DO100I значения 1. Таким образом, правильная интерпретация термов DO100, I не может быть осуществлена до тех пор, пока не проведен анализ всего предложения. Такая интерпретация будет очень важна, например, в случае, если макропроцессор должен заменить переменную с именем I. Компилятор с Фортрана обязан разбираться с подобными ситуациями. Однако для обычного макропроцессора (нe встроенного в компилятор) это сделать очень трудно. Такой макропроцессор может иметь дело с предложениями исходной программы только как со строками символов, не имея возможности выделить их отдельные элементы.

При более тесной связи с транслятором встроенный макропроцессор может обрабатывать макроинструкции, смысл которых зависит от того контекста, в котором они оказались. На пример, с помощью такого макроса можно задать замену имен только переменных или констант определенного типа либо только переменных, являющихся переменными цикла в предложениях DO. Процесс макрогенерации может также зависеть от множества характеристик аргументов предложения макроинициализации. (Примером может служить описание макропроцессора System/370 в разд. 4.5.1.)

Макропроцессоры, тесно связанные с транслятором, имеют, конечнои свои недостатки. Они должны быть спроектированы специально для работы с конкретной реализацией некоторого ассемблера или компилятора (а не просто для работы с языком программирования). Стоимость разработки такого макропроцессора должна быть прибавлена к стоимости разработки транслятора, что приводит к более дорогим компонентам математического обеспечения. Кроме того, ассемблер или компилятор становится больше и сложнее, чем это было бы в случае использования макропропроцессора. Размер транслятора может представлять собой проблему, если транслятор предназначен для работы на ЭВМ с ограниченной оперативной памятью. В любом случае увеличиваются накладные расходы на трансляцию. (Некоторые ассемблеры со встроенными макропроцессорами требуют больше времени на обработку одной строки исходной программы, чем некоторые компиляторы на той же самой ЭВМ.) Решение вопроса о типе макропроцессора, который должен использоваться, опирается на данные о предполагаемой частоте и сложности макрогенерации и другие характеристики операционного окружения.

Примеры реализации

В этом разделе мы кратко опишем три реальных макропроцессора. Как и раньше, не будем пытаться охватить все характеристики каждой системы, а сосредоточимся на наиболее интересных особенностях. Первые два примера посвящены макропроцессорам, тесно связанным с ассемблером (для System/370 и ЭВМ серии VAX). Третий пример - макропроцессор общего назначения, предназначенный для использования в качестве препроцессора с самыми различными языками программирования.

 

Макропроцессор System/370

Рассматриваемый в этом разделе макропроцессор Sуstem/370 тесно связан с ассемблером этой системы. Он обеспечивает все функции макропроцессора, которые мы обсуждали, включая обработку макроопределении и макроинициализаций внутри тела макроопределения. В макроииструкциях могут использоваться позиционные или ключевые параметры либо смесь позиционных и ключевых параметров. Управляющие предожения позволяют пользователю задавать различные режимы работы макропроцессора, например разрешить или запретить появление предложений текста макрорасширения в листинге исходной программы. Комментарии в теле макроопределений могут игнорироваться, а могут и остаться в листинге ассемблера в зависимости от способа их записи.

Существенное отличие макропроцессора System/370 от рассмотренного нами макропроцессора для УУМ состоит в структуре предложений условной макрогенерации. В макроязыке для System/370 они называются предложениями условного ассемблирования. Хотя эти предложения и предназначены в основном для макрогенерации, они могут появиться также и вне макроопределений. Язык ассемблера System/370, дополненный операторами условного ассемблирования, допускает использование переменных периода ассемблирования, которые аналогичны обсуждавшимся выше переменным периода макрогенерации. Этим переменным могут быть присвоены арифметические, двоичные или символьные значения. Этим трем типам значений соответствуют три типа таких переменных. Переменные периода ассемблирования могут быть как локальными, так и глобальными. На локальные переменные можно ссылаться только внутри того макроопределения или такой подпрограммы на ассемблере, которые содержат их определения. Если локальные переменные, имеющие одно имя, будут определены в нескольких макроопределениях, то транслятор будет рассматривать их как различные переменные. Глобальные переменные могут использоваться в любом месте программы. Так, например, глобальной переменной может быть присвоено значение в момент обработки одного макроса, а использоваться это значение может в другом макросе.

Предложения условного ассемблирования, управляющие порождением строк результирующей программы, существенно отличны от условных предложений периода макрогенерацип для УУМ. Базовой управляющей конструкцией является оператор перехода периода ассемблирования. При выполнении такого перехода ассемблер (или макропроцессор) прерывает последовательную обработку предложений программы и в качестве очередного предложения берет то, которое указано в операторе перехода. Эти переходы могут быть как "вниз", так и "вверх" по входному потоку.

На рис. 4.12 изображены примеры макроопределения и текста макрорасширения с использованием макроязыка System/370. Это макроопределение предназначено для генерации кода, осуществляющего сложение двух элементов данных и запоминание результата. В зависимости от типа аргументов - целые или с плавающей точкой - порождается различный код. Если аргументы имеют какой-либо другой или не совпадающий между собой тип, то генерируется сообщение об ошибке. Форма макроопределения на рис. 4.12а в основном та же, что и в наших предыдущих примерах. Макроопределение начинается предложением MACRO и заканчивается предложением MEND.

 

1 MACRO

2 &NAМE ADD &OP1,&OP2,&SUM

3 LCLC &TYPE

4 AIF (T'&OP1 NE Т'&ОР2).MIXTYP

5 AIF (T'&OP1 EQ 'F').INTGR

6 AIF (T'&OP1 EQ 'E').FLOAT

7 AGO.TYPERR

8.FLOAT ANОР

9 &TYPE SETC 'E'

10.INTGR ANOP

11 &.NAME L&.TYPE 2,&OP1

12 A&.TYPE 2,&OP2

13 ST&.TYPE 2,&SUM

14 MEXIT

15.MIXTYP MNOTE 'СМЕШАННЫЕ ТИПЫ ОПЕРАНДОВ'

16 MEXIT

17.TYPERR MNOTE 'НЕДОПУСТИМЫЙ ТИП ОПЕРAНДОВ'

18 MEND

a

 

LAB ADD I,J,K

 

LAB L 2,I

A 2,J

ST 2,K

б

 

ADD X,Y,Z

 

LE 2,X

AE 2,Y

STE 2,Z

в

 

ADD I,Y,Z

 

*** СМЕШАННЫЕ ТИПЫ ОПЕРАНДОВ

г

Рис. 4.12. Примеры макроопределения и макрорасширений для System/370.

 

Макропрототип расположен сразу же за предложением MACRO (строка 2).Все макропараметры и переменные периода ассемблирования начинаются символом &. В этом примере используются только позиционные параметры.

Предложение LCLC в строке 3 определяет переменную &TIPE строкового типа. Эта переменная определена как локальная в том макроопределении, в котором она описана. По умолчанию ей присваивается начальное значение - пустая строка. Предложение в строке 4 (AIF) является предложением условного перехода периода ассемблирования. Ассемблер вычисляет булевское выражение в скобках и переходит на обработку другого места исходной программы, если это выражение истинно. В противном случае ассемблер продолжает обрабатывать следующую строку исходной программы. В нашем примере адрес перехода задается с помощью специальной метки MIXTYP, которая описана в строке 15. Аргументами булевского выражения в предложении AIF являются типы параметров макроопределения. Тип параметра &OP1 (обозначаемый T'&OP1) есть символ F, если соответствующий параметр является целой переменной длиной в одно слово, и символ Е, если он является числом с плавающей точкой. Таким образомпредложение AIF в строке 4 определяет переход к строке 15, если типы двух параметров различны. Если же их типы совпадают, то ассемблер продолжает работу со строки 5. Другое предложение AIF имеет аналогичную структуру.

Предложение AGO в строке 7 является оператором безусловного перехода периода ассемблирования, предложение ANOP (строки 8 и 10) - пустым оператором. Эти предложения используются для описания меток FLOAT и INTGR. В строках 14-17 содержатся макродирективы двух новых типов. Предложение MNOTE вызывает печать сообщения об ошибке в листинге ассемблера. Реакция ассемблера на это сообщение будет такой же, как реакция на собственную ошибку. Предложение MEXIT предписывает макропроцессору закончить процесс порождения текста макрорасширения текущего предложения макроинициализации, несмотря на то что предложение MEND еще не встретилось.

На рис. 4.12б-г изображены предложения макроинициализации и соответствующие им макрорасширения. Предполагается, что I, J и К являются целыми переменными длиной в одно слово, а X, Y, Z - переменными с плавающей точкой. Чтобы убедиться, что вы правильно понимаете работу предложений AIF и AGO, вам необходимо проследить по шагам весь процесс макрогенерации, используя макроопределение на рис.4.12а.

В рассмотренном примере предложения AIF и AGO обеспечивают действия, эквивалентные конструкции IF-ELSE- ENDIF. Поскольку цикл WHILE также может быть запрограммирован c использованием предложений AIF и AGO, эти средства дают широкоие возможности условного ассемблирования. Однако предложения AIF и AGO труднее реализовать (и, вообще говоря, менее удобно использовать), чем предложения IF и WHILE, используемые для УММ. Предложения условной макрогенерации для УУМ аналогичны управляющим операторам структурированного языка, подобного Паскалю. Предложения условного ассемблирования в System/370 больше похожи на средства неструктурированного языка, такого как Фортран IV.

В примере на рис. 4.12 предложение AIF использовалось для проверки типа макроаргументов. Имеется множество других характеристик переменных и аргументов, которые могут использоваться сходным образом. Эти характеристики называются атрибутами соответствующих переменных и аргументов. В предложениях условного ассемблирования допустимо ссылаться на атрибуты объектов, определения которых еще не встречались в исходной программе. В результате ассемблер System/370 должен делать предварительный просмотр всей исходной программы, запоминая атрибуты объектов, которые будут определены лишь в процессе макрогенерации.

Макропроцессор System/370 позволяет использовать ряд системных переменных. Можно считать, что они определены заранее и поэтому могут использоваться при макрогенерации. Примерами таких системных переменных могут служить текущая дата, время работы ассемблера, имя текущего управляющего раздела. Одна из системных переменных &SISNDX предназначена для генерации уникальных меток. Значением переменной &SISNDX является четырехразрядное целое число, первоначально равное 0001 и увеличивающееся на 1 при обработке каждого предложения макроинициализации. Используя эту переменную в качестве составной части метки, программист может избежать дважды определенных меток. Например, L&SISNDX может принять значения L0001, L0002 и т.д. при последовательной обработке предложений макроиициализации. Подробная информация о макропроцессоре System/370 содержится в IBM [1979] и IBM [1974].

 

 

Макропроцессор системы VAX

Макропроцессор системы VAX также сильно связан с ассемблером этой системы. Настолько сильно, что сам язык ассемблера назван VAX-11 и MACRO. Принципы записи макроопределений и предложений макроинициализаций те же, что и для УУМ, но есть и интересные отличия.

Имена параметров макроинструкций не обязаны начинаться с & или какого-либо другого специального символа. В результате процесс сканирования для обнаружения параметров усложняется. Кроме того, чаще должен использоваться оператор конкатенации. Рассмотрим в качестве примера макроопределение на рис. 4.13а. В предложении

3 TSTL R'NUM

операндом является символ R, конкатенированный со значением параметра NUM. Для обозначения операции конкатенации в макроязыке системы VAX используется апостроф '. Если бы этот операнд был записан просто как RNUM, то последовательность символов NUM не была бы распознана в качестве макропараметра. Таким образом, оператор конкатенации тут совершенно необходим. Сравните эту ситуацию с примером на рис. 4.12. В строке 13 этого примера не требуется никакого оператора конкатенации при записи терма ST&TYPE, поскольку амперсанд является признаком тогочто &TYPE является параметром. Вообще токаря, макропроцессор мог бы распознать последовательность символов NUM на рис. 4.12 как имя параметра без оператора конкатенации. Однако в этом случае макропроцессор должен был бы иметь средства, позволяющие запретить подстановку параметров (например, мы можем не за хотеть, чтобы NUMBER было превращено в 5BER). Если же макропараметр не сконкатенирован ни с какими другими символами, то апостроф, конечно же, не нужен.

Макропроцессор системы VAX также предоставляет средства генерации уникальных локальных меток при макрогенерации. Программист описывает локальную метку, путем включения ее в список параметров макроопределения, добавив предварительно перед именем метки символ?. Задав соответствующий аргумент в предложении макроинициализации, можно дать этой метке произвольное значение. Если же оно не определено, то ассемблер сгенерирует новую локальную метку. Метки, генерируемые ассемблеромнаходятся в диапазоне З0000$-65535$

Этот процесс проиллюстрирован макроопределением на рис. 4.13апредложениями макроиинциализации и соответствующими макрорасширениями на рис. 4.13б-в. В первом макрорасширении метка L1 заменена на З0000$; во втором - на З0001$. Программист может также определить локальные метки вне тела макроопределения (в предложении макроинициализации). Однако, чтобы не было пересечений с метками, генерируемыми макросредствами, документация ассемблера требует, чтобы метки пользователя не попадали в интервал З0000$ - 65535$. Вы можете сами проследить процесс получения макрорасширения на рис. 4.13, обращая внимание на использование операторов конкатенации и локальных меток.

Дальнейшая информация о макропроцессоре системы VAX содержится в DEC [1972] и DEC [1979].

 

1.МACRO ABSDIF OP1,OP2,SIZE.NUM,?L1

2 SUB'SIZE'3 OPl,OP2,R'NUM

3 TSTL R'NUM

4 BGEQ L1

5 MNEGL R'NUM,R'NUM

6 L1:.ENDM ABSDIF

а

 

ABSDIF X,Y,L,0

 
 

 


SUBL3 X,Y,R0

TSTL R0

BGEEQ 30000$

MNEGL R0,R0

30000$:

б

 

Рис. 4.13. Примеры макроопределения и макрорасширений для ЭВМ серии VAX.

ABSDIF I,J,W,2

 

 

SUBL3 I,J,R2

TSTL R2

BGEEQ 30001$

MNEGL R2,R2

30001$:

в

 

Рис. 4.13. Примеры макроопределения и макрорасширений для ЭВМ серии VAX.

 



Поделиться:


Последнее изменение этой страницы: 2017-02-17; просмотров: 200; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.217.208.72 (0.044 с.)