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

osn_progr_final

.pdf
Скачиваний:
37
Добавлен:
12.02.2016
Размер:
3.27 Mб
Скачать

Визначення 3. Формальною граматикою Г називається наступна сукупність чотирьох об'єктів:

Г = { VТ, VA, <I>, R },

де VT - термінальний алфавіт (словник); букви цього алфавіту називаються термінальними символами; з них будуються ланцюжки, породжувані граматикою; для позначення букв термінального словника надалі домовимося використовувати малі літери латинського алфавіту;

VA - нетермінальний, допоміжний алфавіт (словник); букви цього алфавіту використовуються при побудові ланцюжків; вони можуть входити в проміжні ланцюжки, але не повинні входити в результат побудови; домовимося для позначення нетермінальних символів використовувати ідентифікатори, що складаються з великих літер латинського алфавіту і поміщені в кутові дужки;

<I> - початковий символ чи аксіома граматики, <I> VA.

R - множина правил виведення виду ,

де та - лан-

цюжки, побудовані з букв алфавіту VТ VA, який

називають пов-

ним алфавітом (словником) граматики Г.

 

У множину правил граматики можуть також входити правила з порожньою правою частиною виду <Е> . Щоб уникнути невизначеності через відсутність символу в правій частині правила, домовимося використовувати символ порожнього ланцюжка, записуючи таке правило у вигляді: <Е> $.

Правила виведення граматики використовуються для побудови ланцюжків.

Визначення 4. Нехай r = - правило граматики Г і = '" - ланцюжок символів, причому ', " (Vт VA) *. Тоді ланцю-

жок = ' " може бути отриманий з ланцюжка шляхом застосування правила r (тобто заміною в ланцюжку на ). У цьому випа-

дку говорять, що ланцюжок безпосередньо виведений з ланцюжка і позначають .

Визначення 5. Якщо задана сукупність ланцюжків = ( 0,

1,..., n), таких що існує послідовність безпосередніх виведень:

0 1, 1 2, ... , n-1 n,

то таку послідовність називають виводом n з 0 у граматиці Г і позначають 0 * n.

41

Визначення 6. Множина скінчених ланцюжків термінального алфавіту Vт граматики Г, виведених з початкового символу <I>, на-

зивається мовою, породжуваною граматикою Г и позначається L( Г). L( Г ) = { VТ* | <I> * }.

Розглянемо кілька прикладів, що ілюструють введені поняття: Приклад 1.

Задано граматику Г1.1, потрібно визначити мову, породжувану цією граматикою:

Г1.1: VТ = {a, b, c}, VА = {<I>}, R = {<I> abc}.

Схема граматики містить одне правило, тому Г1.1 породжує мову з одного слова L(Г1.1) = {abc}.

Приклад 2.

Задано граматику Г1.2 і потрібно визначити мову, породжувану цією граматикою.

Г1.2 : VТ = {a, b, c}, VА = {<I>, <B>, <C>} R = { <I> a<B>,

<B> <C>d, <B> dc, <C> $}.

Побудуємо усі виведення в цій граматиці. Це можна зробити двома способами. Спочатку застосуємо правила 1,2,4, а потім побудуємо друге виведення, використовуючи правила 1 і 3. В результаті отримаємо:

<I> a<B> a<C>d ad, <I> a<B> adc.

Отже мова, породжувана цією граматикою, складається з двох ланцюжків L(Г1.2) = {adc, ad}.

Приклад 3.

Задано граматику Г1.3 і потрібно визначити мову, породжувану цією граматикою.

Г1.3 : VА = {<I>, <A>}, VТ= {0, 1}, R = {<I> 0<A>1,

<A> 0<A>1, <A> $}.

Схема наведеної граматики містить три правила. Друге правило містить нетермінальний символ <А> як у лівій, так і в правій частині правила. Такі правила називають рекурсивними. Застосування такого правила до ланцюжка, що містить нетермінал <А>, призводить до

42

отримання нового ланцюжка, у який знову входить <А>. Таким чином, заміну нетермінала <А> правою частиною правила можна виконувати багаторазово, що дозволяє будувати як завгодно довгі ланцюжки. Щоб виведення із застосуванням рекурсивного правила не було нескінченним, у схемі граматики повинне бути хоча б одне правило із символом <А> у лівій частині. Таке правило завершує рекурсію, виключаючи <А> з виведеного ланцюжка. У розглянутій граматиці для завершення виведення використовується правило <А> $. Розглянемо побудову виведень за допомогою правил граматики Г1.3. Застосовуючи перше і третє правила, отримуємо:

<I> 0<A>1 01.

Застосувавши перше, друге, а потім третє правило, маємо

