# Найти все <tex>\varepsilon</tex>-правила. Составить множество, состоящее из нетерминалов, входящих в левые части таких правил.
# Перебираем правила грамматики <tex>G</tex>. Если существует найдено правило <tex>A \rightarrow C_1C_2...C_k</tex>, для которого верно, что каждый <tex>C_i</tex> принадлежит множеству, то добавить <tex>A</tex> в множество.
# Если на шаге 2 множество изменилось, то повторить шаг 2.
|statement = Описанный выше алгоритм находит все <tex>\varepsilon</tex>-порождающие нетерминалы грамматики <tex>G</tex>.
|proof =
Индукция по длине кратчайшего порождения <tex>A \Rightarrow^* \varepsilon</tex>. Если длина кратчайшего порождения равна <tex>p</tex>, то в множестве <tex>\varepsilon</tex>-порождающих нетерминалов содержатся все нетерминалы, из которых можно вывести пустое слово <tex>\varepsilon</tex> за менее, чем <tex>p</tex> шагов.
'''База.''' Для доказательства корректности алгоритма достаточно показать, что если множество <tex>A \Rightarrow varepsilon</tex>-порождающих нетерминалов на очередной итерации алгоритма не изменялось, то алгоритм нашел все <tex>\varepsilon</tex>-порождающие нетерминалы.<br/>Для простоты доказательства можно считать, то есть что на <tex>k</tex>-й итерации алгоритма в грамматике имеется правило множество <tex>\varepsilon</tex>-порождающих нетерминалов добавляются только нетерминалы <tex>A : A \rightarrowRightarrow^* \varepsilon</tex>за <tex>k</tex> шагов. Следовательно, Пусть алгоритм сделал <tex>An</tex> будет добавлен в итераций и множество <tex>\varepsilon</tex>-порождающих нетерминалов на первом шаге алгоритмане изменилось. '''ПереходТогда множество <tex>\varepsilon</tex>-порождающи нетерминалов содержит все нетерминалы <tex>A : A \Rightarrow^* \varepsilon</tex> не более, чем за <tex>n - 1</tex> шагов.''' Пусть существуют нетерминалы такие, что они является <tex>A \varepsilon</tex>-порождающими, но не были найдены алгоритмом. Выберем из этих нетерминалов нетерминал <tex>B : B \Rightarrow^* \varepsilon</tex> за минимальное количество шагов.Тогда <tex>B \Rightarrow^* \varepsilon</tex> ровно за <tex>n</tex> шагов, так как если из нетерминала выводилась пустая строка за меньшее количество шагов, то нетерминал уже принадлежал бы множеству <tex>\varepsilon</tex>-порождающих нетерминалов, а если — за большее количество шагов, то он не являлся бы <tex>\varepsilon</tex>-порождающим. Тогда первый шаг порождения выполняется по правилу Следовательно, в грамматике есть правило <tex>A B \rightarrow C_1C_2...C_k</tex>, где каждый <tex>C_i \Rightarrow^* \varepsilon</tex> за менее, чем <tex>n</tex> шагов. По индукционному предположению каждый нетерминал Следовательно, на <tex>C_i</tex> уже содержится в множестве <tex>\varepsilonn</tex>-порождающих нетерминалов. Тогда нетерминал й итерации алгоритм должен был добавить <tex>AB</tex> будет добавлен в множество <tex>\varepsilon</tex>-порождающих нетерминалов на шаге 2. Следовательно, алгоритм Получили противоречие. Алгоритм находит все <tex>\varepsilon</tex>-порождающие нетерминалы.
}}