nextupprevious

Next:1.4 Выражения
Up:1 Язык программирования Zonnon
Previous:1.2 Языковые символы и идентификаторы


1.3 Описания

1.3.1. Описание идентификаторов и правила области действия

Каждый идентификатор, встречающийся в программе, должен быть введен в объявлении, если он не является предопределенным. Объявление специфицирует также определенные перманентные свойства элемента, такие как является ли он константой, типом, переменной (см. 1.3.4) или процедурой (см. 1.6). Идентификатор затем используется в качестве ссылки на соответствующий элемент.

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


QualIdent = { ident "." } ident.

Примеры:

Month.Oct (* см 1.3.3.2 *)
NameSpace.Program
 

1.3.1.1. Модификаторы объявлений


Объявление может иметь факультативный модификатор. Модификаторы объявлений определяются следующим образом:


Пример:

var {private} flag: boolean;
var {public, immutable} refCount: integer; (*доступ только для чтения*)
 

1.3.2. Объявление констант


Объявление константы связывает идентификатор с константным значением.

ConstantDeclaration = ident "=" ConstExpression.
ConstExpression = Expression.

Примеры:

const N = 10;
          limit = 2*N – 1; (* see 1.5.2.3*)
          fullSet = {min(set) .. max(set)}; (* см. 1.3.3.1*)

Константное выражение – это выражение, которое может быть вычислено при простом текстовом просмотре, без реального выполнения программы. Его операндами должны быть константы или вызовы предопределенных функций.

1.3.3. Объявление типа


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

TypeDeclaration = ident "=" Type.
Type = ( TypeName [ Width ] | EnumType | ArrayType | ProcedureType | InterfaceType ).
Width = "{" ConstExpression "}".
 

1.3.3.1. Базисные типы


Базисные типы обозначаются предопределенными идентификаторами. Ассоциированные знаки операций определены в 1.4.2, предопределенные функции и процедуры в 1.7. Значения базисных типов следующие:


Заметим, что object является зарезервированным словом.

Для типов char, integer, real и set количество битов, необходимых для хранения значения, может быть специфицировано указанием целого числа битов в виде константного значения в скобках { } после имени типа после имени типа – так называемой ширины (width) типа. По умолчанию используются следующие следующие значения ширины для базисных типов:

char{16}, cardinal {32}, integer{32}, real {80}, set{32}, fixed {128}

О конвертации между различными типами см. 1.3.3.9.
 

1.3.3.2. Перечисляемые типы


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

EnumType = "(" IdentList ")".
IdentList = ident { "," ident }.

Примеры:

type NumberKind = (Bin, Oct, Dec, Hex);
        Month = (Jan, Feb, Mar, Apr, May, Jun, July, Sep, Oct, Nov, Dec);

Имена в различных перечислениях не обязаны различаться, поскольку всегда квалифицируются при использовании. Так для рассмотренного примера NumberKind.Oct всегда отличается от Month.Oct.

Значения выражений могут конвертироваться к некоторому другому типу (см. 1.3.3.9).

Предопределенная функция pred возвращает значение предшественника значения перечисления, указанного в качестве ее параметра, для всех значений, за исключением первого значения перечисления. Предопределенная функция succ возвращает значение преемника значения перечисления, указанного в качестве ее параметра, для всех значений, отличных от последнего значения перечисления.
 

1.3.3.3. Типы массивов


Массив является структурой, состоящей из некоторого числа элементов, которые все имеют один и тот же тип, называемый типом элементов. Массивы могут индексироваться либо положительным целым числом, либо значением перечисляемого типа. В первом случае количество элементов в объявлении массива определяет его длину. Элементы массива обозначаются индексами, которые представляют собой целые числа между нулем и длиной массива минус единица. Во втором случае имя перечисляемого типа используется в объявлении массива, а элементы массива обозначаются значениями перечисляемого типа.

Синтаксические правила для типа массивов имеют вид:

ArrayType = array Length {"," Length} of Type.
Length = Expression | "*".

