2015-11-29 5 views
0

Я работаю над проектом синтаксического анализа, который использует адаптацию этой грамматики для регулярных выражений 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>, и мы по-прежнему получаем это, если мы отменим порядок. Я что-то упускаю, или просто отменяет порядок достижения той же цели, что и левый фактор в этой ситуации?

ответ

0

Проблема вы пытаетесь исправить что

items → item 
items → item items 

не слева учтены; обе постановки начинаются с item.

предложил Ваше затруднительное

items → item 
items → items item 

не помогает (независимо от начала item все еще может начать либо производство items), но что более важно, он остается рекурсией, которая Verboten для LL грамматик ,

В принципе, «новый нетерминал» является правильным решением, но в метод рекурсивного спуска, вы, вероятно, сделать что-то вроде этого:

def items(): 
    list = [ item() ] 
    while couldStart(item, lookahead): 
    list.append(item()) 
    return list 
+0

аха, слева рекурсии. Мне может понадобиться пыль от книги с красным драконом ... Я забыл много этого. Спасибо за это. Вы предполагаете, что в реальной реализации рекурсивного спуска эту проблему можно обойти без левого факторизации грамматики? Я не вижу решение, которое вы предлагаете, с этим фрагментом python. –

+0

@ErikNyquist: Возможно, псевдо-питонный код мало помогает. Дело в том, что практический парсер RD использует петли, а не рекурсию, и можно реализовать «X +» как цикл: сначала распознать «X», а затем повторить, пока следующий токен может запустить «X». В C я бы написал это как цикл «do ... while»; может быть, это было бы яснее. 'X *' также может быть распознан с помощью цикла; единственное отличие состоит в том, что тест приходит в начале, а не в конце. – rici

+0

OK Я тебя. Я действительно буду избегать рекурсии, поэтому я скоро доберусь до точки, где я должен это реализовать, и я ценю совет. Мне не удалось найти какие-либо комнаты IRC, связанные с дизайном компилятора или даже с меньшими подзонами (например, LL-парсерами, BNF-грамматиками). Знаете ли вы о каких-либо хороших форумах для обсуждения этих вещей ... помимо stackoverflow? –