Понятие о грамматике языка

 

Грамматика – это описание способа построения предложений некоторого язы­ка. Иными словами, грамматика – это математическая система, определяющая язык.

Фактически, определив грамматику языка, мы указываем правила порождения цепочек символов, принадлежащих этому языку. Таким образом, грамматика – это генератор цепочек языка. Она относится ко второму способу определения языков – порождению цепочек символов.

Грамматику языка можно описать различными способами; например, грамма­тика русского языка описывается довольно сложным набором правил, которые изучают в начальной школе. Но для многих языков (и для синтаксической части языков программирования в том числе) допустимо использовать формальное описание грамматики, построенное на основе системы правил (или продукций).

Правило (или продукция) – это упорядоченная пара цепочек символов (α, β). В правилах очень важен порядок цепочек, поэтому их чаще записывают в виде α  β (или α ::= β). Такая запись читается как “α порождает β” или “β по опреде­лению есть α”.

Грамматика языка программирования содержит правила двух типов: первые (определяющие синтаксические конструкции языка) довольно легко поддают­ся формальному описанию; вторые (определяющие семантические ограничения языка) обычно излагаются в неформальной форме. Поэтому любое описание (или общепринятый стандарт) языка программирования обычно состоит из двух частей: вначале формально излагаются правила построения синтаксических кон­струкций, а потом на естественном языке дается описание семантических пра­вил. Естественный язык понятен человеку, пользователю, который будет писать программы на языке программирования; для компилятора же семантические ограничения необходимо излагать в виде алгоритмов проверки правильности про­граммы (речь, как уже было сказано выше, не идет о смысле программ, а только лишь о семантических ограничениях на исходный текст). Такой проверкой в компиляторе занимается семантический анализатор – специально для этого раз­работанная часть компилятора.

Далее, говоря о грамматиках языков программирования, будем иметь в виду только правила построения синтаксических конструкций языка. Однако следует помнить, что грамматика любого языка программирования в общем случае не ог­раничивается только этими правилами.

Язык, заданный грамматикой G, обозначается как L(G).

Две грамматики G и G’ называются эквивалентными, если они определяют один и тот же язык: L(G) = L(G’). Две грамматики G и G’ называются почти эквива­лентными, если заданные ими языки различаются не более чем на пустую цепочку символов: L(G){}=L(G’){}.

 

1.2.2. Формальное определение грамматики. Форма
Бэкуса–Наура

 

Для полного формального определения грамматики кроме правил порождения цепочек языка необходимо задать также алфавит языка.

Формально грамматика G определяется как четверка G(VT,VN,P,S), где:

 VT – множество терминальных символов;

 VN – множество нетерминальных символов: VNVT = ;

 Р – множество правил (продукций) грамматики вида αβ, где αV+, βV*;

 S – целевой (начальный) символ грамматики SVN.

Множество V = VNVT называют полным алфавитом грамматики G.

Рассмотрим множества VN и VT. Множество терминальных символов VT содер­жит символы, которые входят в алфавит языка, порождаемого грамматикой. Как правило, символы из множества VT встречаются только в цепочках правых час­тей правил, если же они встречаются в цепочке левой части правила, то обязаны быть и в цепочке правой его части. Множество нетерминальных символов VN содержит символы, которые определяют слова, понятия, конструкции языка. Каж­дый символ этого множества может встречаться в цепочках как левой, так и пра­вой частей правил грамматики, но он обязан хотя бы один раз быть в левой час­ти хотя бы одного правила. Правила грамматики строятся так, чтобы в левой части каждого правила был хотя бы один нетерминальный символ.

Эти два множества не пересекаются: каждый символ может быть либо терми­нальным, либо нетерминальным. Ни один символ в алфавите грамматики не может быть нетерминальным и терминальным одновременно. Целевой символ грамматики – это всегда нетерминальный символ.

Во множестве правил грамматики может быть несколько правил, имеющих оди­наковые правые части, вида: αβ1, αβ2,... αβn. Тогда эти правила объединя­ют вместе и записывают в виде: αβ1|β2|…|βn. Одной строке в такой записи соот­ветствует сразу n правил.

Такую форму записи правил грамматики называют формой Бэкуса–Наура. Форма Бэкуса–Наура предусматривает, как правило, также, что нетерминальные сим­волы берутся в угловые скобки: < >. Иногда знак “” в правилах грамматики заменяют на знак “::=”, но это всего лишь незначительные модификации формы записи, не влияющие на ее суть.

Ниже приведен пример грамматики для целых десятичных чисел со знаком:

G({0,1,2,3,4,5,6,7,8,9,–,+},{<число>,<чс>,<цифра>},Р,<число>)

Р:

<число>  <чс> | +<чс> | –<чс>

<чс>  <цифра> | <чс><цифра>

<цифра>  0|1|2|3|4|5|6|7|8|9

Рассмотрим составляющие элементы грамматики G:

 множество терминальных символов VT содержит двенадцать элементов: де­сять десятичных цифр и два знака;

 множество нетерминальных символов VN содержит три элемента: символы <число>, <чс> и <цифра>;

 множество правил содержит 15 правил, которые записаны в три строки (то есть имеются только три различных правых части правил);

 целевым символом грамматики является символ <число>.

Следует отметить, что символ <чс> – это бессмысленное сочетание букв русско­го языка, но это обычный нетерминальный символ грамматики, такой же, как и два других. Названия нетерминальных символов не обязаны быть осмысленны­ми, это сделано просто для удобства понимания правил грамматики человеком. В принципе в любой грамматике можно полностью изменить имена всех нетерминальных символов, не меняя при этом языка, заданного грамматикой, – точно также, например, в программе на языке Pascal можно изменить имена идентифи­каторов, и при этом не изменится смысл программы.

Для терминальных символов это неверно. Набор терминальных символов всегда строго соответствует алфавиту языка, определяемого грамматикой.

Вот, например, та же самая грамматика для целых десятичных чисел со знаком, в которой нетерминальные символы обозначены большими латинскими буквами (далее это будет часто применяться в примерах):

G’({0,1,2,3,4,5,6,7,8,9,–,+},{S,T,F},P,S)

Р:

S  Т | +Т | – Т

Т  F | TF

F  0|1|2|3|4|5|6|7|8|9

Здесь изменилось только множество нетерминальных символов. Теперь VN={S,T,F}. Язык, заданный грамматикой, не изменился – грамматики G и G’ эк­вивалентны.