Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Теория вычислительных процессов и структур. Учебное пособие
.pdf
позиции, она сигнализирует о том, что счетчик команд установлен на
готовность выполнения следующей инструкции.
На рис. 5.20 представлена сеть Петри для процесса вычисления
квадратного уравнения. При построении использованы условные обозначения табл. 5.1.
Рис. 5.20. Сеть Петри, моделирующая процесс решения
квадратного уравнения
Каждая позиция имеет единственный выходной переход, кроме
позиции, предшествующей принятию решения, у которой имеется два
выходных перехода, соответствующих истинному и ложному значению проверяемого условия.
Переходы, моделирующие вычисления, имеют один вход и
один выход и не могут находиться в конфликте. Действие же, связанное с принятием решения, напротив, создает в сети конфликт. Выбор
способа разрешения конфликта, как мы уже говорили ранее, не регламентируется формализмом сети: он либо недетерминирован, либо
управляется извне.
Рассмотрим еще один пример построения сети Петри.
Пусть дана программа, которая выводит на экран квадраты натуральных чисел от 1 до некоторого заданного n. Пользователь вводит
61

значение переменной n, а переменной i, являющейся счетчиком итераций цикла, присваивается значение 1. Далее запускается цикл.
Его тело состоит из вычисления значения переменной x, которой присваивается значение i2 для каждой итерации, вывода x на экран и увеличения i на 1. Тело цикла выполняется, пока значение i не превышает n.
Текст описанной программы представлен ниже:
begin
readln(n);
i:=1;
while (i<=n) do
begin
x:=i*i;
writeln(x);
i:=i+1;
end;
end.
Соответствующая сеть Петри представлена на рис. 5.21. В данной модели использован несколько иной подход по сравнению с сетью
на рис. 5.20. Поясним использованную здесь интерпретацию позиций
и переходов.
Рис. 5.21. Сеть Петри, моделирующая работу алгоритма программы
вывода на экран квадратов натуральных чисел
62

Позиции p1 и p2 указывают на необходимость ввода исходных
данных, а именно – ввод значения переменной n и присваивание начального значения i соответственно. Срабатывание перехода t1 означает, что все исходные данные поступили, и можно запускать процесс
вычислений.
Позиция p3 моделирует конфликт при проверке логического
условия выполнения тела цикла. Если условие выполнено, срабатывает переход t2, который моделирует выполнение тела цикла. После этого фишка вновь возвращается в позицию p3, и проверка производится
уже на следующей итерации. Если i приняло значение, большее n, выполнение цикла (а вместе с ним – и программы) завершается, что соответствует срабатыванию перехода t3 и переводу единственной фишки сети в позицию p4, которая уже не дает возможности для срабатывания каких-либо переходов.
Отметим, что событие, моделируемое переходом t2, можно
считать непримитивным и заменить его изображение прямоугольником, иллюстрирующим наличие подсети. Данную подсеть, в свою очередь, можно привести в виде отдельной сети Петри, чтобы раскрыть
сложный характер события.
63

6. СХЕМЫ ПРОГРАММ
Программа P
1
Программа P2
Схема программ
P1 и P
2
begin
integer х, у, n;
input(х, n);
у:=1;
L: y:=y*x;
if y < n then goto
L;
print(y);
end.
begin
string х, у;
integer n;
input(х, n);
у:=ε;
L: y:=strncat(x, y);
if len(y) < n then goto L;
print(y);
end.
begin
input(х, n);
у:=а;
L: y:=f (x, y);
if p(y, n) then goto L;
print(y);
end.
6.1. Базис класса стандартных схем программ
В предыдущем разделе в рамках изучения сетей Петри мы в
качестве частного случая рассмотрели возможность моделирования
процесса выполнения программы. В данном разделе мы целиком сосредоточимся на вопросах моделирования программ и рассмотрим
специализированный инструмент для решения этой задачи – схемы
программ.
Схема программы – это математическая модель, описывающая
строение определенного класса программ. В данной модели конкретные операции и функции заменены абстрактными символами из соответствующих множеств.
Для того чтобы понять отличие программы от схемы программы, рассмотрим пример в табл. 6.1.
Таблица 6.1
Сравнение двух программ и соответствующей им схемы
(во всех случаях вместо конкретного языка программирования
использован псевдокод)
Рассмотрим программу P1. Вначале выделяется память под три
целочисленные переменные. Далее пользователю предлагается ввести
значения для x и n, а y присваивается значение 1. После этого в строке с меткой L значения y и x перемножаются, а результат присваивается y. Если полученное значение меньше n, то происходит возвращение к метке L, и указанные операции повторяются. Если y n, то на
экран выводится его значение, и работа программы завершается. Та-
64