Массивы могут быть многомерными; это означает, что элементы массива сами могут быть массивами, и в принципе допустимо соединение форм спецификации различных длин. Но эта возможность вполне может быть ограничена реализацией (см. [Compiler]). Примером и контр примером являются:

type Acceptable = array * of array 42 of T; (* array *, 42 of T *)
        Jagged = array 42 of array * of T; (* 'зубчатый' массив *)

Описание array m of array n of T is текстуально эквивалентно array m, n of T.

Например, array * of array 42 of T может быть записано array *, 42 of T
 

Выражение len(a, n) возвращает количество элементов по измерению n массива a. Выражение len(a) является сокращением для len(a, 0).

В массиве количество элементов по любому измерению может быть переменным и тогда оно обозначается звездочкой. Ответственность за отведения области памяти в куче с использованием зарезервированного слова new для каждого экземпляра массива ложится на программиста:

arrayVariable := new ArrayType(length0, length1, … );

Значение длины должно выражаться положительным выражением целого типа, и количество таких выражений должно соответствовать числу измерений данной переменной.

Примеры использования массивов:

type Vector = array * of integer;
procedure CreateAndReadVector(var a: Vector);
    var i, n: integer;
begin
    read(n);
    a := new Vector(n);
    for i := 0 to len(a) – 1 do
        read(a[i])
    end
end CreateAndReadVector;
procedure InitializeMatrix(var mat: array *, * of real);
    var i, j: integer;
begin
    for i := 0 to len(mat, 0) - 1 do
        for j := 0 to len(mat, 1) – 1 do
            mat[i, j] := 0.0
        end
    end
end InitializeMatrix;

var m: array 10, 10 of real;

InitializeMatrix(m);
 

1.3.3.4. Строковый тип


Переменная типа string представляет неизменные последовательности литер. Строки можно сравнивать на равенство и неравенство с использованием операций ‘=’ и ‘#’. Знак операции ‘+’ представляет конкатенацию, а ‘:=’   присваивание. Предопределенная процедура copy конвертирует значения строкового типа в значения литерного массива и обратно.
 
 

1.3.3.5 Объектные типы


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

Object = object [ ObjModifier ] ObjectName [ FormalParameters ] [ ImplementationClause ] ";"
    [ ImportDeclaration ]
    Declarations
    { ActivityDeclaration }
    ( BlockStatement | end ) SimpleName.
ObjModifier = "{" ident "}". // value или ref
    // private или public
ActivityDeclaration = activity ActivityName [ ImplementationClause ] ";"
    Declarations ( BlockStatement | end SimpleName ).
ImplementationClause = implements DefinitionName { "," DefinitionName }.
ImportDeclaration = import Import { "," Import } ";".
Import = ImportedName [ as Ident ].
ImportedName = ( ModuleName | ImplementationName | NamespaceName |
DefinitionName, ObjectName).

Объект образован объявлениями, включающими константы, типы, переменные (на которые ссылаются как на поля), и процедуры (на которые ссылаются как на методы). Модификаторы public и private можно использовать для объявления видимости содержимого объекта. Если модификатор не представлен, то умолчанию считается private.

Отдельные данные можно сделать общими явным использованием модификатора {public}, размещенным после их объявления. Сам объект тоже может иметь модификатор, который обозначает его либо как объект-значение, либо ссылочный объект, используя значения модификаторов value и ref соответственно. Если модификатор отсутствует, по умолчанию выбирается value.

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

object {ref} Box(w, h: integer);
    var width, height: integer;
    procedure Area(): integer;
    begin
        return width * height
    end Area;
begin
    self.width := w; self.height := h (* self является здесь необязательным в обоих случаях*)
end Box.

var box: Box;

box := new Box(3, 7); (*создает новый объект Box с шириной 3 и высотой 7 *)

См. 1.9.2 об объектах как программных единицах.
 

1.3.3.6. Типы записей


Запись является типом объектов значений. Она может использоваться для инкапсуляции описаний констант, типов и переменных, но не методов и активностей. Ключевое слово record эквивалентно object {value}. Переменные, которые объявлены как объекты-значения, статически размещаются во время компиляции

