Рассмотрим схему реализации простой блочной структуры, аналогичной процедурам в Паскале или блокам в Си. Каждый блок может иметь свой набор описаний. Программа состоит из основного именованного блока, в котором имеются описания и операторы. Описания состоят из описаний типов и объявлений переменных. В качестве типа может использоваться целочисленный тип и тип
массива. Два типа T1 и T2 считаются эквивалентными, если имеется описание T1=T2 (или T2=T1). Операторами служат операторы присваивания вида Переменная1=Переменная2 и блоки. Переменная - это либо просто идентификатор, либо выборка из массива. Оператор присваивания считается правильным, если типы переменных левой и правой части эквивалентны. Примером правильной программы может служить
| program Example begin 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 end end. |
Рассматриваемое подмножество языка может быть порождено следующей грамматикой (запись в расширенной БНФ):
| Prog ::= 'program' Ident Block '.' Block ::= 'begin' [( Declaration )] [ (Statement) ] 'end' Declaration ::= 'type' ( Type_Decl ) Type_Decl ::= Ident '=' Type_Defin Type_Defin ::= 'ARRAY' Index 'OF' Type_Defin Type_Defin ::= Type_Use Type_Use ::= Ident Declaration ::= 'var' ( Var_Decl ) Var_Decl ::= Ident_List ':' Type_Use ';' Ident_List ::= ( Ident / ',' ) Statement ::= Block ';' Statement ::= Variable '=' Variable ';' Variable ::= Ident Access Access ::= '[' Expression ']' Access Access ::= |
|
for (V in S) Оператор; |
![]()
|
|
// Описание атрибутов ALPHABET Prog:: KEY TName SETOF TElement Env. // Корневая компонента, содержащая предопределенные описания. Block:: KEY TName SETOF TElement Env; 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. // Описание синтаксисических и семантических правил RULE Prog ::= 'program' Ident Block '.' SEMANTICS 0:{Init(Env); PreDefine(Env); Pred=NULL }. RULE Block ::= 'begin' [( Declaration )] [ (Statement) ] 'end' SEMANTICS 0: if (!=NULL){ Init(Env); Pred= }. RULE Declaration ::= 'type' ( Type_Decl ). RULE Type_Decl ::= Ident '=' Type_Defin SEMANTICS TElement V; if (Find(Val,Env)!=NULL) Error("Identifier declared twice"); // Идентификатор уже объявлен в блоке // В любом случае заносится новое описание V.Name=Val; V.Object=TypeObject; V.Type=ElementType; Include(V,Env). RULE Type_Defin ::= 'ARRAY' Index 'OF' Type_Defin SEMANTICS ElementType=ArrayType(ElementType,Val). RULE Type_Defin ::= Type_Use SEMANTICS ElementType=ElementType. RULE Type_Use ::= Ident SEMANTICS TElement * PV; PV=FindObject(Val,,TypeObject,); If (PV!=NULL) ElementType=PV->Type. // В этом правиле анализируется использующая позиция // идентификатора типа. RULE Declaration ::= 'var' ( Var_Decl ). RULE Var_Decl ::= Ident_List ':' Type_Use ';' SEMANTICS TElement V; TName N; for (N in Ident_Set){ // Цикл по (неупорядоченному) списку идентификаторов if (Find(N,Env)!=NULL) Error("Identifier declared twice"); // Идентификатор уже объявлен в блоке // В любом случае заносится новое описание V.Name=N; V.Object=VarObject; V.Type=ElementType; Include(V,Env) }. // N - рабочая переменная для элементов списка. Для каждого // идентификатора из множества идентификаторов Ident_Set // сформировать объект-переменную в текущей компоненте среды // с соответствующими характеристиками. RULE Ident_List ::= ( Ident /',' ) SEMANTICS 0:Init(Ident_Set); 1A:Include(Val,Ident_Set). RULE Statement ::= Block ';'. RULE Statement ::= Variable '=' Variable ';' SEMANTICS if (ElementType!=NULL) && (ElementType!=NULL) && (ElementType!=ElementType) Error("Incompatible Expression Types"). RULE Variable ::= Ident Access SEMANTICS TElement * PV; PV=FindObject(Val,,VarObject,); if (PV==NULL){ Error("Identifier used is not declared"); ElementType=NULL ; } else ElementType=PV->Type. RULE Access ::= '[' Expression ']' Access SEMANTICS ElementType=ArrayElementType(ElementType, ElementType). RULE Access ::= SEMANTICS ElementType=ElementType. |
|
TElement * FindObject(TName Ident, BlockPointer, TObject Object, 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 category is not found"); ElementPointer=NULL; } else // Объект не найден Error("Object is not found"); return ElementPointer; } |