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…