Опубликован: 08.04.2009 | Доступ: свободный | Студентов: 485 / 0 | Длительность: 17:26:00
Специальности: Программист
Лекция 15:

Контекстно-свободные грамматики

Ключевые слова: контекстно-свободная грамматика, 1-грамматика, алфавит, символ, слово, символ алфавита, терминальный символ, нетерминальный символ, начальный символ, правило, префикс, вывод, ПО, выводимое слово, язык, алгоритм, Пустое слово, стек, множества, TE, свойства множества, представление, выражение, умножение, множитель, полином, эффективность алгоритма, нетерминал, информация, переменная, инвариант, конкатенация, 'quotes', функция, специальный символ, EOI, end, input, move, истина, значение переменной, корректность, объединение, PQ, Паскаль, forwarder, доказательство, рекурсия, завершение работы, длина, эквивалентность, рекурсивный вызов, true, итерация, цикла, инвариант цикла, фигурные скобки, альтернативные, LL(1)-разбор, Левый вывод, индукция, определение, множество направляющих терминалов, LL(1)-грамматика, леворекурсивная грамматика, LL, терминал, очередной символ

15.1. Общий алгоритм разбора

Чтобы определить то, что называют контекстно-свободной грамматикой (КС-грамматикой), надо:

  • указать конечное множество A, называемое алфавитом ; его элементы называют символами ; конечные последовательности символов называют словами (в данном алфавите);
  • разделить все символы алфавита A на две группы: терминальные ("окончательные") и нетерминальные ("промежуточные");
  • выбрать среди нетерминальных символов один, называемый начальным ;
  • указать конечное число правил грамматики, каждое из которых должно иметь вид K \to X, где K - некоторый нетерминальный символ, а X - слово (в него могут входить и терминальные, и нетерминальные символы).

Пусть фиксирована КС-грамматика (мы часто будем опускать префикс "КС-", так как других грамматик у нас не будет). Выводом в этой грамматике называется последовательность слов X_0, X_1,\ldots,X_n, в которой X_0 состоит из одного символа, и этот символ - начальный, а X_{i+1} получается из X_i заменой некоторого нетерминального символа K на слово X по одному из правил грамматики. Слово, составленное из терминальных символов, называется выводимым, если существует вывод, который им кончается. Множество всех выводимых слов (из терминальных символов) называется языком, порождаемым данной грамматикой}.

В этой и следующей лекции нас будет интересовать такой вопрос: дана КС-грамматика; построить алгоритм, который по любому слову проверяет, выводимо ли оно в этой грамматике.

Пример 1. Алфавит:

\begin{center}\ttfamily
( ) [ ] E
\end{center}
(четыре терминальных символа и один нетерминальный символ E ). Начальный символ: E. Правила:
\begin{align*}
      \hbox{\texttt{E}} & \to  \hbox{\texttt{(E)}}\\
      \hbox{\texttt{E}} & \to  \hbox{\texttt{[E]}}\\
      \hbox{\texttt{E}} & \to  \hbox{\texttt{EE}}\\
      \hbox{\texttt{E}} & \to
\end{align*}
(в последнем правиле справа стоит пустое слово).

Примеры выводимых слов:

\begin{center}\ttfamily
\hspace*{1em}  \textrm{(пустое слово)}\\
                ()\\
                ([$\,$])\\
                ()[([$\,$])]\\
