nextupprevious

Next:1.5 Операторы
Up:1 Язык программирования Zonnon
Previous:1.3 Описания


1.4 Выражения

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

1.4.1. Операнды


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

Designator = Instance

| Designator "{" Type “}”// Приведение
| Designator "^" // Разыменование
| Designator "[" Expression { "," Expression } "]"// Элемент массива
| Designator "(" [ ActualParameters ] ")" // Вызов функции
| Designator "." MemberName // Селектор члена
Instance = (self| InstanceName | DefinitionName "(" InstanceName ")" ).

ActualParameters = Actual { "," Actual }.

Actual = Expression [ "{" [var] FormalType "}" ]. // Аргумент с сигнатурой типа

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

Примеры:

Обозначение                  Тип                          Значение
size                                  integer                      Значение переменной, называемой size
a[i]                                   real                           Элемент массива a в позиции i
dateOfBirth.day               integer{8}                 Поле day объекта, называемого dateOfBirth
w[3].name[i]                   char                           Элемент в позиции i в поле name у элемента массива w в позиции 3

Если a обозначает массив, то a[e] обозначает тот элемент a, чей индекс является текущим значением выражения e. Выражение e должно быть либо типом перечисления, либо кардинального или целого типа. Обозначение вида a[e0, e1, …., en] означает a[e0][e1]….[en].

Если obj обозначает объект, то obj.f обозначает поле f у obj или метод f у объекта obj (см. 1.9.1).

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

1.4.2. Предопределенные знаки операций


Предопределенные знаки операций зафиксированы и встроены в язык.
 

1.4.2.1. Логические операции


Эти знаки операций применимы к операндам boolean и производят результат boolean.

or логическая дизъюнкция p or q  “если p то true, иначе q”
& логическая конъюнкция p & q  “если p то q, иначе false
~ отрицание   ~ p  “не p”
 

1.4.2.2 Арифметические операции


Знаки операций +, -, и * применимы в выражениях к операндам числовых типов (см. 1.4.3.1). Знак операции деления применим к операндам типа real и производит результат типа real. При использовании знаков унарных операций, - обозначает изменение знака и + обозначает тождественную операцию.
+ сложение
- вычитание
* умножение
/ вещественное деление (вещественных)

Примеры:

i :=j + k;
x := real(i) / float(j); (* см. раздел 1.3.3.9*)

Знаки операций div и mod применимы только к целым операндам.

div целочисленное деление
mod модуль

Они удовлетворяют следующим формулам, определенным для любого x и положительного делителя y:
x = (x div y) * y + (x mod y)
0 <= (x mod y) < y

Если значение делителя отрицательно, то смысл знаков операций div и mod определяется реализацией. Рекомендуется программисту проверять это условия и использовать математические рассуждения для обеспечения гарантии того, что используются в качестве делителей только положительные значения.

Примеры:

 x  y   x div y  x mod y
 5  3      1           2
-5  3      2           1
 

1.4.2.3. Знаки операций для множеств


Знаки операций для множеств применимы к операндам типа set и вырабатывают результат типа set. Объявленные размеры в битах для операндов типа set должны совпадать. Знак унарного минуса обозначает дополнение x, т.е. –x обозначает множество целых чисел между 0 и max(set), которые не являются элементами x.

+     объединение                                         покомпонентное или
-      разность                                                покомпонентное вычитание
       (x - y = x * (-y))
*     пересечение                                           покомпонентное и
/      симметричная разность множеств      покомпонентное исключенное или
       (x / y = (x-y) + (y-x))

Конструктор множества определяет значение множества перечислением в скобках его элементов, если они есть. Элементы должны быть числами из диапазона 0 .. max(set). Диапазон m .. n обозначает все целые числа из интервала, начинающегося элементом m и завершающегося элементом n, включая m и n. Если m > n, то m .. n обозначает пустое множество.

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

const left = 0; right = 1; top = 2; bottom = 3;
var edges: set; x, y: integer;
begin
    edges := { }; (* пустое множество *)
    if x < xMin then edges := edges + {left}

    if left in edges then … (* отрезать слева *)

