8.3.2. Синтаксичні правила та вивідні ланцюжки
Система БНФ для виразів присвоювання мови С++, записана в прикладах вище, описує їх дещо спрощений синтаксис. Система задає формальну мову, утворену представниками поняття <вираз присвоювання>. Породження (виведення) цих представників з їх позначення, тобто нетермінала <вираз присвоювання>, розглянемо на прикладі.
Приклад. Назвемо поняття “вираз присвоювання” головним, а нетермінал <вираз присвоювання> — початковим, або стартовим, і позначимо його S. Замінимо нетермінал S тілом правила (або однією з альтернатив, якщо їх декілька), в якому S є головою, й одержимо послідовність терміналів і нетерміналів, вивідну з S. Запишемо термінали без апострофів.
<ім’я> = <вираз>
Замінимо у вивідній послідовності який-небудь нетермінал відповідним йому тілом (однією з альтернатив), та одержимо послідовність, теж вивідну з S. З послідовності <ім’я> = <вираз> утворюються, наприклад, такі.
<Б><ПБЦ> = <вираз> <ім’я> = <вираз> <вираз> <ім’я> = (<вираз>) <ім’я> = <ім’я>
У вивідних послідовностях нетермінали так само замінюємо відповідними метавиразами, утворюючи нові вивідні послідовності, наприклад, такі.
<Б>= <вираз> <ім’я>=<ім’я>+<вираз>
Описані заміни виконуються, поки не буде одержано послідовності терміналів, наприклад A=B або CC=A01+B10.
Усі вивідні послідовності терміналів називаються вивідними ланцюжками (словами мови). Вони є представниками головного поняття, а їх множина — формальною мовою, яку задає система БНФ.
Записи можна виводити з довільного нетермінала системи БНФ, а не лише з початкового, як у прикладі вище. Тоді одержуються представники відповідного поняття, наприклад конкретні вирази або імена: (B1+C0), (A01), A01.
Отже, БНФ — це вираз, складений з терміналів, нетерміналів та метасимволів. БНФ має певну структуру — нетермінал, знак “::=”, метавираз. Семантикою системи БНФ є означення структури й множин представників понять, позначених нетерміналами. Мова БНФ використовується для опису синтаксису інших мов, тому називається метамовою. Її було створено наприкінці 1950-х років, щоб формально описувати синтаксис мов програмування. Виявилося, що синтаксис практично всіх конструкцій мов програмування описується за допомогою систем БНФ (звичайно, складніших, ніж у прикладах вище).
8.3.3. Розширені форми Бекуса–Наура
Доповнимо мову БНФ кількома зручними конструкціями. Для цього знадобиться ще одне поняття — еквівалентність БНФ.
Дві системи БНФ називаються еквівалентними, якщо задають одну й ту саму формальну мову.
Для коротшого й наочнішого запису еквівалентних БНФ в метавирази додають метасимволи (, ), [, ], {, }. Метавираз із такими символами називається розширеним, а БНФ — розширеною, або РБНФ. Розглянемо утворення РБНФ.
Нехай букви X, Y, Z, …, T позначають довільні метавирази (можливо, порожні), N — нетермінал.
1. Декілька альтернатив вигляду X Z Y | ... | X T Y у метавиразі, які мають спільні початок X та закінчення Y, можна замінити таким метавиразом.
X ( Z | ... | T ) Y
Метасимволи ( та ) тут просто відокремлюють частину метавиразу з альтернативами Z, …, T від інших частин.
Приклад. Правило
<вираз> ::= <ім’я> '+' <ім’я> | <ім’я> '-' <ім’я>
можна замінити еквівалентним.
<вираз> ::= <ім’я> ('+' | '-') <ім’я>
2. Замість двох альтернатив вигляду X Z Y | X Y можна записати такий еквівалентний вираз.
X [ Z ] Y
Приклад. Замість БНФ
<вираз> ::= <ім’я> | <ім’я> ('+'| '-') <ім’я>
запишемо таку.
<вираз> ::= <ім’я> [ ('+'| '-') <ім’я> ]
Аналогічно, замість БНФ
<інструкція_розгалуження> ::=
if '(' <умова> ')' <інструкція> |
if '(' <умова> ')' <інструкція> else <інструкція>
запишемо таку.
<інструкція_розгалуження> ::= if '(' <умова> ')' <інструкція> [ else <інструкція> ]
3. Семантику метасимволів {, } означимо за допомогою прикладу.
Приклад. Ім’я, або ідентифікатор, у мовах програмування — це послідовність букв і цифр, що починається з букви. Нехай буквами є тільки A, B, C, цифрами — 0 і 1. Для імен вище було означено таку систему БНФ.
<ім’я> ::= <Б><ПБЦ> <ПБЦ> ::= <> | (<Б> | <Ц>) <ПБЦ> <Б> ::= 'A' | 'B' | 'C' <Ц> ::= '0' | '1'
Узагальнимо букви й цифри поняттям “буква-цифра” з нетерміналом <БЦ>, додавши таке правило.
<БЦ> ::= <Б> | <Ц>
Тоді <ПБЦ> можна задати двома такими правилами.
<ПБЦ> ::= <> | <БЦ> <ПБЦ>
За допомогою цих правил із нетермінала <ПБЦ> можна вивести всі можливі послідовності <БЦ>:
<>, <БЦ>, <БЦ><БЦ>, ...,
і тільки їх. Позначимо множину послідовностей, складених з <БЦ>, метавиразом {<БЦ>} із новими метасимволами {, }. Будемо вважати, що всі послідовності <БЦ> вивідні з цього метавиразу. Тоді правилу
<ПБЦ> ::= {<БЦ>}
еквівалентні такі.
<ПБЦ> ::= <> | <БЦ> <ПБЦ>
Якщо X — довільний метавираз, то метавираз {X} позначає всі скінченні послідовності <>, X, XX, XXX, … . Дужки {} називаються ітераційними й підкреслюють ітеративну природу різного роду послідовностей.
Приклади.
1. Інструкція оголошення імен змінних у С++-програмі починається ім’ям типу (або іншим виразом, що задає тип), після якого записано список імен змінних і знак “;”. Задамо синтаксис інструкції оголошення імен змінних такою РБНФ.
<оголошення_змінних> ::= <ім’я типу> <список імен> ';'
Обмежимося іменами типів int і char.
<ім’я типу> ::= 'int' | 'char'
Імена в списку розділяються комами, список має бути непорожнім.
<список імен> ::= <ім’я> { ',' <ім’я> }
2. Блок у мові С++ — це послідовність інструкцій (можливо, порожня) в дужках {}.
<блок> ::= '{' { <інструкція> } '}'
3. Розглянемо вирази з цілими константами, знаками адитивних операцій “” і “”, мультиплікативних операцій “*” і “/”, а також дужками. Припустимо таке:
– вираз розглядається як сума доданків (термів);
– терм є добутком множників (англійською factor);
– множник є константою або виразом у дужках;
– константа — це непорожня послідовність цифр, можливо, зі знаком “” або ““.
Запишемо ці правила мовою РБНФ. Позначимо вирази, терми, множники й константи нетерміналами E (Expression), T (Term), F (Factor) і C (Constant). Початковий нетермінал — E. Для опису суми термів і добутків співмножників використовуємо ітераційні дужки.
E ::= T {('+'|'-') T} T ::= F {('*'|'/') F} F ::= C | (E) C ::= ['+'|'-']D{D} D ::= '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
Рекурсивність синтаксичних правил (E означається за допомогою T, T — за допомогою F, F — за допомогою E) в останньому прикладі відтворює рекурсивну природу означуваних виразів.
