Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Занесение в среду и поиск объектов






Рассмотрим схему реализации простой блочной структуры, аналогичной процедурам в Паскале или блокам в Си. Каждый блок может иметь свой набор описаний. Программа состоит из основного именованного блока, в котором имеются описания и операторы. Описания состоят из описаний типов и объявлений переменных. В качестве типа может использоваться целочисленный тип и тип массива. Два типа T1 и T2 считаются эквивалентными, если имеется описание T1=T2 (или T2=T1). Операторами служат операторы присваивания вида Переменная1=Переменная2 и блоки. Переменная - это либо просто идентификатор, либо выборка из массива. Оператор присваивания считается правильным, если типы переменных левой и правой части эквивалентны.

Примером правильной программы может служить

program Examplebegin type T1=array 100 of array 200 of integer; T2=T1; var V1: T1; V2: T2; begin V1=V2; V2[1]=V1[2]; begin type T3=array 300 of T1; var V3: T3; V3[50]=V1; end endend.

Рассматриваемое подмножество языка может быть порождено следующей грамматикой (запись в расширенной БНФ):

Prog:: ='program' Ident Block '.'Block:: ='begin' [(Declaration)] [(Statement)] 'end'Declaration:: ='type' (Type_Decl)Type_Decl:: =Ident '=' Type_DefinType_Defin:: ='ARRAY' Index 'OF' Type_DefinType_Defin:: =Type_UseType_Use:: =IdentDeclaration:: ='var' (Var_Decl)Var_Decl:: =Ident_List ': ' Type_Use '; 'Ident_List:: =(Ident / ', ')Statement:: =Block '; 'Statement:: =Variable '=' Variable '; 'Variable:: =Ident AccessAccess:: ='[' Expression ']' AccessAccess:: =

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

· 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 пробегает все значения множества. Если множество упорядочено, то элементы пробегаются в этом порядке, если нет - в произвольном порядке.

Среда представляет собой ключевое множество с ключом - именем объекта. Идентификаторы имеют тип TName. Обозначение< Нетерминал > в позиции типа - это указатель на вершину типа Нетерминал. Обозначение < Нетерминал > в выражении - это взятие значения указателя


Рис. 6.2.

на ближайшую вершину вверх по дереву разбора, помеченную соответствующим нетерминалом.

Для реализации среды каждый нетерминал Block имеет атрибут Env. Для обеспечения возможности просматривать компоненты среды в соответствии с вложенностью блоков каждый нетерминал Block имеет атрибут Pred - указатель на охватывающий блок. Кроме того, среда блока корня дерева (нетерминал Prog) содержит все предопределенные описания (рис. 6.2). Это заполнение реализуется процедурой PreDefine. Атрибут Pred блока корневой компоненты имеет значение NULL.

Атрибутная реализация выглядит следующим образом.

