Содержание
7. Операции
В Pascal Script определены следующие операции:
- унарные
not, @
; - мультипликативные
*, /, div, mod, and, shl, shr
; - аддитивные
+, -, or, xor
; - отношения
=, <>, <, >, ⇐, >=, in
.
Приоритет операций убывает в указанном порядке, т. е. наивысшим приоритетом обладают унарные операции, низшим – операции отношения. Порядок выполнения нескольких операций равного приоритета устанавливается компилятором из условия оптимизации кода программы и не обязательно слева направо. При исчислении логических выражений операции равного приоритета всегда вычисляются слева направо, причем будут вычисляться только достаточные для однозначного определения результата операции. Унарная операция @
используется при назначении обработчиков событий, она возвращает адрес точки входа в процедуру. Пример:
procedure AfterScrollHandler(Sender: TObject); begin end; procedure Form_Create; begin Self.OnAfterScroll := @AfterScrollHandler; end;
Логические операции
В языке определены следующие логические операции:
- not – логическое НЕ;
- and – логическое И;
- or – логическое ИЛИ;
- xor – исключительное ИЛИ.
Логические операции применимы к операндам целого и логического типов. Если операнды - целые числа, то результат логической операции есть тоже целое число, биты которого (двоичные разряды) формируются из битов операндов по правилам, указанным в таблице:
Операнд 1 | Операнд 2 | not | and | or | xor |
1 | - | 0 | - | - | - |
0 | - | 1 | - | - | - |
0 | 0 | - | 0 | 0 | 0 |
0 | 1 | - | 0 | 1 | 1 |
1 | 0 | - | 0 | 1 | 1 |
1 | 1 | - | 1 | 1 | 0 |
К логическим операциям в Паскале обычно относятся и две сдвиговые операции над целыми числами:
i shl j
- сдвиг содержимого i на j разрядов влево; освободившиеся младшие разряды заполняются нулями; i shr j
- сдвиг содержимого i на j разрядов вправо; освободившиеся старшие разряды заполняются нулями.
В этих операциях i и j – выражения любого целого типа.
Логические операции над логическими данными дают результат логического типа по правилам, указанным в таблице:
Операнд 1 | Операнд 2 | not | and | or | xor |
True | - | False | - | - | - |
False | - | True | - | - | - |
False | False | - | False | False | False |
False | True | - | False | True | True |
True | False | - | False | True | True |
Операции отношения
Операция отношения in применяется к двум операндам. Первым (левым) операндом должно быть выражение любого порядкового типа, вторым - множество, состоящее из элементов того же типа, или идентификатор множественного типа. Результат операции будет True, если левый операнд принадлежит множеству. Пример:
if Self.State in [dsInsert, dsEdit] then …
Определение типа результата операции
Если в операции участвуют операнды разных типов, то необходимо определить тип достаточный для вмещения результата. К сожалению, Pascal Script не всегда корректно определяет тип результата. Тип результата будет равен типу левого операнда. Пример:
var b: Byte; i: Integer; begin b := 201; i := 2; Debug(i * b); // 402 Debug(b * i); // 146 = 402 - 256, т. к. тип Byte в пределах 0..255 end;
Если в операции участвует целый тип и вещественный, то результат будет вещественного типа независимо от порядка операндов. В следующей таблице приводится несколько примеров того, как Pascal Script определяет тип результата:
Тип левого операнда | Тип правого операнда | Тип результата |
Byte | Integer | Byte |
Word | Cardinal | Word |
Integer | Byte | Integer |
Integer | Single | Single |
Double | Byte | Double |
Byte | Double | Double |
Single | Double | Single |
Double | Single | Double |
Чтобы избежать ошибок в вычислениях, делайте явное приведение к нужному типу. Приведение к типу похоже на вызов функции, имя функции совпадает с типом:
Debug(Integer(b) * i); // 402
Если в выражении используются числовые константы, то их тип зависит от значения: для целых констант минимальный тип Integer, для вещественных констант тип всегда Extended.
Значение константы | Тип константы |
5 | Integer |
> 2147483647 | Cardinal |
> 4294967295 | Int64 |
0.1 | Extended |
1000234234.023 | Extended |
К сожалению, движок не всегда корректно определяет тип отрицательных констант. Например,
-2147483648 будет считаться типом Cardinal, хотя этот тип в принципе не может иметь отрицательные значения, поэтому результат вычислений будет неправильным.
var i64: Int64; begin Debug(Int64(-2147483648)); // !!! 2147483648 – с константами там не проходит i64 := -2147483648; Debug(i64); // !!! 2147483648 – и даже так Debug(-2147483648.0); // -2147483648 – так правильно end;
Операции деления
Операции деления /
и div
тоже имеют свои особенности. Дело в том, что в Pascal Script эти операции являются идентичными и тип результата определяется по алгоритму указанному в начале параграфа.
Debug(5 / 3); // 1 Debug(5 div 3); // 1 Debug(5.0 / 3); // 1,666… Debug(5.0 div 3); // 1,666…