Лекции по конструированию компиляторов. В.А. Серебряков (1134687), страница 12
Текст из файла (страница 12)
- удалить компоненту из среды.
Компоненты среды могут быть именованы. Поиск в среде обычно ведется с учетом упорядоченности компонент. Среда может включать в себя как компоненты, полученные при трансляции "текущего" текста программы, так и "внешние" компоненты.
Для обозначения участков программы, в которых доступны те или иные описания, используются понятия "область действия" и "область видимости". Областью действия описания является процедура (блок), содержащая описание, со всеми входящими в нее (подчиненными по дереву) процедурами (блоками). Областью видимости описания называется часть области действия, из которой исключены те подобласти, в которых по тем или иным причинам описание недоступно.
В разных языках понятия области действия и области видимости уточняются по-разному. В дальнейшем изложение ведется на примере языка Модула -2.
5.2. Структура среды Модулы-2
Имеются четыре рода языковых конструкций, которые могут содержать описания: 1) программный модуль или модуль реализации; 2) модуль определения; 3) процедура; 4) локальный модуль.
"Корневую" компоненту среды в Модуле-2 образует программный модуль или модуль реализации. Объекты этой компоненты могут быть описаны в самом модуле или могут быть импортированы из других модулей определений. Такой импорт может быть квалифицированным (from M import X,Y, ...;) или не квалифицированным (import M;).
Экспортирующий Компонента Импортирующий
локальный модуль среды локальный модуль
MODULE M1; MODULE X1;
EXPORT A1; A1 IMPORT A1;
A1
MODULE M2; MODULE X2;
EXPORT M2 FROM M2
QUALIFIED A2 IMPORT A2;
A2
A2
MODULE M3; MODULE X3;
EXPORT M31; M31 IMPORT A31;
A31
MODULE M31;
EXPORT A31; A31 MODULE X
IMPORT M31;
A31
MODULE M4; M41 MODULE X4;
EXPORT M41; FROM M41
IMPORT A41;
MODULE M41; A41
EXPORT A41
QUALIFIED A41; MODULE X
IMPORT M41;
A41
MODULE M5; M5 MODULE X5;
EXPORT FROM M5
QUALIFIED M51; IMPORT M51;
M51 M51.A51
MODULE M51;
EXPORT A51;
A51
MODULE M6; M6
EXPORT MODULE X6;
QULIFIED M61; FROM M6
M61 IMPORT M61
MODULE M61; M61.A61
EXPORT
QUALIFIED A61; A61
Рис. 5.2
В первом случае импортированные объекты становятся элементами среды данного модуля, во втором - сам импортированный модуль становится элементом среды, а его объекты могут быть доступны через указание имени модуля (M.X).
Область действия объектов, описанных в локальном модуле, может состоять из самого этого локального модуля или из охватывающего его блока, если объект экспортируется из локального модуля. Схему импорта в локальный модуль можно пояснить рис. 5.2. Существует предопределенная компонента, объекты которой доступны во всех других компонентах (если они там не переопределены). Эта компонента включает в себя типы данных такие как, integer, real, boolean, char, word, address, proc, константы true, false, nil, процедуры adr, tsize, cap, small, chr, inc, dec, float, halt, hihg, odd, ord, trunc, val, excl, incl, max, min, size, abs.
Элементом описания может быть процедура или локальный модуль, имеющие свой список описаний. Процедура образует новую компоненту среды, а локальный модуль - нет (рис. 5.3).
Модуль (программный или реализации)
Среда Свой модуль определений
Импорт из других
Объявления модулей определений
Импорт Видимость
Экспорт
Локальный модуль Процедура
................ .........
Рис. 5.3
Объекты локального модуля являются объектами охватывающей компоненты, но с ограниченными областями видимости. Внутри локального модуля доступны те и только те объекты этой компоненты, которые явно импортированы в локальный модуль. И наоборот: объекты локального модуля могут быть экспортированы в охватывающую компоненту. В то же время объекты процедуры образуют новую компоненту, поскольку объекты этой компоненты могут быть доступны в процедуре. Конфликт имен при этом не противоречит определению компоненты: объект охватывающей компоненты может быть виден (если внутри данной процедуры не описан объект с тем же именем).
Среда состоит из отдельных объектов, реализуемых как записи. Состав полей записи вообще говоря зависит от объекта (тип, переменная и т.д.), но есть поля, входящие в запись для любого объекта:
Tobject Object - категория объекта: тип, переменная, процедура и т.д.;
Tmode Mode - вид объекта: целый, массив, запись и т.д.;
Tname Name - имя объекта;
Ttype Type - указатель на описание типа.
5.3. Занесение в среду и поиск объектов
Поскольку блоки образуют иерархию на дереве разбора программы, при поиске объекта мы можем с помощью атрибута типа "указатель на блок" переходить от блока к охватывающему блоку. Если теперь у каждого блока есть атрибут, указывающий, является ли блок процедурой или модулем, то легко реализовать сочетание блочной структуры со средствами управления видимостью. Кроме того, корень дерева имеет атрибут, соответствующий предопределенной компоненте, так что через этот глобальный атрибут доступны все предопределенные описания (рис. 5.4).
Env
^ ^
/ \
Env Env
^^ ^^
/ \ / \
Env Env Env Env
Рис. 5.4
В качестве типов данных атрибутов мы будем использовать множество. Множество может быть упорядоченным или неупорядоченным, ключевым или простым. Элементом ключевого множества может быть запись, одним из полей которой является ключ:
SETOF T - простое неупорядоченное множество объектов типа T;
KEY K SETOF T - ключевое неупорядоченное множество объектов типа T с ключом типа K;
LISTOF T - простое упорядоченное множество объектов типа T;
KEY K LISTOF T - ключевое упорядоченное множество объектов типа T с ключом типа K;
Над объектами типа множества определены следующие операции:
Init(S) - создать и проинициализировать переменную S;
Include(V,S) - включить объект V в множество S; если множество упорядоченное, то включение осуществляется в качестве последнего элемента;
Find(K,S) - выдать указатель на объект с ключом K во множестве S и NIL, если объект с таким ключом не найден.
Имеется специальный оператор цикла, пробегающий элементы множества:
for (V in S) Оператор;
Переменная V локализована в теле оператора и пробегает все значения множества. Если множество упорядочено, то элементы пробегаются в этом порядке, если нет - в произвольном порядке.
Среда представляет собой ключевое множество с ключом - именем объекта. Каждый локальный модуль имеет атрибут - множество импортируемых объектов и атрибут - множество экспортируемых объектов. Экспортируемые модулем объекты в соответствии с правилами экспорта включаются в компоненту среды, в которую входит сам модуль. Ниже приведен фрагмент описания контекстных условий языка Модула-2 (в фигурные скобки заключены комментарии).
ALPHABET
Prog:: KEY TName SETOF Element Env.
Предопределенная компонента. Идентификаторы имеют тип Name.
Block :: KEY Name SETOF Element Env;
bool Kind;
Block * Pred.
Арибут Kind равен true для процедур и false для модулей. Env - множество объявлений блока. Pred - указатель на охватывающий блок.
Mod_Head :: Element * Entry;
SETOF Import_Pair Imp_Set;
bool Mode.
Imp_Set - множество импортируемых модулем объектов; тип Import_Pair - запись из двух полей: Imp_Name:Name - имя импортируемого объекта, и Name_Set:Set of Name - список импортируемых из модуля объектов, если импорт квалифицированный, и Nil, если неквалифицированный; Entry - указатель на вход для модуля; Mode - признак квалифицированного экспорта.
Import :: SETOF Name Imp_Set.
Imp_Set - список квалифицированного импорта.
Export :: bool Mode.
Mode - признак квалифицированного экспорта.
From :: bool Qual; TName Name.
Qual :: bool Qual.
Ident_List :: SETOF Name Ident_Set.
Type_Des :: Element * Exit.
Qual - признак квалифицированного импорта; Name - имя модуля, из которого делается импорт; Ident_Set - список идентификаторов; Exit - указатель на описание типа.
RULE
Declaration ::= 'procedure' Ident [ Formal_Param ] ';'
Block ';'
SEMANTICS
Element* Entry;
Kind<5>=true;
2:if (Find(Val<2>,Env<Block>)!=NULL)
Error("Identifire declared twice");
Entry=Include(Val<2>,Env<Block>);
Entry->Object=ProcObject.
Помещение процедуры; ищем объект с данным именем в текущей компоненте; Entry - указатель на вход для процедуры. Если объект с таким именем уже есть, - ошибка.
RULE
Declaration ::= 'module' Ident Mod_Head Block ';'
SEMANTICS
Import_Pair M;
Element * V;
if (Find(Val<2>,Env<Block>)!=NULL)
Error("Identifire declared twice");