<I> 0<A>1 00<A>11 0011.

Застосувавши друге правило k разів, одержимо в результаті ланцюжок, що містить k нулів і k одиниць. Отже, мова, породжувана граматикою Г1.3, містить усі ланцюжки, у яких число нулів дорівнює числу одиниць.

Приклад 4:

Задано граматику Г1.4 . Потрібно побудувати мову, породжувану цією граматикою.

Г1.4 : VТ= {a, b}, VА = {<I>, <A>}, R = { <I> a<A>, <A> b<A>}.

Спроба побудови виведення в цій граматиці приводить нас до ланцюжка

<I> a<A> ab<A> abb<A> …,

який виявляється нескінченним. У розглянутій граматиці відсутнє правило, що дозволяє завершити рекурсію, тому за допомогою правил цієї граматики не можна побудувати жодного скінченого ланцюжка. Іншими словами, граматика Г1.4 породжує порожню мову.

Визначення 7 Якщо мова, породжувана граматикою Г, не містить жодного скінченного ланцюжка (скінченного слова), то вона називається порожньою.

3.2ТИПИ ФОРМАЛЬНИХ ГРАМАТИК

Утеорії формальних мов виділяються 4 типи граматик, яким відповідають 4 типи мов. Ці граматики виділяються шляхом накладення обмежень на правила граматики.

Граматики типу 0, що називають граматиками загального виду, не мають ніяких обмежень на правила породження. Будь-яке правило

43

r =

може бути побудоване з використанням довільних ланцюжків(Vт Va)*. Наприклад,

<T> <W> <W> <T> чи x <A> b <C> <D> x <H> <D>.

Граматики типу 1, що називають також контекстно-залежними граматиками, не допускають використання будь-яких правил. Правила виведень в таких граматиках повинні мати вигляд:

1 <A> 2 1 2,

де 1, 2 - ланцюжка, можливо порожні, з множини (Vт Va)*, символ <А> Va і ланцюжок ω (Vт Va)*. Ланцюжка 1 і 2 залишаються незмінними при застосуванні правила, тому їх називають контекстом (відповідно лівим і правої), а граматику - контекстно залежною.

Граматики типу 1 значно зручніші на практиці, ніж граматики типу 0, оскільки в лівій частині правила заміняється завжди один нетермінальний символ, який можна зв'язати з деяким синтаксичним поняттям, у той час як у граматиці типу 0 можна заміняти відразу кілька символів, у тому числі і термінальних.

Наприклад, граматика:

Г1.5:

VТ = {a, b, c, d}, VА = {<I>, <A>, <B>} R = { <I> a <A> <I>,

<A> <I> <A> <A> <I>,

<A> <A> <A> <A> <B> <A>, <A> b,

b <B> <A> b c d <A>, b <I> b a }

є контекстно-залежною, оскільки друге і шосте правила мають непорожній лівий контекст, а третє і п'яте правила містять обидва контексти. Виведення у такій граматиці може мати вигляд:

<I> a<A><I> a<A><A><I> ab<A><I> abb<I> abba.

Граматики типу 2 називають контекстно-вільними чи безконтекстними граматиками ( КВ-граматики чи Б-граматики). Правила виведень таких граматик мають вигляд:

<A> ,

де <A> VА і (VТ VА)*.

Очевидно, що ці правила виходять із правил граматики типу 1 за умови 1 = 2 = $. Оскільки контекстні умови відсутні, то правила КВ-

44

граматик виходять простішими, ніж правила граматик типу 1. Саме такі граматики використовуються для опису мов програмування. Прикладом КС-граматики може служити наступна граматика:

Г1.6: VТ= {a, b}, VА = {<I>}, R = { <I> a<I>a,

<I> b<I>b, <I> aa,

<I> bb}.

Ця граматика породжує мову, що складається з ланцюжків, кожен з яких, у свою чергу, складається з двох частин, ланцюжка

VТ* і дзеркального відображення цього ланцюжка '.

