
- •2.3 Розвиток основних понять програмування 53
- •1. Формалізація простої мови програмування
- •1.1 Неформальний опис простої мови програмування
- •1.2 Формальний опис синтаксису мови sipl
- •Малюнок 1.1. Дерево синтаксичного виводу програми gcd
- •1.3 Формальний опис семантики мови sipl
- •Малюнок 1.3. Алгебра даних мови sipl
- •1.3.2 Функції
- •1.3.3 Композиції
- •1.3.4 Програмні алгебри
- •Малюнок 1.4. Алгебра функцій (програмна алгебра)
- •1.3.5 Визначення семантичних термів
- •1.3.6 Побудова семантичного терму програми
- •1.3.7 Обчислення значень семантичних термів
- •1.3.8 Загальна схема формалізації мови sipl
- •Малюнок 1.5 Схема визначення композиційної семантики
- •1.4 Властивості програмної алгебри
- •2. Розвиток основних понять програмування
- •2.1 Аналіз словникових визначень поняття програми
- •2.2 Розвиток поняття програми з гносеологічної точки зору
- •2.3 Розвиток основних понять програмування
- •2.3.1 Початкова тріада понять програмування
- •Малюнок 2.2. Сфера інформатизації як особлива сфера суспільства
- •Малюнок 2.3. Тріада цільового призначення програм
- •2.3.2 Тріада прагматичності програм
- •Малюнок 2.4. Тріада прагматичності програм
- •2.3.3 Тріада основних понять програмування
- •Малюнок 2.5. Тріада основних понять програмування
- •2.3.4 Пентада основних понять програмування
- •Малюнок 2.6. Пентада основних понять програмування
- •2.4 Розвиток основних програмних понять
- •2.4.1 Тріада основних програмних понять
- •Малюнок 2.7. Програма як діалектичне заперечення проблеми
- •2.4.2 Пентада основних програмних понять
- •2.5 Сутнісні та семіотичні аспекти програм
- •2.6 Програми і мови
- •2.7 Пентада програмних понять процесного типу
- •3. Формалізація програмних понять
- •3.1 Теоретико-функціональна формалізація
- •3.2 Класи функцій
- •3.3 Програмні системи
- •3.4 Рівні конкретизації програмних систем
- •4. Синтактика: формальні мови та граматики
- •4.1 Розвиток понять формальної мови та породжучої граматики
- •4.2 Визначення основних понять формальних мов
- •4.3 Операції над формальними мовами
- •4.3 Породжуючі граматики
- •4.5 Ієрархія граматик Хомського
- •4.6 Автоматні формалізми сприйняття мов
- •4.6.1 Машини Тьюрінга
- •4.6.2 Еквівалентність машин Тьюрінга та породжуючих граматик
- •4.6.3 Лінійно-обмежені автомати
- •4.6.4 Магазинні автомати
- •4.6.5 Скінченні автомати
- •4.7 Методи подання синтаксису мов програмування
- •4.7.1 Нормальні форми Бекуса–Наура
- •4.7.2 Модифіковані нормальні форми Бекуса–Наура
- •4.7.3 Синтаксичні діаграми
- •4.8 Властивості контекстно-вільних граматик
- •4.8.1 Видалення несуттєвих символів
- •4.8.2 Видалення -правил
- •4.8.3 Нормальна форма Хомського
- •4.8.4 Нормальна форма Грейбах
- •4.8.5 Рекурсивні нетермінали
- •4.9 Властивості контекстно-вільних мов
- •4.10 Операції над формальними мовами
- •4.11 Дерева виводу
- •4.12 Однозначні та неоднозначні граматики
- •4.13 Розв’язні та нерозв’язні проблеми кв-граматик та мов
- •4.14 Рівняння в алгебрах формальних мов
- •5. Теорія рекурсії (теорія найменшої нерухомої точки)
- •5.1 Рекурсивні визначення та рекурсивні рівняння
- •5.2 Частково впорядковані множини, границі ланцюгів та -області
- •5.3 Неперервні відображення
- •5.4 Теореми про нерухомі точки
- •5.5 Конструювання похідних -областей
- •5.6 Властивості оператора найменшої нерухомої точки
- •5.7 Застосування теорії ннт
- •5.7.1 Уточнення синтаксису мов програмування
- •5.7.2 Семантика мов програмування
- •5.7.3 Рекурсивні розширення мови sipl
1.3.5 Визначення семантичних термів
Дотепер ми не дуже чітко розрізняли функціональний вираз алгебри A_Prog та функцію, що задається цим виразом. Наприклад, запис (fg)h можна тлумачити як функцію, і тоді її можна застосувати до стану st, та як вираз, і тоді, наприклад, вивчати тотожність (fg)h=f(gh). В математичній логіці таке розрізнення роблять явним, вважаючи, що (fg)h є виразом (термом, формулою), а не функцією. Саму ж функцію, яка задається цим виразом, позначають, наприклад, (fg)h I , де I – інтерпретація символів f, g, h в алгебрі A_Prog.
Таке розрізнення можна було б зробити і для мови SIPL. В такому випадку для опису (дескрипції) функцій, які задаються програмами мови SIPL, можуть використовуватись функціональні вирази алгебри A_SIPL, які називаються термами цієї алгебри. Такі класи термів будуються індуктивно, аналогічно класам синтаксичних категорій. Терми програмної алгебри будемо також називати семантичними термами. Але зараз не будемо використовувати різні позначення для термів та функцій, сподіваючись, що читач із контекста зрозуміє, про яке поняття іде мова. Разом з тим, слід пам’ятати, що це розрізнення є важливим в теорії програмування, яка чітко виокремлює синтаксис та семантику програм.
1.3.6 Побудова семантичного терму програми
Програма мови SIPL може бути перетворена в семантичний терм (терм програмної алгебри), який задає семантику цієї програми (семантичну функцію програми), перетвореннями такого типу:
-
sem_P: Prog FS
-
sem_S: Stm FS
-
sem_A: Aexp FA
-
sem_B: Bexp FB
Ці перетворення задаються рекурсивно (за структурою програми). Тому побудова семантичного терму залежить від вибору структури синтаксичного запису програми. Тут треба зважати на неоднозначність обраної нами граматики, що може призвести до різної семантики програм. Для досягненя однозначності треба користуватись пріоритетами операцій та типом їх асоціативності.
Таблиця 1.6
Правило заміни |
Номер правила |
sem_P: Prog FS задається правилами:
|
|
sem_P(begin S end)= sem_S(S) |
NS_Prog |
sem_S: Stm FS задається правилами:
|
|
sem_S(x:=a)=ASx(sem_A(a)) sem_S(S1;S2)= sem_S(S1) sem_S(S2) sem_S(if b then S1 else S2)= IF(sem_B(b), sem_S(S1), sem_S(S2)) sem_S(while b do S)= WH(sem_B(b), sem_S(S)) sem_S(begin S end)=(sem_S(S)) sem_S(skip)=id
|
NS_Stm_As NS_Stm_Seq NS_Stm_If
NS_Stm_Wh NS_Stm_skip
|
sem_A: Aexp FA задається правилами:
|
|
sem_A(n))=
sem_A(x))=x sem_A(a1+a2)=S2(add, sem_A(a1), sem_A(a2)) sem_A(a1–a2)=S2(sub, sem_A(a1), sem_A(a2)) sem_A(a1a2)=S2(mult, sem_A(a1), sem_A(a2)) sem_A(a1a2)=S2(div, sem_A(a1), sem_A(a2)) sem_A((a))=sem_A(a) |
NS_A_Num NS_A_Var NS_A_Add NS_A_Sub NS_A_Mult NS_A_Div NS_A_Par |
sem_B: Bexp FB задається правилами:
|
|
sem_B(true)=
sem_B(false)=
sem_B(a1<a2)=S2(less, sem_A(a1), sem_A(a2)) sem_B(a1a2)=S2(leq, sem_A(a1), sem_A(a2)) sem_B(a1=a2)=S2(eq, sem_A(a1), sem_A(a2)) sem_B(a1a2)=S2(neq, sem_A(a1), sem_A(a2)) sem_B(a1a2)=S2(geq, sem_A(a1), sem_A(a2)) sem_B(a1>a2)=S2(gr, sem_A(a1), sem_A(a2))
sem_B(b1b2)=S2(or, sem_B(b1), sem_B(b2)) sem_B(b1b2)=S2(and, sem_B(b1), sem_B(b2)) sem_B(b)=S1(neg, sem_B(b)) sem_B((b))= sem_B(b) |
NS_B_true NS_B_false
NS_B_less NS_B_leq NS_B_eq NS_B_neq NS_B_geq NS_B_gr
NS_B_or NS_B_and NS_B_neg NS_B_Par
|
Наведені правила слід розглядати як загальні правила, які в логіці називають схемами правил. Щоб із загального правила (метаправила) отримати конкретне правило (об’єктне правило), слід замість синтаксичних метасимволів, таких як a, b, S, P, n, x, підставити конкретні синтаксичні елементи (записи), наприклад замість a підставити N–M, замість b – M>N і т.п. Далі ліва частина конкретного правила заміняються на його праву частину і т.д.
Приклад 1.2 Побудуємо семантичний терм виразу X+Y*Z. Побудова терму полягає в обчисленні значення sem_A(X+Y*Z). Щоб зробити перший крок такого обчислення, треба віднайти правило, ліва частина якого буде співпадати з записом sem_A(X+Y*Z) при відповідній конкретизації такого правила. Цей процес називається уніфікацією двох записів (термів). В нашому випадку можлива уніфікація з лівою частиною правил NS_A_Add та NS_A_Mult. В першому випадку уніфікація sem_A(X+Y*Z) та sem_A(a1+a2) можлива при заміні a1 на X та a2 на Y*Z, а в другому уніфікація sem_A(X+Y*Z) та sem_A(a1a2) можлива при заміні a1 на X+Y та a2 на Z. Наведені заміни називаються уніфікаторами і зазвичай позначаються [a1/X, a2 /Y*Z] та [a1/X+Y, a2 /Z], або [a1X, a2 Y*Z] та [a1X+Y, a2 Z]. Зазначимо, що друга уніфікація порушує пріоритет операцій, тому розглядаємо лише першу уніфікацію. Застосування цієї уніфікації до правила NS_A_Add призводить до наступного конкретного (об’єктного) правила
NS_A_Add: sem_A(X+Y*Z)= S2(add, sem_A(X), sem_A(Y*Z)).
Застосування цього правила дозволяє перетворити запис sem_A(X+Y*Z) в запис S2(add, sem_A(X), sem_A(Y*Z)). Цей запис містить два підзаписи (sem_A(X) та sem_A(Y*Z)), до яких можна застосувати перетворення. А саме, підзапис sem_A(X) уніфікується з лівою частиною правила NS_A_Var за допомогою уніфікатора [x/X], а підзапис sem_A(Y*Z) – з NS_A_Mult за допомогою уніфікатора [a1/Y, a2/Z]. Застосування цих уніфікаторів призводить до двох нових конкретних правил
NS_A_Var: sem_A(X)= X та
NS_A_Mult: sem_A(Y*Z)= S2(mult, sem_A(Y), sem_A(Z)).
Застосовуючи ці правила до виразу S2(add, sem_A(X), sem_A(Y*Z)) отримаємо S2(add, X, S2(mult, sem_A(Y), sem_A(Z))). Залишилось конкретизувати правило NS_A_Var, щоб отримати остаточний результат
sem_A(X+Y*Z)= S2(add, X, S2(mult, Y, Z))▄
Отже, процес побудови семантичного терму програми полягає в послідовному перетворенні запису, для якого будується семантичний терм. Ці перетворення вимагають наступних дій:
-
вибір загального правила, яке можна застосувати до підзапису поточного виразу з урахуванням пріоритету операцій,
-
уніфікація лівої частини правила з обраним підзаписом,
-
отримання конкретного правила із загального правила,
-
заміна у поточному записі лівої частини конкретного правила на його праву частину.
Більш формально процес перетворень такого типу сформульований в теорії переписуючих правил.
Зауважимо ще раз, що ми тлумачимо відображення sem_P: Prog FS, sem_S: Stm FS, sem_A: Aexp FA, sem_B: Bexp FB синкретично, вважаючи в залежності від контексту, що це відображення в відповідні функції класів FS, FA, FB, або в терми, що задають функції відповідних класів.
Приклад 1.3 Побудовати семантичний терм програми SIPL. Побудову будемо робити згідно вищенаведених правил. Деталі не вказуємо.
sem_P(GCD)=
= sem_P(begin
while MN do
if M>N then M:=M–N else N:=N–M
end)=
= sem_S(while MN do if M>N then M:=M–N else N:=N–M)=
= WH(sem_B(MN), sem_S(if M>N then M:=M–N else N:=N–M))=
= WH(S2(neq, sem_A(M), sem_A(N)),
IF(sem_B(M>N), sem_S(M:=M–N), sem_S(N:=N–M)))=
= WH(S2(neq, M, N), IF(S2(gr,M,N),
ASM(sem_A(M–N)), ASN(sem_A(N–M))))=
= WH(S2(neq, M, N), IF(S2(gr,M,N),
ASM(S2(sub,sem_A(M),sem_A(N))), ASN(S2(sub,sem_A(N),sem_A(M)))))=
=WH(S2(neq, M, N),
IF(S2(gr, M, N),
ASM( S2(sub, M, N)),
ASN( S2(sub, N, M))))▄
Повернемось тепер до доведення того факту, що семантика довільної програми мови SIPL задається термом алгебри A_SIPL. Дійсно, аналізуючи таблицю 1.6 бачимо, що там фігурують лише базові фукції алгебри A_SIPL. Більш стоге доведення можна отримати індукцією за структурою програми SIPL. Таким чином, є справедливим наступне твердження.
Теорема 1.1. Для довільної програми мови SIPL її семантична функція задається термом алгебри A_SIPL.