\leavevmode  \hbox{\texttt{[()[$\,$]()[$\,$]]}}
\end{center}
Примеры невыводимых слов:
\begin{center}\ttfamily
(\\
)(\\
(]\\
([)]
\end{center}
Эта грамматика встречалась в "разделе 6.1." (где выводимость в ней проверялась с помощью стека).

Пример 2. Другая грамматика, порождающая тот же язык:

Алфавит: ( ) [ ] T E

Правила:

\begin{align*}
 \hbox{\texttt{E}} &\to\\ \hbox{\texttt{E}}  &\to\hbox{\texttt{TE}}\\ \hbox{\texttt{T}}  &\to\hbox{\texttt{(E)}}\\ \hbox{\texttt{T}}  &\to\hbox{\texttt{[E]}}
\end{align*}
Начальным символом во всех приводимых далее примерах будем считать символ, стоящий в левой части первого правила (в данном случае это символ E ), не оговаривая этого особо.

Для каждого нетерминального символа можно рассмотреть множество всех слов из терминальных символов, которые из него выводятся (аналогично тому, как это сделано для начального символа в определении выводимости в грамматике). Каждое правило грамматики можно рассматривать как свойство этих множеств. Покажем это на примере только что приведенной грамматики. Пусть T и E - множества слов (из скобок), выводимых из нетерминалов T и E соответственно. Тогда правилам грамматики соответствуют такие свойства:

E \to E содержит пустое слово
E->TE если слово A принадлежит T, а слово B принадлежит E, то слово AB принадлежит E
T->[E] если A принадлежит E, то слово [A] принадлежит T
T->(E) если A принадлежит E, то слово (A) принадлежит T

Сформулированные свойства множеств E, T не определяют эти множества однозначно (например, они остаются верными, если в качестве E и T взять множество всех слов). Однако можно доказать, что множества, задаваемые грамматикой, являются минимальными среди удовлетворяющих этим условиям.

15.1.1. Сформулировать точно и доказать это утверждение для произвольной контекстно-свободной грамматики.

15.1.2. Построить грамматику, в которой выводимы слова

(а) 00..0011..11 (число нулей равно числу единиц);

(б) 00..0011..11 (число нулей вдвое больше числа единиц);

(в) 00..0011..11 (число нулей больше числа единиц);

(и только они).

15.1.3. Доказать, что не существует КС-грамматики, в которой были бы выводимы слова вида 00..0011..1122..22, в которых числа нулей, единиц и двоек равны, и только они.

Указание. Доказать следующую лемму о произвольной КС-грамматике: для любого достаточно длинного слова F, выводимого в этой грамматике, существует такое его представление в виде ABCDE, что любое слово вида AB\ldots BCD\ldots DE, где B и D повторены одинаковое число раз, также выводимо в этой грамматике. (Это можно установить, найдя нетерминальный символ, оказывающийся своим собственным "наследником" в процессе вывода.)

Нетерминальный символ можно рассматривать как "родовое имя" для выводимых из него слов. В следующем примере для наглядности в качестве нетерминальных символов использованы фрагменты русских слов, заключенные в угловые скобки. (С точки зрения грамматики каждый такой фрагмент - один символ!)

Пример 3. Алфавит:

\begin{flushleft}
\qquad\qquad терминалы: \quad  \texttt{+ * ( ) x}\\
\qquad\qquad нетерминалы: \quad \langle{выр}\rangle\ \langle{оствыр}\rangle\
   \langle{слаг}\rangle\  \langle{остслаг}\rangle\ \langle{множ}\rangle\\
\end{flushleft}
Правила:
\begin{align*}
    \langle{выр}\rangle    &\to\langle{слаг}\rangle\ \langle{оствыр}\rangle\\
    \langle{оствыр}\rangle &\to \hbox{\texttt{+}}\ \langle{выр}\rangle\\
    \langle{оствыр}\rangle &\to \\
    \langle{слаг}\rangle   &\to \langle{множ}\rangle\ \langle{остслаг}\rangle\\
    \langle{остслаг}\rangle &\to \hbox{\texttt{*}}\ \langle{слаг}\rangle\\
    \langle{остслаг}\rangle&\to \\
    \langle{множ}\rangle   &\to \hbox{\texttt{x}}\\
    \langle{множ}\rangle   &\to \hbox{\texttt{(}}\ \langle{выр}\rangle\ \hbox{\texttt{)}}
\end{align*}
Согласно этой грамматике, выражение \langle{выр}\rangle - это последовательность слагаемых \langle{слаг}\rangle, разделенных плюсами, слагаемое - это последовательность множителей \langle{множ}\rangle, разделенных звездочками (знаками умножения), а множитель - это либо буква x, либо выражение в скобках.