L( Г1.6 ) = { ' | VТ+},

де VТ+ - це множина VТ* без порожнього ланцюжка. За допомогою правил цієї граматики може бути побудований, наприклад, наступний ланцюжок:

<I> a<I>a ab<I>ba aba<I>aba ababbaba.

Граматики типу 3 називають автоматними граматиками (А - граматиками). Правила виведень в таких граматиках мають вигляд:

<A> a чи <A> a <B> чи <A> <B> a,

де a VТ, і <A>, <B> VА, причому граматика може мати тільки правила виду <A> a <B> - правосторонні правила, або тільки виду <A> <B> a - лівосторонні правила.

Прикладами автоматних граматик можуть служити правостороння граматика Г1.7 і лівостороння граматика Г1.8

Г1.7: VТ = {a, b}, VА = {<I>, <A>}, R = { <I> a <I>,

<I> a <A>, <A> b <A>, <A> b <Z>, <Z> $ }.

Г1.8:

VТ= {a, b}, VА = {<I>, <A>}, R = { <I> <A> b, <A> <A> b,

<A> <Z> a, <Z> <Z> a,

<Z> $ }.

45

Ці граматики породжують одну і ту ж саму мову. Якщо позначати ланцюжок, що складається з k однакових символів x як xk, наприклад x4 = xxxx, то мову, що породжується цими граматиками, можна

визначити в такий спосіб: L(Г1.8) = { anbm | n,m > 0}.

Класифікація мов може бути побудована відповідно до типу граматик, що породжують мову. Однак одна і та ж сама мова може бути задана різними граматиками, що можуть бути різнотипними. Тому тип мови визначають по типу тієї граматики, що не може бути представлена граматикою типу k+1.

Наприклад, якщо граматика типу 2 містить правило виду

<А> a1 a2 <B> a3 a4,

то перетворити її в автоматну граматику не можна. Отже, мова, що породжується такою граматикою, відноситься до мов типу 2. Якщо ж схема граматики типу 2 містить правила виду

<А> a1 a2 a3 a4 <B>,

то можна показати, що таку граматику можна перетворити до граматики типу 3 і, отже, мова, породжена цією граматикою, є мовою типу

3.

Якщо позначити множину мов типу k виразом {Lтипуk}, то відношення між множинами мов різних типів можна визначити за допо-

могою наступного включення:

{ L типу3 } { L типу2 } { L типу1 } { L типу0}.

При цьому доведено, що існують мови типу 0, що не є мовами типу 1, мови типу 2, що не є мовами типу 1, і мови типу 3, не є мовами типу 2.

3.3 БНФ.

Ми вже відзначали, що вченими велика увага приділялася проблемам формалізації опису синтаксису мови програмування. Однак, помітимо, що вдалий формалізм дозволяє не тільки описувати мови, але і спрощувати роботу зі створення компіляторів.

Мова, що використовується для формалізації синтаксису іншої мови, називається метамовою.

Схема граматики містить правила виведень, що визначають синтаксис мови, чи, іншими словами, допустимі компоненти і конструкції ланцюжків мови. Для задання правил використовуються різні форми опису: символічна, форма Бекуса-Наура, ітераційна та синтаксичні діаграми.

46

У роботах, зв'язаних з розглядом загальних властивостей граматик, звичайно застосовують символічну форму задання правил. Ця форма була розглянута в попередньому параграфі. Вона передбачає використання як елементів нетермінального словника окремих символів і стрілки - як роздільник правої і лівої частин правила.

При описі синтаксису конкретних мов програмування доводиться вводити велику кількість нетермінальних символів і символічна форма запису втрачає свою наочність.

В даний час найбільш вживаною для опису синтаксису мов програмування є метамова форм Бекуса-Наура (БНФ).

Ідея цієї метамови полягає в структуруванні понять вихідної мови програмування і визначення більш складних понять через більш прості. Для цього в мові БНФ прийняті наступні угоди.

Будь-яке поняття зображується своїм найменуванням, поміщеним у кутові дужки: <...>. Речення БНФ являє собою одне визначення деякого поняття через інші у формі:

поняття,знак "::=", після якого записується визначення поняття.

У складі визначення можуть використовуватися інші поняття мови програмування, символи алфавіту, ключові слова мови програмування, а також спеціальні символи мови БНФ, що мають визначений сенс.

Як такі символи використовуються вертикальну риску і круглі, квадратні та фігурні дужки. Їхнє використання підкоряється наступним правилам:

запис <поняття1> ::= <поняття2> <поняття3> і

т.д. означає, що перше поняття являє собою послідовний запис інших понять;

запис <поняття1> ::= <поняття2> | <поняття3>

| і т.д. означає, що перше поняття збігається з одним з інших понять;

круглі дужки використовуються для групування складних конструкцій БНФ усередині простих (допоміжний інструмент, можна не використовувати);

взяття в квадратні дужки частини визначення говорить про те, що ця частина не обов'язкова;

47

взяття у фігурні дужки частини визначення, говорить про те, що ця частина може бути повторена довільну кількість раз (у тому числі жодного разу);

замість складного поняття у форми БНФ можуть входити термінальні символи і ключові слова; для того, щоб відрізняти їх від символів БНФ (наприклад, дужок) домовимося, що будемо виділяти символи і ключові слова мови жирним курсивом.

Наведемо кілька прикладів.

1. Непорожній список, що складається з довільного числа елементів, розділених комами, описується так:

<список>::= <елемент списку>{,<елемент спис-

ку>}

2.Якщо список може бути порожнім, то його опис буде виглядати так:

<список>::= | <елемент списку>{,<елемент списку>}

3.Ідентифікатором є послідовність букв і цифр, що починається

збукви :

<ідентифікатор>::=<буква>{<буква>|<цифра>}

Більшість символів у мовах програмування попадають в один з наступних класів:

ідентифікатори;

службові слова (які є підмножиною ідентифікаторів);

цілі числа;

однолітерні розділювачі (+, - (,), / і т.д.);

дволітерні розділювачі (//, /*, **, : = і т.д.).

Ці символи можуть бути описані наступними простими правилами:

<ідентифікатор>::=<буква> | <ідентифікатор> <буква> | <ідентифікатор> <цифра>

<ціле> ::= <цифра> | <ціле> <цифра>

<розділювач> ::= + | - | ( | ) | \ <SLASH> | <AST> | <COLON>

<SLASH> ::= / <AST> ::= * <COLON> ::= :

48

3.4 ГРАМАТИКИ, ЩО ОПИСУЮТЬ НАЙПРОСТІШІ КОНСТРУКЦІЇ МОВ ПРОГРАМУВАННЯ.

Розглянемо як можна описувати конструкції мов програмування

звикористанням граматик.

1.Нехай маємо ціле число. Воно являє собою послідовність цифр. Тому можна розглядати його як список. Використовуючи як аналог граматику, що задає список без розділювачів, одержуємо схему граматики для цілих чисел у вигляді:

Г: <N> <D> <R>,

<R> <D> <R> <R> $, <D> 0 | 1 | ... | 9.

2. Основною лексичною одиницею будь якої мови програмування є ідентифікатор. Його структуру можна представити у вигляді двох компонент: початку та основної частини. Початком може бути кожна з букв, а основна частина являє собою список без розділювачів, елементами якого можуть бути або букви, або цифри (домовимось, для полегшення, що інші символи не будемо використовувати для запису ідентифікатора). Використовуючи виділені компоненти, одержуємо схему граматики виду:

Г: R ={ <I> <C> <A>, <A> <C> <A> | <D> <A>,

<A> <C> | <D>, <A> $, <D> 0 | 1 | ... | 9,

<C> a | d | c | ... | z |_}.

3. Домовимося розглядати арифметичні вирази, що використовують тільки знаки додавання і віднімання. Спочатку побудуємо граматику для виразів без дужок. Такі вирази являють собою ланцюжки, які можна розглядати як списки з розділювачами, у яких роль розділювачів виконують знаки операцій. Відповідно до цієї аналогії одержуємо схему граматики, у якій символ <I> позначає ідентифікатор, визначення якого наведено вище.

Г1 : R = { <H> <I> <R>,

<R> <W> <I> <R>, <R> $,

49

<W> +, <W> - }.

Щоб побудувати граматику, що допускає використання в арифметичних виразах дужки без вкладеності, представимо структуру таких виразів у вигляді списку з розділювачами, елементами якого є вирази без дужок чи вирази без дужок, вкладені в дужки. Розділювачами цього списку є знаки операцій. Такій структурі відповідає наступна схема граматики:

Г2 : R = { <G> <H> <Q>, <G> ( <H> ) <Q>,

<Q> <W> <G>, <Q> $ }.

У схемі цієї граматики використовуються нетермінали, визначені в граматиці Г1.

4. Нехай потрібно побудувати граматику для опису цілих і дійсних змінних. Нехай опис змінних визначеного типу повинен починатися вказівником типу float чи int. У повному тексті опису змінні визначеного типу можуть повторюватися. Наприклад, повний опис може включати три різних описи змінних цілого типу. Як розділювач описів змінних різних типів приймемо крапку з комою, а як розділювач змінних одного типу - кому. Структуру повного опису можна представити у вигляді двох вкладених списків з розділювачами. Внутрішній список, розглянутий як елемент зовнішнього списку, являє собою опис змінних одного типу. Він має заголовок у вигляді вказівника типу, за яким слідує послідовність ідентифікаторів, розділених комами. Зовнішній список використовує як розділювач крапку з комою. Схема граматики розглянутого виду може бути записана так:

Г : R = { <Z> <A2>, <A2> <B1> <C1>,

<C1> ; <B1> <C1>, <C1> $,

<B1> 'float' <L>, <B1> 'int' <L>, <L> <I> <K>,

<K> , <I> <K>, <K> $ }

5. Розглянемо операцію присвоювання. Припустимо, що в її правій частині можуть бути використані лише вирази без дужок, що

50

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]