Примеры:

record Position; (*описание Position типа 'record'*)
    var x, y: integer
end Position;

что эквивалентно

object {value} Position; (*описание Position типа 'record'*)
    var x, y: integer
end Position;

record Date; (*описание Date типа 'record' *)
    var year: integer{8};
        month: Month;
        day: integer{8}
end Date;

1.3.3.7. Типы постулированных интерфейсов


Интерфейс является постулированной реализацией для объекта, образованного из одного или более определений. См. 1.3.3.8 и 1.9.2 для дальнейших деталей.

InterfaceType = object [ PostulatedInterface ].
PostulatedInterface = "{" DefinitionName { "," DefinitionName } "}".

1.3.3.8. Процедурные типы


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

ProcedureType = procedure [ ProcedureTypeFormals ].
ProcedureTypeFormals = "(" [ PTFSection { ";" PTFSection } ] ")" [ ":" FormalType ].
PTFSection = [ var ] FormalType { "," FormalType }.
FormalType = { array "*" of } ( TypeName | InterfaceType ).
InterfaceType = object [ PostulatedInterface ].
PostulatedInterface = "{" DefinitionName { "," DefinitionName } "}".
 

1.3.3.9. Преобразование типов


В языке Zonnon преобразование (conversion) типа внутри одного ‘семейства’ (такого как integer) является неявным тогда, когда оно гарантированно является безопасным. Однако любое преобразование типов между семействами должно быть явным (поскольку оно вызывает преобразование внутреннего представления). Обратные преобразования (например, integer{32} в integer{16}) внутри семейства также всегда должны быть явными. Механизм исключительных ситуаций обнаруживает конвертационные аномалии (см. 1.6.10.1). Взаимосвязь между типами базируется на модели Общей Системы Типов ECMA , как она используется в .NET и суммирована в следующей таблице:
 


 

Заметим, что отношение неявного преобразования типов является транзитивным и обратное отношение (противоположное направлению стрелки) требует явного преобразования и может привести к усечению или исключительной ситуации.

1.3.3.9.1. Имя типа, используемое в качестве функции преобразования


Чтобы осуществить преобразование типа, имя целевого типа может рассматриваться как встроенная функция, которая берет значение выражения исходного типа в качестве параметра и возвращает конвертированное значение. Факультативный второй параметр функции этой функции указывает размер результата.

Синтаксис:

TypeConversion = TypeIdentifier "(" expression [ "," Width ] ")".

Примеры:

integer(x + e/f, 16)

является значением выражения x + e/f , представленным в виде 16-битового целого (может возникнуть исключительная ситуация, если преобразование типа не возможно).

integer(x + e/f)

является значением выражения x + e/f , представленным в виде 32-битового целого (предполагая, что 32 является размером по умолчанию для целого типа). Заметим, что целые не могут неявно быть приведены к вещественным и поэтому:

var count, sum: integer; mean: real;

mean := sum / count

синтаксически не допустимо и требует явного преобразования типа:

mean := real(sum) / real(count)

1.3.3.9.2. Неявный тип константы


Тип простой целочисленной константы определяется путем описания переменной, которой она присваивается. Так, например, при наличии описания:

var i: integer {16};

оператор присваивания

i := 1;

фактически рассматривается компилятором как присваивание

i := 1{16};

Если размер не специфицирован, то выбирается тот размер, который определен для данного типа по умолчанию.

Другое преобразование типа достигается посредством предопределенных процедур (см. раздел 1.7).
 

1.3.4. Описание переменных


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

VariableDeclaration = IdentList ":" Type.

Примеры:

var i, j, k: integer;

x, y: real;
p, q: boolean;
s: set {32};
a: array 100 of real;
name: array 32 of char;
size, count: integer;
mousePosition: Position;
dateOfBirth, today: Date;
Next:1.4 Выражения
Up:1 Язык программирования Zonnon
Previous:1.2 Языковые символы и идентификаторы

© В.Н. Касьянов, Е.В.Касьянова,2004