Вот комбинированный парсер, компоновщик NFA и интерпретатор NFA на одной странице Python. Надеюсь, я не испорчу удовольствие от выяснения этого для себя - вы можете подождать и продолжить взлом, прежде чем перейти по ссылке.
Это похоже на предложение Дейнста, но «назад». Как говорит deinst, вы можете заставить анализатор создавать NFA для каждого подвыражения регулярного выражения, а затем подключать их по ходу работы. Например, для (a|b)*c
сначала нужно проанализировать (a|b)*
, чтобы получить NFA # 1, затем проанализировать c
, чтобы получить NFA # 2, а затем завершить конечное состояние NFA # 1, изменив его на начальное состояние # 2. И так далее рекурсивно. Это обычный ответ.
Мой код вместо этого сначала создает тривиальный NFA с просто принимающим состоянием и ничего более. Затем он анализирует c
, расширяя NFA: теперь у нас есть NFA, который проверяет на c
, а затем принимает. Затем он рекурсивно анализирует (a|b)*
, продолжая расширять NFA. Контракт синтаксического анализатора, заданный строкой re
и NFA k
, состоит в том, чтобы проанализировать строку для получения результирующего NFA, который заканчивается в начале k
, когда re
совпадает. Этот подход избавляет от необходимости разбивать биты частичных NFA, чтобы соединить их вместе.