ким образом, программа P1 вычисляет степень переменной x до тех
пор, пока она не превысит значение n.
В программе P2 вначале также выделяется память под переменные: две строковых и одну целочисленную. Далее пользователь
вводит значения переменных x и n, а переменной y присваивается
пустая строка . Далее в строке с меткой L переменной y присваивается результат конкатенации x и y (конкатенация совершается посредством функции strncat). Если длина полученной в y строки не превышает n, производится повторение операций, происходящих после
метки L. Как только длина строки y становится большей или равной n, строка y выводится на экран, и программа завершает свою
работу.
Нетрудно видеть, что, несмотря на то, что программы P1 и P2
выполняют абсолютно разные задачи и даже обрабатывают разные
типы данных (программа P1 работает только с целочисленными переменными, а в программе P2 ключевую роль играют строковые), они
имеют довольно ощутимое сходство. Сходство это заключается в их
структуре. В обеих программах происходит следующее:
1) пользователю предлагается ввести значения двух перемен-
ных;
2) третьей переменной присваивается некоторая константа;
3) запускается цикл, условие выполнения которого зависит
от логического выражения с двумя аргументами y и n, а тело состоит из присваивания переменной y значения некоторой функции
от x и y;
4) когда условие выполнения цикла становится ложным, происходит вывод на экран значения переменной y, и программа завершает свою работу.
Описанная выше структура представлена в табл. 6.1 в третьем
столбце. В ней отсутствуют операторы выделения памяти под переменные, т.к. с точки зрения описания структуры и логики представленных программ они не слишком существенны, и в схеме можно ограничиться начальным оператором.
Схемы программ, вообще говоря, строятся с применением оп-
ределенных символов, роль которых определяется принадлежностью к
соответствующим множествам.
Полный базис В класса стандартных схем состоит из четырех
множеств символов, которые являются непересекающимися и счетными. Из символов этих множеств строятся слова – операторы.
65

Множества символов полного базиса:
1. X = {х, x1, х2,..., у, y1, у2,.., z, z1, z2,..} – множество символов,
называемых переменными.
2. F = {f
(0)
, f
(1)
, f
(2)
... g
(0)
, g
(1)
, g
(2)
,.., h
(0)
, h
(1)
(2)
, h
,..} – множество
функциональных символов. В верхнем индексе записывается местность символа. Ближайший пример функционального символа –
обычная функция в программе. Местность представляет собой фактически количество аргументов, которое может принимать такая функция. Символы с нулевой местностью – это, очевидно, константы. Их
традиционно обозначают начальными буквами латинского алфавита,
например: a, b, c.
Индексы местности можно опускать, если это не приводит к
двусмысленности или противоречиям.
3. Р = {р
(0)
, р
(1)
, р
(2)
,…, q
(0)
, q
(1)
(2)
, q
,...} – множество предикат-
ных символов. Предикат – это утверждение, истинность которого зави-
сит от аргументов, входящих в него. Ближайший пример предикатного
символа – это логическая функция в программе: в зависимости от значений своих аргументов она возвращает значение либо «истина», либо
«ложь». Предикатные символы так же, как и функциональные, обладают местностью. Нульместные предикатные символы представляют
собой логические константы.
4. {start, stop, :=, (, ),…} – множество специальных символов. Пример специального символа – оператор языка программирования.
Здесь следует сделать оговорку относительно терминологии. Под словом «символ» мы традиционно подразумеваем некоторый единичный элементарный объект типа буквы, цифры, знака
разделителя и т.п. Конструкции вида star или f (x, y) интуитивно
не кажутся такими простыми элементами, что может вызывать
недопонимание при изучении рассматриваемого материала. Следует
просто привыкнуть к такому более широкому подходу к понятию символа, а также понятию слова, которое из таких символов строится.
Введем еще два понятия, представляющих собой в некотором
смысле обобщение для объектов, приведенных в определении множеств базиса B.
Функциональное выражение, или терм, – это слово, построенное из переменных, функциональных и специальных симво-
66

лов. Термами являются односимвольные слова, состоящие из пере-
(2)
(n)
(1, 2,…, n), где 1,
(3)
(x, h
(y1, y2, y3)).
,…,
2
менных или констант, а также слова вида f
n – термы.
Примеры термов: a, x, f
(1)
(x), g
Логическое выражение, или тест, – это слово вида
(n)
p
(1, 2,…, n), где p
(n)
– предикатный символ, а 1, 2,…, n – термы.
Логические константы также являются тестами.
Рассмотрим множество операторов. Оно включает в себя пять
типов:
1. Начальный оператор – слово вида start(x1, х2,..., хk), где k > 0,
а x1, х2,..., хk – переменные, называемые результатами этого оператора.
2. Заключительный оператор – слово вида stop(1, 2,…, n),
где n > 0, а 1, 2,…, n – термы. Переменные, входящие в термы
1, 2,…, n, называются аргументами этого оператора.
3. Оператор присваивания – слово вида х:=, где х – перемен-
ная (результат оператора), а – терм. Переменные, входящие в
терм , называются аргументами этого оператора. Если – переменная (х:=у), оператор присваивания называется пересылкой, а если
– константа (x:=a), то – засылкой.
4. Условный оператор – логическое выражение. Входящие в
него переменные называются его аргументами.
5. Оператор петли – односимвольное слово loop.
Отметим, что, кроме полного базиса стандартных схем, возможны случаи как ограниченных базисов на его основе, когда из всего
представленного многообразия берутся лишь отдельные элементы, так
и случаи обогащенных схем, для которых базис расширяется новыми
элементами, структурами данных и т.д. Мы сосредоточимся преимущественно на изучении описанного выше полного базиса стандартных
схем программ.
Пример ограниченного базиса:
- множество переменных: X = {x1, x2, x3};
- множество функциональных символов: F = {a, f
- множество предикатных символов: P = {p
(1)
};
(1)
};
- множество специальных символов: {start, stop, , , (, ), :=}
(элементы выделены жирным шрифтом для лучшей читаемости).
67

