Next:1.5
Операторы
Up:1
Язык программирования Zonnon
Previous:1.3
Описания
За исключением конструкторов множеств и литеральных констант (числа,
символьные константы или строки), операнды изображаются обозначениями.
Обозначение состоит из идентификатора, ссылающегося на константу, переменную
или процедуру. Возможно, что этот идентификатор квалифицируется идентификатором,
обозначающим модуль, определение, реализацию или объект и может завершаться
селекторами, если обозначаемый объект является элементом структуры.
Designator = Instance
| Designator "{" Type “}”// ПриведениеInstance = (self| InstanceName | DefinitionName "(" InstanceName ")" ).
| Designator "^" // Разыменование
| Designator "[" Expression { "," Expression } "]"// Элемент массива
| Designator "(" [ ActualParameters ] ")" // Вызов функции
| Designator "." MemberName // Селектор члена
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).
Предопределенные знаки операций зафиксированы и встроены в язык.
Эти знаки операций применимы к операндам boolean и производят результат
boolean.
or логическая дизъюнкция p or q “если p то true,
иначе q”
& логическая конъюнкция p & q “если p то q, иначе false”
~ отрицание ~ p “не p”
Знаки операций +, -, и * применимы в выражениях к операндам числовых
типов (см. 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
Знаки операций для множеств применимы к операндам типа 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
*)
Отношения вырабатывают результат 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
является цифрой
Дополнительно к базисным знакам операций есть возможность специфицировать
программистские версии некоторых предопределенных я языке Zonnon знаки
операций, называемые определенными пользователем знаки операций. Это делает
возможным определять новые знаки операций, которые работают с определенными
пользователем типами (например, комплексными числами) при сохранении обычного
синтаксиса выражений и без необходимости прибегать к функционально-ориентированному
стилю программирования.
Множество предопределенных операций, для которых допустимы перегрузки,
является следующим:
- (унарный минус) + (унарный плюс) ~
^ (унарное разыменование)
+ - * / div mod & or
= # < <= > >= in
:= (присваивание является специальным случаем, см. 1.4.3.4)
Заметим, что для знаков операций implements и is не допустима
перегрузка (См. 1.9.1).
Перегруженные операции вводятся как объявления знаков операций.
Синтаксис объявления имеет следующий вид:
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) По крайней мере, тип у одного операнда перегруженного знака операции должен быть определенным пользователем типом (тип массивов, тип объектов, процедурный тип, тип перечисления). Законно вводить определенные пользователем версии “базисных” типов, такие как integer, real, и boolean.
2) Не разрешена спецификация типа объекта с постулированным интерфейсом (таким как object {D}) в качестве параметра знака операции. Причина – должна быть полная возможность разрешения перегрузки во время компиляции (т.е. статически).
3) Нет ограничений на тип результата перегруженной операции.
4) Число аргументов, старшинство перегруженной операции и форма (префиксная или постфиксная) унарной операции должны совпадать с соответствующими чертами для предопределенной операции с тем же знаком.
5) Конструкция разыменования со знаком ^ (см. обозначение правила Designator в синтаксисе) рассматривается здесь как постфиксный знак унарной операции. Следовательно, любая перегрузка знака операции ^ сохраняет форму унарного постфиксного знака; аналогично, унарные + и – знаки операций всегда являются унарными префиксными знаками операций.
6) Допускается перегрузка оператора присваивания. В этом случае, присваивание рассматривается как специальная операция со знаком ‘:=’, реализующая определенный побочный эффект и не производящая значения.
7) В перегруженном знаке операции для оператора присваивания должно быть два параметра и первый параметр должен подставляться по ссылке.
8) Законно специфицировать более одной версии перегруженной операции
с одним и тем же знаком; в этом случае типы параметров соответствующих
определений операции должны отличаться от любого другого определения операции
с тем же знаком (см. раздел 1.4.3.1).
При использовании в выражениях знаков операций синтаксически выделяются
четыре их класса, различающихся по старшинству (силе связывания). Операции
одного и того же старшинства соединяются слева направо. Например, x-y-z
означает (x-y)-z. Старшинство операций от наибольшего старшинства к наименьшему
имеет следующий вид:
1. унарная операция отрицания ~
2. операции типа умножения
3. операции типа сложения
4. отношения
Знаки операций используются в выражениях:
Expression = SimpleExpression
[ ( "=" | "#" | "<" | "<=" | ">" | ">=" | in ) SimpleExpression ]SimpleExpression = [ "+"|"-" ] Term { ( "+" | "-" | or ) Term }.
| Designator implements DefinitionName.
Term = Factor { ( "*" | "/" | div | mod | "&" ) Factor }.
Factor = number
| CharConstantSet = "{" [ SetElement { "," SetElement } ] "}".
| string
| nil
| Set
| Designator
| new TypeName [ "(" ActualParameters ")" ]
| new ActivityInstanceName
| "(" Expression ")"
| "~" Factor.
SetElement = Expression [ ".." Expression ].
Допустимые знаки операций перечислены ниже. Некоторые из них применимы
к операндам различных типов, обозначая различные операции. В этих случаях
реальная операция идентифицируется типом операндов. Операнды должны быть
выражениями, совместимыми по отношению к данному знаку операции (см. 1.11.6).
Выражение состоит из серии выполнений операций над своими операндами.
Для каждой операции отношение между разрешением каждого из его операндов
и результатом определяется следующим образом:
Операция Первый операнд
Второй операнд
Результат
+
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
Описания