CodeNet / Приложения / Алгоритмы / Разбор выражений. Компиляторы и интерпретаторы. / Лекции по конструированию компиляторов
Лекции по конструированию компиляторов - Глава 6. Контекстные условия языков программирования
6.1. Описание областей видимости и блочной структуры Задачей контекстного анализа является установление правильности использования объектов. Наиболее часто решаемой задачей является определение существования объекта и соответствия его использования контексту, что осуществляется с помощью анализа типа объекта. Таким образом необходимо хранить объекты, их типы, уметь находить эти объекты и определять их типы, определять характеристики контекста. Совокупность доступных в даной точке объектов будем называть "средой". Обычно среда программы состоит из частично упорядоченного набора компонент E={DS1,...DSn}. Каждая компонента - это множество объявлений, представляющих собой пары : DSi={}, где под типом будем подразумевать полное описание свойств объекта (объектом, в частности, может быть само описание типа). Между компонентами DSi и DSj имеет место отношение "DSi включает DSj" тогда и только тогда, когда любой объект из DSi может быть доступен из DSj (конкретный способ доступа определяется правилами видимости языка), но не наоборот. Компоненты образуют дерево. Это дерево соответствует блокам или процедурам (рис. 6.1 +-------------+ | Корневая | | компонента | | (программа) | +-------------+ +---------+ | +--------+ | | | +-----------++-----------++-----------+ | процедура || процедура || процедура | | (блок) || (блок) || (блок) | +-----------++-----------++-----------+ /|\ /|\ /|\ Рис. 6.1 Обычными операциями при работе со средой являются: - включить объект в компоненту среды; - найти объект в среде и получить доступ к его описанию; - образовать в среде новую компоненту, определенным образом связанную с остальными; - удалить компоненту из среды. Компоненты среды могут быть именованы. Поиск в среде обычно ведется с учетом упорядоченности компонент. Среда может включать в себя как компоненты, полученные при трансляции "текущего" текста программы, так и "внешние" компоненты. Для обозначения участков программы, в которых доступны те или иные описания, используются понятия "область действия" и "область видимости". Областью действия описания является процедура (блок), содержащая описание, со всеми входящими в нее (подчиненными по дереву) процедурами (блоками). Областью видимости описания называется часть области действия, из которой исключены те подобласти, в которых по тем или иным причинам описание недоступно. В разных языках понятия области действия и области видимости уточняются по-разному. В дальнейшем изложение ведется на примере языка Модула -2. 6.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; | | | +------------+ | EXPORT | | +----+ | | MODULE X2; | | QUALIFIED A2-+------+-->| M2 | | | FROM M2 | | ............ | | +----+ | | IMPORT A2; | +--------------+ | v | +---+---->A2 | | +----+ | | +------------+ | | A2 |---+-+ | +----+ | +-----------------+ | | | MODULE M3; | | +-----+ | | EXPORT M31;-----+---+-->| M31 | | +-------------+ | +-------------+| | +-----+ | | MODULE X3; | | | MODULE M31; || | +-----+ | | IMPORT A31; | | | EXPORT A31;-++---+-->| A31 |--+-----+--> A31 | | | .......... || | +-----+ | | +-------------+ | +-------------+| | | | | ................| | | | +-------------+ +-----------------+ | | | | MODULE X | | | | | IMPORT M31; | | | +--+---> A31 | v v +-------------+ +-------------------+ v v | MODULE M4; | | +-----+ | | EXPORT M41;-------+-+-->| M41 | | +-------------+ | +---------------+| | +-----+ | | MODULE X4; | | | MODULE M41; || | v | | FROM M41 | | | EXPORT || | +-----+ | | IMPORT A41; | | | QUALIFIED A41;|+-+-->| A41 |--+-----+----> A41 | | | .......... || | +-----+ | | +-------------+ | +---------------+| | | | +--------------+ | ..................| | | | | MODULE X | +-------------------+ | | | | IMPORT M41; | | | +--+-->A41 | | | +--------------+ +-----------------+ | +----+ | | MODULE M5; | | | M5 | | +-------------+ | EXPORT | | +----+ | | MODULE X5; | | QUALIFIED M51;--+---+-+ v | | FROM M5 | | +-------------+| | | +-----+ | | IMPORT M51; | | | MODULE M51; || | +->| M51 |-+------+-> M51.A51 | | | EXPORT A51;-++---+-+ +-----+ | +-------------+ | | .......... || | | v | | +-------------+| | | +-----+ | | ................| | +->| A51 | | +-----------------+ | +-----+ | +-------------------+ | +----+ | | MODULE M6; | | | M6 | | +-------------+ | EXPORT | | +----+ | | MODULE X6; | | QULIFIED M61;-----+-+-+ v | | FROM M6 | | +---------------+| | | +-----+ | | IMPORT M61; | | | MODULE M61; || | +->| M61 |-+------+--> M61.A61 | | | EXPORT || | +-----+ | +-------------+ | | QUALIFIED A61;|+-+-+ v | | | ............ || | | +-----+ | | +---------------+| | +->| A61 | | | ..................| | +-----+ | +-------------------+ +------------+ Рис. 6.2 В первом случае импортированные объекты становятся элементами среды данного модуля, во втором - сам импортированный модуль становится элементом среды, а его объекты могут быть доступны через указание имени модуля (M.X). Область действия объектов, описанных в локальном модуле, может состоять из самого этого локального модуля или из охватывающего его блока, если объект экспортируется из локального модуля. Схему импорта в локальный модуль можно пояснить рис. 6.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. Элементом описания может быть процедура или локальный модуль, имеющие свой список описаний. Процедура образует новую компоненту среды, а локальный модуль - нет (рис. 6.3). Объекты локального модуля являются объектами охватывающей компоненты, но с ограниченными областями видимости. Внутри локального модуля доступны те и только те объекты этой компоненты, которые явно импортированы в локальный модуль. И наоборот: объекты локального модуля могут быть экспортированы в охватывающую компоненту. В то же время объекты процедуры образуют новую компоненту, поскольку объекты этой компоненты могут быть доступны в процедуре. Конфликт имен при этом не противоречит определению компоненты: объект охватывающей компоненты может быть виден (если внутри данной процедуры не описан объект с тем же именем). Модуль (программный или реализации) +------------+ | Среда |:=true; 2:if Find(Val,Env)Nil then Error("Identifire declared twice"); end; Entry:=Include(Val,Env); Entry@.Object:=ProcObject. Помещение процедуры; ищем объект с данным именем в текущей компоненте; Entry - указатель на вход для процедуры. Если объект с таким именем уже есть, - ошибка. RULE Declaration ::= 'module' Ident Mod_Head Block ';' SEMANTICS var M:Import_Pair; V:Element; if Find(Val,Env)Nil then Error("Identifire declared twice") end; Entry:=Include(Val,Env); Entry@.Object:=LocalModuleObject; Kind:=false; 3: for M in Imp_Set do Inc_Imp(M,Env); end; if (Mode=NotQual) then for V in Entry@.Exp_Set do Export(V,Env); end end. Помещение модуля; ищем объект с данным именем в текущей компоненте. Если такой уже есть, - ошибка. Заносим в текущую компоненту среды объект-модуль. Множество Imp_Set - это множество импортируемых модулем объектов. Элементы этого множества - пары, первая компонента которых - имя импортируемого модуля, вторая - список импортируемых из него объектов. Если вторая компонента Nil, то импорт неквалифицированный. Если импортируемый объект M - модуль и если M импортируется неквалифицированно (IMPORT M), то процедура Inc_Imp включает M в среду текущего модуля; если импорт квалифицированный (FROM M IMPORT ...), то M имеет список импорта и процедура Inc_Imp включает в текущую компоненту те экспортируемые из M объекты, которые перечислены в списке квалифицированного импорта; если при этом импортируемый объект - в свою очередь модуль, то из M рекурсивно импортируется все его экспортные объекты. Атрибут Mode вычисляется в правиле для экспорта и определяет, осуществляется ли квалифицированный экспорт (EXPORT QUALIFIED ...) или нет (EXPORT ...). Процедура Export в случае неквалифицированного экспорта EXPORT A1,A2,... все объекты экспортного списка модуля заносит в компоненту среды, охватывающую модуль; если Ai - модуль, его экспорт обрабатывается рекурсивно; если экспорт квалифицированный, то в охватывающую модуль компоненту попадает только сам модуль со списком экспорта. RULE Block ::= [( Declaration )] [ Block_St_Seq ] 'end' Ident SEMANTICS 0:Init(Env); Pred:=@. Атрибут Pred - указатель на охватывающий блок. RULE Mod_Head ::= [ Priority ] ';' [ ( Import ) ] [ Export ] SEMANTICS 4E: Mode:=NotQual; Entry@.Mode:=Mode; Mode:=Mode; 0:Init(Imp_Set). Инициализируется список импорта. Тип экспорта заносится в описание модуля. RULE Import ::= [ From ] 'import' ( Ident /',' ) ';' SEMANTICS var Tmp:Import_Pair; 0:Init(Imp_Set); 1E: Qual:=false; 3A:if Qual then Include(Val,Imp_Set) else Tmp.Name_Set:=Nil; Tmp.Imp_Name:=Name; Include(Tmp,Imp_Set) end; if Qual then Tmp.Name_Set:=Imp_Set; Tmp.Imp_Name:=Name; Include(Tmp,Imp_Set) end. Если импорт квалифицированный, то Name - имя модуля, из которого делается импорт. В этом случае Imp_Set - множество импортируемых из него объектов. Идентификатор включается в список импорта из модуля, иначе идентификатор - имя модуля и он включается в список импортируемых модулей. Если импорт квалифицированный, включить в список импорта модуля весь список импортируемых объектов. RULE From ::= 'from' Ident SEMANTICS Qual:=true; Name:=Val. RULE Export ::= 'export' [ Qual ] ( Ident /',' ) SEMANTICS 0: Init(Entry@.Exp_Set); 2Е: Mode:=NotQual; Mode:=Mode; 3A: Include(Val,Entry@.Exp_Set). Включить идентификатор в экспортный список модуля; множество экспортируемых модулем объектов заносится в поле Exp_Set : Key Name Set Of Element в таблице объектов, поскольку при использовании квалифицированного импорта или обращении M.V, где M - имя модуля, а V - имя экспортируемого объекта, необходимо иметь доступ к списку квалифицированного экспорта. RULE Qual ::= 'qualified' SEMANTICS Qual:=Qualified RULE Declaration ::= 'var' ( Var_Decl ). RULE Var_Decl ::= Ident_List ':' Type_Des ';' SEMANTICS var V:Name; for V in Ident_Set do if (Find(V,Env)Nil) then Error("Identifire declared twice") end; Include(V,Env); V@.Object:=VarObject; V@.Type:=Exit; end. V - рабочая переменная для элементов списка. Для каждого идентификатора из множества Ident_Set сформировать объект- переменную в текущей компоненте среды с соответствующими характеристиками. RULE Ident_List ::= ( Ident /',' ) SEMANTICS 0:Init(Ident_Set); 1A:Include(Val,Ident_Set). RULE Type_Des ::= Ident SEMANTICS var P:pointer to Block; P:=Block@; repeat Exit:=Find(Val,P@.Env); if P@.Kind then P:=P@.Pred end; until (ExitNIL)or(not P@.Kind); if (Exit=NIL) then Exit:=Find(Val,Env) end; if (Exit=Nil) then Error("тип не найден") else if (Exit@.ObjectTypeObject) then Error("Not type object"); Exit:=Nil; end end. Рабочая переменная P - указатель на ближайший охватывающий блок. Переходя от блока от блоку, ищем объект в его среде. Если не нашли, то, если блок - процедура, перейти к охватывающей. Если дошли до границы модуля, попытаться найти объект в предопределенной компоненте. Если объект нашли, надо убедиться, что он - тип. Зависимости атрибутов на дереве разбора приведены на рис. 6.5. +--------------------+ | | | Block | EnvEnv | v | | | +-----> Imp_Set | Mod_Head | Exp_SetНазад | Оглавление | Вперед