// Описание атрибутовALPHABET Prog:: KEY TName SETOF TElement Env.// Корневая компонента, содержащая предопределенные// описания. Block:: KEY TName SETOF TElement Env; < Block> Pred. Ident_List:: SETOF TName Ident_Set.// Ident_Set - список идентификаторов Type_Defin, Type_Use, Access, Expression:: TType ElementType.// ElementType - указатель на описание типаDeclaration, Var_Decl, Type_Decl::. Ident:: TName Val. Index:: int Val. // Описание синтаксических и семантических правилRULEProg:: = 'program' Ident Block '.'SEMANTICS0: {Init(Env< 3>); PreDefine(Env< 3>); Pred< 3> =NULL; }. RULEBlock:: = 'begin'[(Declaration)] [(Statement)]'end'SEMANTICS0: if (< Block>! =NULL){ Init(Env< 0>); Pred< 0> =< Block>; }. RULEDeclaration:: = 'type' (Type_Decl). RULEType_Decl:: = Ident '=' Type_DefinSEMANTICSTElement V; if (Find(Val< 1>, Env< Block>)! =NULL) Error(" Identifier declared twice"); // Идентификатор уже объявлен в блоке// В любом случае заносится новое описаниеV.Name=Val< 1>; V.Object=TypeObject; V.Type=ElementType< 3>; Include(V, Env< Block>). RULEType_Defin:: = 'ARRAY' Index 'OF' Type_DefinSEMANTICSElementType< 0> =ArrayType(ElementType< 4>, Val< 2>). RULEType_Defin:: = Type_UseSEMANTICSElementType< 0> =ElementType< 1>. RULEType_Use:: = IdentSEMANTICSTElement * PV; PV=FindObject(Val< 1>, < Block>, TypeObject, < Prog>); If (PV! =NULL)ElementType< 0> =PV-> Type.// В этом правиле анализируется использующая// позиция идентификатора типа. RULEDeclaration:: = 'var' (Var_Decl).RULEVar_Decl:: = Ident_List ': ' Type_Use '; 'SEMANTICSTElement V; TName N; for (N in Ident_Set< 1>){// Цикл по (неупорядоченному) списку// идентификаторов if (Find(N, Env< Block>)! =NULL) Error(" Identifier declared twice"); // Идентификатор уже объявлен в блоке// В любом случае заносится новое описание V.Name=N; V.Object=VarObject; V.Type=ElementType< 3>; Include(V, Env< Block>); }.// N - рабочая переменная для элементов списка.// Для каждого идентификатора из множества// идентификаторов Ident_Set< 1> сформировать// объект-переменную в текущей компоненте среды// с соответствующими характеристиками. RULEIdent_List:: = (Ident /', ')SEMANTICS0: Init(Ident_Set< 0>); 1A: Include(Val< 1>, Ident_Set< 0>). RULEStatement:: = Block '; '. RULEStatement:: = Variable '=' Variable '; 'SEMANTICSif (ElementType< 1>! =NULL) & & (ElementType< 3>! =NULL) & & (ElementType< 1>! =ElementType< 3>) Error(" Incompatible Expression Types"). RULEVariable:: = Ident AccessSEMANTICSTElement * PV; PV=FindObject(Val< 1>, < Block>, VarObject, < Prog>); if (PV==NULL){ Error(" Identifier used is not declared"); ElementType< 2> =NULL; }else ElementType< 2> =PV-> Type. RULEAccess:: = '[' Expression ']' AccessSEMANTICSElementType< 4> =ArrayElementType(ElementType< 0>, ElementType< 2>). RULEAccess:: =SEMANTICSElementType< Variable> =ElementType< 0>.Поиск в среде осуществляется следующей функцией: TElement * FindObject(TName Ident, < Block> BlockPointer, TObject Object, < Prog> Prog){ TElement * ElementPointer; // Получить указатель на ближайший// охватывающий блокdo{ElementPointer=Find(Ident, BlockPointer-> Env); BlockPointer=BlockPointer-> Pred; }while (ElementPointer==NULL)& & (BlockPointer! =NULL); // Искать до момента, когда либо найдем нужный// идентификатор, либо дойдем до корневой// компонентыif (ElementPointer==NULL)& & (BlockPointer==NULL)// Дошли до корневой компоненты и еще не нашли// идентификатора// Найти объект среди предопределенныхElementPointer=Find(Ident, Prog-> Env); if (ElementPointer! =NULL)// Нашли объект с данным идентификатором либо// в очередном блоке, либо среди предопределенныхif (ElementPointer-> Object! =Object){// Проверить, имеет ли найденный объект// нужную категориюError(" Object of specified categoryis not found"); ElementPointer=NULL; }else // Объект не найденError(" Object is not found"); return ElementPointer; }

Листинг 6.1.

Переменная BlockPointer - указатель на ближайший охватывающий блок. Переходя от блока к блоку, ищем объект в его среде. Если не нашли, то переходим к охватывающему блоку. Если дошли до корневой компоненты, пытаемся найти объект среди предопределенных объектов. Если объект нашли, надо убедиться, что он имеет нужную категорию.

Функция ArrayElementType(TType EntryType, TType ExprType) осуществляет проверку допустимости применения операции взятия индекса к переменной и возвращает тип элемента массива.

Функция ArrayType(TType EntryType, int Val) возвращает описание типа - массива с типом элемента EntryType и диапазоном индекса Val.

 






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.