Соответственно, множество операторов (слов, которые можно
построить из указанных символов) может быть следующим:
{start(x1, x2, x3), stop(x1, x2, x3), x1:=a, x2:=a, x3:=a, x1:=f (x1),
x2:=f (x2), x3:=f (x3), p(x1), p(x2), p(x3)}.
6.2. Способы представления стандартной схемы программы
Как мы увидели из предыдущего раздела, схема программы
описывает структурные особенности некоторого множества программ,
не указывая семантику элементов этой структуры. Функции, предикаты и переменные представлены абстракциями.
Удобно для изображения схемы программы использовать граф.
Вершинами такого графа будут операторы из базиса B.
Сформулируем следующее определение: стандартная схема в
базисе В есть конечный ориентированный граф без свободных дуг,
обладающий вершинами следующих видов:
1. Начальная вершина. Соответствует начальному оператору и
единственна. Входящих дуг не имеет, выходящая только одна.
2. Заключительная вершина. Соответствует заключительному
оператору. Таких вершин может быть несколько. Не имеет выходящих
дуг.
3. Вершина-преобразователь. Соответствует оператору присваивания. Имеет только одну выходящую дугу.
4. Вершина-распознаватель. Соответствует условному оператору. Имеет две выходящих дуги, одна из которых помечается «0», а
другая – «1» («условие не выполнено» и «условие выполнено» соответственно).
5. Вершина-петля. Соответствует оператору петли. Не имеет
выходящих дуг.
Вершины нумеруются, начальная вершина всегда имеет
метку 0.
Схема называется правильной, если в ней не используются пе-
ременные, значения которых не определены.
Граф схемы программ из табл. 6.1 представлен на рис. 6.1.
Вершины всех операторов изображены в виде прямоугольников,
кроме вершины-распознавателя, которая представлена овалом.
Вершины пронумерованы от 0 до 4, и внутри них записаны сами операторы.
68

Рис. 6.1. Граф схемы программ из табл. 6.1
Другим способом задания стандартной схемы является представление ее в линейной форме. Фактически мы уже кратко познакомились с этим способом в примере из табл. 6.1, но теперь рассмотрим
его более подробно.
Стандартная схема в линейной форме – это последовательность инструкций, которые строятся по следующим правилам:
1. Если начальная вершина содержит оператор start(x1,..., х
), а
n
ее выходная дуга ведет к вершине с меткой L, то соответствующая инструкция
0: start(x1,..., хn) goto L.
2. Если заключительная вершина обладает меткой L и содер-
жит оператор stop(1,..., n), то соответствующая инструкция
L: stop(1,..., n).
3. Если вершина с меткой L является преобразователем с опера-
тором х:=, а ее выходная дуга ведет к вершине с меткой L1, то соответствующая инструкция
L: х:= goto L1.
4. Если вершина с меткой L является распознавателем с усло-
вием p(1,..., n), чья выходящая дуга с пометкой 1 ведет к вершине с
меткой L1, а выходящая дуга с пометкой 0 – к вершине с меткой L0,
то соответствующая инструкция
L: if p(1,..., n) then L1 else L0.
69

5. Если вершина с меткой L представляет собой петлю, то ей
соответствует инструкция
L: loop.
Построим теперь линейную форму для схемы программ P1 и P2
из табл. 6.1 в полном соответствии с представленными правилами:
0: start(x, n) goto 1,
1: у:=a goto 2,
2: y:=f (x, y) goto 3,
3: if p(y, n) then 2 else 4,
4: stop(y).
Видно, что получившаяся запись перегружена лишними метками и ссылками на метки. В большинстве случаев в данном примере
и так понятна последовательность выполнения инструкций. Поэтому
рациональнее применять сокращенную запись линейной формы, где
ненужные метки и ссылки опущены:
start(x, n),
у:=a,
2: y:=f(x, y),
if p(y, n) then 2 else 4,
4: stop(y).
Представленная схема является более компактным и строгим
вариантом схемы, которая дана в табл. 6.1.
6.3. Интерпретированная стандартная схема программы
Как мы увидели, стандартная схема, вообще говоря, не является записью алгоритма. Она моделирует структурные свойства
программ без учета семантики вычислений. Один из способов построения семантической теории схем программ основан на понятии
интерпретации, или интерпретированной схемы.
Пусть задан некоторый базис B класса стандартных схем.
Интерпретацией базиса B в области интерпретации D называется
функция I, которая строится по следующим правилам:
1. Каждой переменной х из базиса B функция I ставит в соот-
ветствие некоторый элемент d = I (х), d D.
70
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