const opCodemask = {0..3};
var opCode, word: set;

    opCode := word * opCodeMask; (* извлечь op-code *)
 

1.4.2.4. Отношения


Отношения вырабатывают результат boolean. Отношения =, #, <, <=, >, и >= применимы числовым типам и char. Отношения = и # также применимы к boolean и set, также как и к процедурным типам (включая значение nil). x in s означает “x является элементом s”. x должно быть целого типа, а s  типа set.

=                        равно
#                        неравно
<                        меньше
<=                      меньше или равно
>                        больше
>=                      больше или равно
in                        быть элементом множества
implements        x implements D равно true, если объект x реализует определение D
is                        x is T является true, если присущий тип x является T

Примеры выражений

выражение                                 тип                  пояснения
1991                                            integer              Простое константное значение
i div 3                                          integer              Целочисленное деление i на 3
~wellFormed or outOfRange       boolean            (не well-formed) или out-of-range
(i+j) * (i-j)                                   integer              Арифметическое выражение
s - {8, 9, 13}                                set{8}              s , из которого удалены 8, 9, 13
keys in {left, right}                       boolean           keys в left или в right или в том и другом
('0'<=ch) & (ch<='9')                    boolean           ch является цифрой
 
 

1.4.3. Определенные пользователем знаки операций и объявления знаков операций


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

1.4.3.1. Базисные знаки операций, для которых допустима перегрузка


Множество предопределенных операций, для которых допустимы перегрузки, является следующим:

- (унарный минус) + (унарный плюс) ~
^ (унарное разыменование)
+ - * / div mod & or
= # < <= > >= in
:= (присваивание является специальным случаем, см. 1.4.3.4)

Заметим, что для знаков операций implements и is не допустима перегрузка (См. 1.9.1).
 

1.4.3.2. Объявления новых знаков операций


Перегруженные операции вводятся как объявления знаков операций. Синтаксис объявления имеет следующий вид:

OperatorDeclaration = operator [ OpModifiers ] OpSymbol [ FormalParameters ] ";" OperatorBody ";".
OperatorBody = Declarations BlockStatement OpSymbol.
OpModifiers = "{" ident { "," ident } [ "," Priority ] "}".
Priority = ConstExpression.
OpSymbol = String. // 1-, 2- или 3-литерная строка; множество возможных символов ограничено

Пример:

operator '+' (x1, x2: Complex): Complex;
    var res: Complex;
begin
    res.re := x1.re + x2.re;
    res.im := x1.im + x2.im;
    return res
end '+';

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

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

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

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

Допускается определять знаки операций в некотором модуле для расширения абстрактного типа данных. Эти знаки операций должны быть определены в терминах операций, уже определенных в модуле, где объявлен абстрактный тип данных.

Обычно, все импортируемые вхождения должны квалифицироваться именами импортируемых единиц. Это также возможно, но не требуется для знаков операций. Например, имеется два законных способа использования “новых сложений” для операндов некоторого типа T.

module M;
    type T {public}= …;
    operator {public}"+" ( a, b : T ) : T; begin …end "+";
end M.

object Obj;
    import M;
    var x, y : T;
begin
    x := x + y; (* подобно обычному выражению *)
    x := x M."+" y; (* полностью квалифицрованный *)
end Obj.

Процедура знака операции не может быть вызвана как обычная функция:

x := M."+"(x, y); (* не законно; должна использоваться нотация выражения *)
 

1.4.3.3. Правила, управляющие перегрузкой


Следующее множество правил применяется для перегруженных знаков операций:

1) По крайней мере, тип у одного операнда перегруженного знака операции должен быть определенным пользователем типом (тип массивов, тип объектов, процедурный тип, тип перечисления). Законно вводить определенные пользователем версии “базисных” типов, такие как integer, real, и boolean.

2) Не разрешена спецификация типа объекта с постулированным интерфейсом (таким как object {D}) в качестве параметра знака операции. Причина – должна быть полная возможность разрешения перегрузки во время компиляции (т.е. статически).

