Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Теория вычислительных процессов и структур. Учебное пособие

.pdf
Скачиваний:
0
Добавлен:
07.09.2026
Размер:
1 Мб
Скачать
☆
2. Каждой константе а из базиса B функция I ставит в соот-
' WWx
ветствие некоторый элемент d = I (а), d D.
3. Каждому функциональному символу f
(n)
при n 1 функция I
ставит в соответствие всюду определенную функцию
(n)
F
= I(f
(n)
) : Dn D
(это значит, что n аргументов функции и ее значения принадлежат об­ласти интерпретации D).
4. Каждой логической константе р
(0)
функция I ставит в соот-
ветствие один из символов множества {0, 1}.
5. Каждому предикатному символу p
(n)
при n 1 функция I ста-
вит в соответствие всюду определенный предикат
(n)
P
= I(p
(n)
) : Dn {0, 1}.
Интерпретация называется конечной, если D – конечное мно­жество.
Как можно заметить, определение интерпретации не уточняет природу объектов множества D: она выбирается в зависимости от кон­кретной задачи.
Пусть S – схема в базисе B, а I – интерпретация этого базиса. Тогда пара (S, I) называется интерпретированной стандартной схе- мой, или программой.
Обозначим конечное множество переменных схемы S как Xs. Это множество называется памятью схемы S.
Состоянием памяти программы (S, I) называется функция W : Хs  D, которая каждой переменной х Xs сопоставляет элемент W(х) из области интерпретации D. Элемент W(х) называется значени- ем переменной х в состоянии W.
Если два состояния памяти W и W' совпадают с точностью до значений переменной х (т.е. yx, y Xs : W(y) = W'(y)), то исполь- зуют запись
.
Если X = (х1, x2,…, хп) – некоторый набор переменных, х1,…, хп X
, то W(X) = (W(х1), W(x2),…, W(хп)) – набор значений этих
s
переменных.
71
Начальным состоянием памяти Xs при интерпретации I назы­вается такое состояние W0, для которого xXs W0(х) = I(х).
Определим значение терма при интерпретации I и состоя­нии памяти W (будем обозначать его I (W)) по следующим прави­лам:
1) если = х, где х – переменная, то I (W) = W(х);
2) если = а, где а – константа, то I (W) = I(а);
3) если = f
(n)
(1, 2,…, n), где 1, 2,…, n – термы, то
I (W) = I(f
(n)
)(
(W),
1I
(W),…,
2I
(W)).
nI
Понять конструкцию в правой части этого выражения можно следующим образом. Вместо функционального символа f ляется его интерпретация – некоторая функция F
(n)
из области интер-
(n)
подстав-
претации D, обладающая n аргументами. Аргументами функциональ­ного символа f няется своим значением при интерпретации I и состоянии W, и эти значения используются в качестве аргументов функции F
(n)
были термы 1, 2,…, n. Теперь каждый из них заме-
(n)
.
Значение теста π при интерпретации I и состоянии памяти W обозначается и определяется аналогичным образом:
π
(W) = I(p
I
(n)
)(
(W),
1I
(W),…,
2I
(W)).
nI
6.4. Протокол выполнения программы
Пусть дана программа (S, I). Пара и = (l, W), где l – метка вер­шины схемы S, а W – состояние ее памяти, называется конфигурацией данной программы. Выполнение программы можно описать в виде по­следовательности конфигураций. Эта последовательность называется
протоколом выполнения программы.
Протокол строится следующим образом. Пусть дана последо­вательность конфигураций (u0, u1,… , ui, u
, …) для программы (S, I).
i+1
Будем обозначать i-ю конфигурацию протокола как ui = (ki, Wi), где ki – соответствующая данной конфигурации метка вершины, а Wi – состояние памяти. Тогда начальному состоянию памяти схемы S
при интерпретации I соответствует конфигурация u0 = (0, W0).
Рассмотрим некоторую i-ю конфигурацию протокола. Пусть
O – оператор схемы S, находящийся в вершине с меткой ki.
72
Если O – заключительный оператор stop(1,...,
i
x
i
WW
1
21
21
21
,0
,1
),(
ddесли
ddесли
ddP
), то протокол
n
конечен, и ui – последняя его конфигурация. Программа (S, I) останав- ливается, а последовательность значений
1I (Wi
),
2I (Wi
),…,
nI (Wi
) на-
зывается результатом выполнения программы.
Если O не является заключительным оператором, то в прото­коле существует следующая конфигурация: u
i+1
= (k
i+1
, W
). Здесь
i+1
возможны следующие варианты:
1. O – начальный оператор с выходящей дугой, ведущей к
вершине с меткой l. Тогда k
= l, а W
i+1
= Wi.
i+1
2. O – оператор присваивания x:= с выходящей дугой, веду-
щей к метке l. Тогда k
i+1
= l,
, W
(x) = I (Wi), т.е. в состоянии
i+1
памяти произошло единственное изменение – переменная x получила новое значение.
3. O – условный оператор, для которого выполнено
π
) = Δ (Δ {0, 1}), а соответствующая Δ выходящая дуга ведет к
I (Wi
вершине с меткой l (т.е. при данной конфигурации проверка теста π приводит к переходу к вершине с меткой l). Тогда k
4. O – оператор петли. Тогда k
= ki, W
i+1
= l, а W
i+1
= W
i+1
= Wi.
i+1
, и протокол
i
бесконечен.
Программа останавливается тогда и только тогда, когда прото­кол ее выполнения конечен. Иначе она зацикливается, и результат ее выполнения не определен.
В качестве примера рассмотрим протокол выполнения программ P1 и P2 из табл. 6.1.
Вначале зададим интерпретацию для первой программы. Об­ласть интерпретации для нее обозначим как D1. Она будет включать в себя множество целых неотрицательных чисел. Функцию I определим следующим образом:
I(x) = 2; I(n) = 8; I(y) = 0; I(a) = 1; I(f) = F, где F : D2 D – функция умножения двух чисел: F(d1, d2) = d1 d2, где d1, d2 D; I(p) = P, где P : D2 {0, 1} – предикат вида
, d1, d2 D.
Тогда протокол выполнения программы P1 будет выглядеть так, как это показано в табл. 6.2.
73
Таблица 6.2
Номер конфигурации
0 1 2 3 4 5 6 7 8
Метка
0 1 2 3 2 3 2 3 4
Значение x
2 2 2 2 2 2 2 2 2
Значение n
8 8 8 8 8 8 8 8 8
Значение y
0 1 2 2 4 4 8 8 8
21
21
21
||,0
||,1
),(
ddесли
ddесли
ddP
Номер
конфигу-
рации
0 1 2 3 4 5 6 7 8
Метка
0 1 2 3 2 3 2 3 4
Значение x
abc
abc
abc
abc
abc
abc
abc
abc
abc
Значение n
9 9 9 9 9 9 9 9 9
Значение y
ε ε abc
abc
abcabc
abcabc
abcabcabc
abcabcabc
abcabcabc
Протокол выполнения программы P1
Зададим интерпретацию для программы P2. Область интерпре­тации здесь будет состоять из объединения двух непересекающихся множеств D = Di Ds, где Di – множество целых неотрицательных чисел, а Ds – множество цепочек, состоящих из букв латинского алфа­вита. Построим функцию I:
I(x) = abc; I(n) = 9; I(y) = ; I(f) = F, где F : D
2
Ds – функция конкатенации двух строк:
s
F(d1, d2) = d1 • d2, где d1, d2 Ds; I(p) = P, где P : Ds Di {0, 1} – предикат вида
, d1 Ds, d2 Di.
Протокол выполнения программы P2 представлен в табл. 6.3.
Протокол выполнения программы P2
74
Таблица 6.3
Интерпретации переменных x и n для обеих программ мы вы-
2121
~~ SSSS
E
брали произвольно, смоделировав ситуацию ввода их начальных зна­чений пользователем. Отметим также, что для обеих программ интер­претация переменной y является несущественной: какую бы I(y) мы не выбрали, в любом случае переменной y в обеих программах будет присвоено значение константы a.
Протоколы обеих программ конечны. Результатом программы P1 является число 8, а программы P2 – строка abcabcabc.
6.5. Свойства стандартных схем программ
Стандартная схема S в базисе B называется тотальной, если для любой интерпретации I базиса B программа (S, I) останавли­вается.
Стандартная схема S в базисе B является пустой, если для лю­бой интерпретации I базиса B программа (S, I) зацикливается.
Стандартные схемы S1 и S2 функционально эквивалентны
(S1 ~ S2), если для любой интерпретации I базиса B программы (S1, I) и (S2, I) останавливаются с одинаковым результатом, либо обе зацикли-
ваются. Отметим, что отношение эквивалентности введено для схем в одном базисе. Если схема S1 соответствует некоторому базису B1, а схема S2 – B2, то в качестве единого базиса для определения эквива­лентности этих схем можно взять объединение базисов B1 и B2.
Некоторое отношение эквивалентности E, заданное для пар стандартных схем, называется корректным, если S1, S2
. Другими словами, из отношения E следует функцио-
нальная эквивалентность схем, для которых оно имеет место.
Поиск разрешимых корректных отношений эквивалентности представляет значительный интерес, т.к. функциональная эквивалент­ность алгоритмически неразрешима. Таким образом, возникает проблема сужения понятия эквивалентности. Основным способом, позволяющим достичь этой цели, является сравнение не функций, реализуемых программами, а истории их вычисления в процессе вы­полнения. Детальность истории сама по себе имеет мало значения, главное, чтобы можно было однозначным образом восстановить по этой истории результат выполнения программы. Тогда программы, истории которых совпадают, автоматически будут иметь совпадаю­щие результаты, что и означает функциональную эквивалентность.
75
Рассмотрим кратко виды историй программы.
1. Операционная история. Представляет собой последователь-
ность преобразователей, выполняемых при работе программы.
2. Операционно-логическая история. По сравнению с операци-
онной историей дополняется распознавателями, пройденными по ходу работы программы.
3. Информационный граф реализации программы. Вершины
графа – преобразователи. Вершина vi соединяется с вершиной v
, если
j
vj использует результат vi в качестве аргумента.
4. Информационно-логический граф реализации программы.
Информационный граф дополняется вершинами проходимых по ходу работы программы распознавателей.
5. Термальное значение результирующих переменных.
Для каждого аргумента a любой вершины графа строится дерево, включающее в себя все вершины, достижимые из a при движении на­встречу дугам информационных связей. Это дерево может быть запи­сано в виде некоторого терма и называется термальным значением
аргумента a.
6. Логико-термальная история реализации программы. К тер-
мальному значению результативных переменных добавляются прой­денные по ходу работы программы распознаватели вместе с термаль­ными значениями их аргументов. Логико-термальная история строится по информационно-логическому графу.
6.6. Цепочка стандартной схемы
Конечный путь по вершинам схемы, ведущий от начальной вершины к заключительной, а также бесконечный путь по вершинам схемы, начинающийся с начальной вершины схемы, называется
цепочкой стандартной схемы. Пример цепочки для схемы с рис. 6.1:
(0, 1, 2, 30, 4).
В верхнем индексе для метки 3 указан 0. Это означает, что дальнейшее построение цепочки продолжится по дуге 0 вершины­распознавателя, помеченной 3. Таким образом, верхние индексы слу­жат указателями на соответствующую исходящую дугу вершины рас­познавателя.
76
Последовательность операторов, помечающих вершины неко­торой цепочки схемы, называется цепочкой операторов. Пример це­почки операторов для схемы с рис. 6.1:
(start(x, n); y:=a; y:=f (x, y); p0(y, n); stop(y)).
Смысл верхнего индекса при условном операторе такой же, как было выше описано для вершин цепочки схемы. Не следует пу­тать этот индекс с индексом местности, который заключается в скоб­ки.
Пусть S – стандартная схема в базисе В, I – некоторая его ин­терпретация, (0, 1, k2, k3,...) – последовательность меток инструкций S, расположенных в порядке их вхождения в конфигурации протокола выполнения программы (S, I). Очевидно, что данная последователь­ность является цепочкой схемы S. Говорят, что интерпретация I порождает (подтверждает) эту цепочку.
Цепочка стандартной схемы в базисе B называется допусти- мой, если она подтверждается хотя бы одной интерпретацией этого базиса.
Стандартная схема называется свободной, если все ее цепочки допустимы.
Цепочка операторов называется допустимой, если она соответ­ствует допустимой цепочке схемы.
6.7. Свободные интерпретации
Свойства тотальности и пустоты, а также отношение функ­циональной эквивалентности введены для множеств всех возможных интерпретаций базиса. Это означает, что если мы хотим установить, является ли некоторая схема S пустой, то нам придется устанавливать этой свойство для любой интерпретации I. Множество всех интерпре­таций очень велико, и потому такой подход оказывается малополез­ным. Поэтому вместо всего множества интерпретаций рассматривает­ся подкласс свободных интерпретаций.
Справедливость высказываний о семантических свойст­вах стандартной схемы, оказывается, достаточно продемонстриро­вать для программ, получаемых только с помощью этого под­класса.
77
Все свободные интерпретации базиса В имеют одну и ту же область интерпретации. Она совпадает со множеством Т всех термов базиса В. Строится свободная интерпретация следующим образом:
1. Для любой переменной x из базиса В и для любой свобод-
ной интерпретации Ih этого базиса Ih(х) = х.
2. Для любой константы а из базиса В Ih(a) = a.
3. Для любого функционального символа f
В Ih(f F
(n)
(n)
) = F
(1,..., n) = f
(n)
: Тn Т, где F
(n)
(1,..., n). Это означает, что функция F, используя
(n)
– словарная функция такая, что
(n)
(n 1) из базиса
функциональный символ f, по термам 1,..., n Т строит новый терм.
Предикатному символу в свободной интерпретации сопостав­ляется произвольный предикат, отображающий T в {0, 1}. Таким об­разом, разные свободные интерпретации различаются лишь интерпре­тацией предикатных символов.
Интерпретация I базиса B и свободная интерпретация Ih ба­зиса B называются согласованными, если π I(π) = Ih(π), где π – логи­ческое выражение.
78
7. ОПИСАНИЕ СИНТАКСИСА И СЕМАНТИКИ ЯЗЫКА ПРОГРАММИРОВАНИЯ
7.1. Проблема точного описания языка программирования
Одной из главных проблем, связанных с созданием и примене­нием языка программирования, является его точное описание. Как уже отмечалось ранее, для определения формального языка необходимы алфавит, из элементов которого строятся его конструкции, и правила, по которым это построение будет производиться. Для полного описа­ния языка программирования также необходимо определить смысло­вую нагрузку соответствующих конструкций.
Итак, для определения языка программирования необходимо задать:
1. Множество символов языка.
2. Синтаксис языка, который определяет правила составления
корректных программ как цепочек, состоящих из основных символов языка.
3. Семантику языка, которая задает смысловые значения кон-
струкций языка.
Точное описание языка необходимо, во-первых, разработчикам языковых процессоров. Языковой процессор – это программа, осуществляющая перевод программы на языке программирования в машинный код, который может быть выполнен на данном физическом или виртуальном процессоре. Примерами языкового процессора явля­ются компиляторы и интерпретаторы.
Вид и смысл языковых конструкций должны быть в точности такими, как их задумал автор языка. Любые реализации языкового процессора должны давать одинаковые результаты для одинаковых программ.
Пользователю языка программирования также необходимо точное определения этого языка, иначе он просто не сможет правиль­но понимать и использовать его конструкции.
Таким образом, описание языка программирования должно быть достаточно полным, однозначным (не допускающим двусмыс­ленных толкований) и непротиворечивым.
Естественный язык не слишком хорошо подходит для решения поставленной задачи, т.к. его конструкции не обладают достаточной однозначностью и непротиворечивостью: одна и та же фраза может
79
быть понята разными людьми по-разному, в зависимости от уровня их знания, компетентности, мировоззрения, взгляда на проблему и т.д. Поэтому возникает необходимость использования какого-то другого, специального языка, который бы не обладал указанными недостат­ками.
Язык, предназначенный для описания другого языка, называ­ется метаязыком. Метаязык задает систему обозначений, понятий языка и образованных из них конструкций, позволяющих представить описываемый язык с помощью определенных ранее понятий и отно­шений между ними.
7.2. Определение синтаксиса языка программирования
Определение синтаксиса языка программирования является отправной точкой его разработки. Существует ряд методов, позво­ляющих представить синтаксис в формализованном виде. Некоторые из них рассмотрены ниже.
7.2.1. Форма Бэкуса–Наура
В форме Бэкуса–Наура каждое определяемое понятие пред­ставляется с помощью металингвистической переменной. Ее значени­ем может быть любая конструкция из некоторого множества, фикси­рованного для данного понятия.
Металингвистические переменные описываются с помощью формы, состоящей из двух частей.
В левой части указывается сама металингвистическая пере­менная, которую необходимо определить. Она заключается в угловые скобки «<» и «>», которые в данном случае считаются специальными символами («метасимволами»), не принадлежащими к алфавиту рас­сматриваемого языка.
В правой части формы записываются все варианты определе­ния описываемой конструкции. Каждый такой вариант представляет собой цепочку, состоящую из символов языка и металингвистических переменных. Варианты отделяются друг от друга символом «|», вы­полняющим роль логической операции «или». Между левой и правой частью ставится символ «::=», который можно интерпретировать как «по определению является».
80
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]