Я работаю над проектом синтаксического анализа, который использует адаптацию этой грамматики для регулярных выражений Perl http://www.cs.sfu.ca/~cameron/Teaching/384/99-3/regexp-plg.html. Я упростил эту грамматику для своих собственных целей, например, так (обратите внимание, что, поскольку «|» является лексема, я вместо того, чтобы с помощью запятой «» так раздельные постановки на данный нетерминал):Ищете совет по составлению этой грамматики BNF, подходящей для анализа LL (1) (левый факторинг)
<RE> := <union>, <simple>
<union> := <RE> | <simple>
<simple> := <concat>, <basic>
<concat> := <simple><basic>
<basic> := <zero>, <one>, <onezero>, <elem>
<zero> := <elem>*
<one> := <elem>+
<onezero> := <elem>?
<elem> := <group>, <any>, <literal>, <class>
<group> := (<RE>)
<class> := [<items>]
<items> := <item>, <item><items>
<item> := <range>, <literal>
I хотите написать парсер LL (1) для обработки этой грамматики, а для анализатора LL (1) производные для <items>
имеют некоторую двусмысленность. Чтобы это исправить, я бы оставил-фактор их, добавив новый нетерминал <X>
, например, так:
<items> := <item><X>
<X> := <items>, epsilon
Но что мне интересно, я мог просто перевернуть вокруг порядка второго производства в <items>
, как это:
<items> := <item>, <items><item>
и не добавлять новые нетерминальные? Похоже, что это ничего не сломает, ведь вся цель этой продукции - разрешить любое переменное число последовательных символов <item>
, и мы по-прежнему получаем это, если мы отменим порядок. Я что-то упускаю, или просто отменяет порядок достижения той же цели, что и левый фактор в этой ситуации?
аха, слева рекурсии. Мне может понадобиться пыль от книги с красным драконом ... Я забыл много этого. Спасибо за это. Вы предполагаете, что в реальной реализации рекурсивного спуска эту проблему можно обойти без левого факторизации грамматики? Я не вижу решение, которое вы предлагаете, с этим фрагментом python. –
@ErikNyquist: Возможно, псевдо-питонный код мало помогает. Дело в том, что практический парсер RD использует петли, а не рекурсию, и можно реализовать «X +» как цикл: сначала распознать «X», а затем повторить, пока следующий токен может запустить «X». В C я бы написал это как цикл «do ... while»; может быть, это было бы яснее. 'X *' также может быть распознан с помощью цикла; единственное отличие состоит в том, что тест приходит в начале, а не в конце. – rici
OK Я тебя. Я действительно буду избегать рекурсии, поэтому я скоро доберусь до точки, где я должен это реализовать, и я ценю совет. Мне не удалось найти какие-либо комнаты IRC, связанные с дизайном компилятора или даже с меньшими подзонами (например, LL-парсерами, BNF-грамматиками). Знаете ли вы о каких-либо хороших форумах для обсуждения этих вещей ... помимо stackoverflow? –