3) Нет ограничений на тип результата перегруженной операции.

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

5) Конструкция разыменования со знаком ^ (см. обозначение правила Designator в синтаксисе) рассматривается здесь как постфиксный знак унарной операции. Следовательно, любая перегрузка знака операции ^ сохраняет форму унарного постфиксного знака; аналогично, унарные + и – знаки операций всегда являются унарными префиксными знаками операций.

6) Допускается перегрузка оператора присваивания. В этом случае, присваивание рассматривается как специальная операция со знаком ‘:=’, реализующая определенный побочный эффект и не производящая значения.

7) В перегруженном знаке операции для оператора присваивания должно быть два параметра и первый параметр должен подставляться по ссылке.

8) Законно специфицировать более одной версии перегруженной операции с одним и тем же знаком; в этом случае типы параметров соответствующих определений операции должны отличаться от любого другого определения операции с тем же знаком (см. раздел 1.4.3.1).
 

1.4.3.4. Старшинство операций


При использовании в выражениях знаков операций синтаксически выделяются четыре их класса, различающихся по старшинству (силе связывания). Операции одного и того же старшинства соединяются слева направо. Например, x-y-z означает (x-y)-z. Старшинство операций от наибольшего старшинства к наименьшему имеет следующий вид:

1. унарная операция отрицания ~
2. операции типа умножения
3. операции типа сложения
4. отношения

Знаки операций используются в выражениях:

Expression = SimpleExpression

[ ( "=" | "#" | "<" | "<=" | ">" | ">=" | in ) SimpleExpression ]
| Designator implements DefinitionName.
SimpleExpression = [ "+"|"-" ] Term { ( "+" | "-" | or ) Term }.

Term = Factor { ( "*" | "/" | div | mod | "&" ) Factor }.

Factor = number

| CharConstant
| string
| nil
| Set
| Designator
| new TypeName [ "(" ActualParameters ")" ]
| new ActivityInstanceName
| "(" Expression ")"
| "~" Factor.
Set = "{" [ SetElement { "," SetElement } ] "}".

SetElement = Expression [ ".." Expression ].

Допустимые знаки операций перечислены ниже. Некоторые из них применимы к операндам различных типов, обозначая различные операции. В этих случаях реальная операция идентифицируется типом операндов. Операнды должны быть выражениями, совместимыми по отношению к данному знаку операции (см. 1.11.6).
 

1.4.3.5. Численные разрешения внутри выражений


Выражение состоит из серии выполнений операций над своими операндами. Для каждой операции отношение между разрешением каждого из его операндов и результатом определяется следующим образом:

Операция     Первый операнд           Второй операнд           Результат
+                   integer{s}                       integer{t}                       integer{max.(s, t)}
-                    integer{s}                       integer{t}                       integer{max.(s, t)}
*                    integer{s}                       integer{t}                       integer{s + t}
div                 integer{s}                       integer{t}                       integer{s}
mod               integer{s}                       integer{t}                       integer{t}
+                    cardinal{s}                     cardinal{t}                     cardinal{max.(s, t)}
-                     cardinal{s}                     cardinal{t}                     cardinal{max.(s, t)}
*                     cardinal{s}                     cardinal{t}                     cardinal{s + t}
div                 cardinal{s}                      cardinal{t}                     cardinal{s}
mod               cardinal{s}                      cardinal{t}                     cardinal{t}
+                    real{s}                             real{t}                            real{max.(s, t)}
-                     real{s}                             real{t}                            real{max.(s, t)}
*                     real{s}                             real{t}                            real{s + t}
/                     real{s}                              real{t}                            real{ s + t}
+                    fixed                                  fixed                               fixed
-                     fixed                                  fixed                               fixed
*                     fixed                                  fixed                               fixed
/                     fixed                                   fixed                               fixed

где max(s, t) = s, if s > t else t
 

Next:1.5 Операторы
Up:1 Язык программирования Zonnon
Previous:1.3 Описания


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