Сочетание лексера со многими парсерами
Я знаю типичную конфигурацию лексера и парсера, где лексер читает исходный код и генерирует токены, которые затем направляются парсеру, и парсер использует их в качестве терминальных символов в своих грамматических произведениях. В типичном парсере с рекурсивным спуском вы начинаете с вызова некоторой функции верхнего уровня, представляющей начальный нетерминал, и эта функция вызывает других и читает токен токеном из лексера.
Но что, если мне понадобятся два разных парсера поверх одного и того же лексера?
Я имею в виду, что они оба читают из одного и того же места, потому что я не хочу читать один и тот же источник несколько раз, то есть не допускается многократное прохождение, чтобы избежать ненужного дублирования работы в лексере. Я просто хочу, чтобы, когда следующий токен в последовательности только что был сгенерирован, оба парсера использовали его одновременно.
Но я могу вызвать только одну функцию верхнего уровня в одном из этих парсеров; не могу вызвать оба одновременно:/
Есть ли способ запустить эти парсеры в каком-то пошаговом режиме? То есть, когда у меня есть новый токен, я хочу передать его обоим парсерам один за другим, но только для того, чтобы продвигать их по одному токену, обновлять их внутренние состояния и структуры данных, насколько это возможно, и немедленно возвращать их ждать другого токена.
Я никогда не видел подобной конфигурации никогда раньше. Можно ли вообще так построить парсер? Существуют ли материалы о том, как этот вид парсера может быть структурирован в коде? У него есть имя?
РЕДАКТИРОВАТЬ 1: Я не хочу использовать какой-либо инструмент генератора синтаксического анализатора, но сам пишу код, потому что я хочу узнать, как такого рода вещи работают внутри.
1 ответ
Вы описали типичный поток парсера. Он вызывается один раз и принимает управление, пока все его входные данные не будут полностью проанализированы. Парсер сам вызывает lexer для получения следующего токена. С другой стороны, push-парсер вызывается каждый раз, когда становится доступным новый токен. Таким образом, вы можете вызывать несколько парсеров для каждого нового токена. Классический Зубр может быть использован в режиме push (подробности есть). Генератор парсеров Lemon генерирует парсеры.