Вызов предиката

Элементарным оператором программы является вызов предиката.

ВЫЗОВ-ПРЕДИКАТА ::= ВЫЗОВ-ПРЕДИКАТА-ФУНКЦИИ |

ВЫЗОВ-ПРЕДИКАТА-ГИПЕРФУНКЦИИ

ВЫЗОВ-ПРЕДИКАТА-ФУНКЦИИ ::=

ИДЕНТИФИКАЦИЯ-ПРЕДИКАТА ( [АРГУМЕНТЫ] : РЕЗУЛЬТАТЫ )

ИДЕНТИФИКАЦИЯ-ПРЕДИКАТА ::= [ИМЯ-МОДУЛЯ .] ИМЯ-ПРЕДИКАТА |

ВЫРАЖЕНИЕ |

[ОБЪЕКТ-КЛАССА .] ИМЯ-ПРЕДИКАТА

ОБЪЕКТ-КЛАССА ::= ПЕРЕМЕННАЯ

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

АРГУМЕНТЫ ::= СПИСОК-ВЫРАЖЕНИЙ

СПИСОК-ВЫРАЖЕНИЙ ::= ВЫРАЖЕНИЕ [, СПИСОК-ВЫРАЖЕНИЙ]

Типы аргументов вызова должны быть совместимы (см. разд. 6.7) с типами соответствующих аргументов определения (или спецификации) вызываемого предиката.


РЕЗУЛЬТАТЫ ::= ПЕРЕМЕННАЯ [, РЕЗУЛЬТАТЫ] |

РЕЗУЛЬТАТ-ЛОКАЛ [, РЕЗУЛЬТАТЫ]

РЕЗУЛЬТАТ-ЛОКАЛ ::= ОПИСАНИЕ-ПЕРЕМЕННОЙ

ОПИСАНИЕ-ПЕРЕМЕННОЙ ::= ИЗОБРАЖЕНИЕ-ТИПА-ПЕРЕМЕННОЙ ИДЕНТИФИКАТОР

ИЗОБРАЖЕНИЕ-ТИПА-ПЕРЕМЕННОЙ ::=

ИЗОБРАЖЕНИЕ-ТИПА [:blank:] | var [:blank:]

Использование var возможно вместо соответствующего ИЗОБРАЖЕНИЯ-ТИПА, поскольку тип результата-локала в большинстве случаев можно восстановить по определению вызываемого предиката. Описатель var также может использоваться при описании локальной переменной в случае, когда тип этой переменной легко определяется из контекста дальнейшего использования переменной (см. разд. 6.4, 6.5).

Типы результатов вызова должны совпадать с типами соответствующих результатов в определении вызываемого предиката. Переменная, представленная описанием результата-локала, определяется как локальная в теле предиката, содержащем данный вызов. Описание локальной результирующей переменной внутри вызова эквивалентно описанию этой переменной перед вызовом.

Использование специального имени “_” в качестве результирующей переменной обозначает пустой результат: результат по этой позиции, получаемый при завершении исполнения вызова предиката, не используется в дальнейшем исполнении. Имя “_” зарезервировано в языке P - его нельзя использовать для именования объектов программы.

ВЫЗОВ-ПРЕДИКАТА-ГИПЕРФУНКЦИИ ::=

ИДЕНТИФИКАЦИЯ-ПРЕДИКАТА ( [АРГУМЕНТЫ] (: РЕЗУЛЬТАТЫ-ВЕТВИ)+ )

РЕЗУЛЬТАТЫ-ВЕТВИ ::= [РЕЗУЛЬТАТЫ] [ОПЕРАТОР-ПЕРЕХОДА]

ОПЕРАТОР-ПЕРЕХОДА ::= # МЕТКА

В качестве метки в операторе указывается либо метка ветви предиката, в теле которого находится данный вызов, либо метка ветви обработчика; подробнее см. в разд. 6.5.

Исполнение вызова предиката реализуется следующим образом. Результатом исполнения аргументов вызова является набор значений. Вычисление каждого аргумента вызова реализуется независимо от вычисления других, т. е. параллельно. Полученный набор значений аргументов присваивается соответствующим входным параметрам определения вызываемого предиката. Далее исполняется тело определения вызываемого предиката. В процессе исполнения тела определяется итоговая ветвь предиката и вычисляются значения результирующих переменных по этой ветви. Наконец, полученные значения результирующих переменных присваиваются соответствующим результирующим переменным вызова предиката, и исполнение вызова завершается по этой ветви вызова. Если в данной ветви вызова указан оператор перехода, то либо происходит переход на локальную метку, либо завершается тело предиката, содержащего вызов, той ветвью, которая указана в операторе перехода. Отметим, что подстановка аргументов и результатов предиката реализуется по значению.

ВЫЗОВ-ФУНКЦИИ ::= ИДЕНТИФИКАЦИЯ-ПРЕДИКАТА ( [АРГУМЕНТЫ] )

Вызов предиката-функции может иметь вид вызова функции. Результатом исполнения является набор значений результирующих переменных предиката.

 


real r;

sqrt (2 : r);

real q = sqrt (3);

Comp (list(int) s: : int d, list (int) r) // спецификация гиперфункции Comp

pre 1: s = nil

post 2: s = cons(d, r) ;

/* если список s пуст, реализуется первая ветвь гиперфункции, иначе - реализуется вторая ветвь с результатами: d - первый элемент, r - хвост списка */

elemTwo (list(int) s: int e #value : #empty)

pre empty: s = nil or s.cdr = nil

{ Comp (s : #empty : int e1, list(int) s1 #ok)

case ok: Comp (s1 : #empty : e, list(int) s2 #value);

}

post value: e = (s.cdr).car;

/* гиперфункция elemTwo извлекает второй элемент списка, если элемент существует */

Пример 2.Вызовы и определения предикатов и гиперфункций,

спецификация гиперфункции

 

В определении предиката elemTwo переход по локальной метке ok является излишним. Кроме того, результаты e1 и s2 далее нигде не используются. Определение предиката elemTwo, представленное ниже, исправляет отмеченные недостатки:

elemTwo (list(int) s: int e #value : #empty)

pre 1: s = nil or s.cdr = nil

{ Comp (s : #empty : _, list(int) s1 );

Comp (s1 : #empty : e, _ #value);

}

post value: e = s.cdr.car;