Не удается получить LL(1) форму грамматики для синтаксического анализатора рекурсивного спуска

#parsing #compiler-construction #context-free-grammar #recursive-descent #ambiguous-grammar

#синтаксический анализ #компилятор-конструкция #контекстно-свободная грамматика #рекурсивный спуск #неоднозначная грамматика

Вопрос:

У меня есть грамматика:

 S -> bU | ad | d
U -> Ufab | VSc | bS
V -> fad | f | Ua
 

Чтобы сконструировать анализатор рекурсивного спуска, мне нужна форма LL(1).
Лучшее, что у меня есть, это:

 S -> bU | ad | d
U -> fY | bSX
Y -> adScX | ScX
X -> fabX | aScX | ε
 

Удалил левые рекурсии и выполнил некоторый левый факторинг, но я застрял.
Пытался в течение нескольких часов, но у меня ничего не получается…

Например, допустимой строкой являются:

  • bbdfabadc ббдфабадк
  • bbdfabfabfabfab
  • bfadadcfabfab
  • bbadaadc
  • bfbbdfabc

Очевидно, что моя грамматическая форма неоднозначна для некоторых, поэтому я не могу создать анализатор рекурсивного спуска…

Из ответа:

 S -> bU | ad | d
U -> fYZ | bSZ
X -> fab | aSc
Y -> adA | bUc | dc
Z -> ε | XZ
A -> Sc | c
 

Все еще не LL(1). Первое и последующее для Z не являются непересекающимися.

Ответ №1:

Как правило, чтобы создать грамматический LL (1), вам нужно будет многократно использовать левый фактор и удалять левую рекурсию до тех пор, пока вам не удастся избавиться от всех вещей, отличных от LL. Что вы сделаете в первую очередь, зависит от грамматики, но в этом случае вам нужно начать с факторинга слева

К левому фактору относится правило

 U -> Ufab | VSc | bS
 

вам нужно сначала заменить V, давая

 U -> Ufab | fadSc | fSc | UaSc | bS
 

который вы затем оставили включенным в

 U -> UX | fY | bS
X -> fab | aSc
Y -> adSc | Sc
 

теперь U достаточно прост, чтобы вы могли устранить левую рекурсию напрямую:

 U -> fYZ | bSZ
Z -> ε | XZ
 

предоставляя вам

 S -> bU | ad | d
U -> fYZ | bSZ
X -> fab | aSc
Y -> adSc | Sc
Z -> ε | XZ
 

Теперь у вас все еще есть проблема с факторингом слева с Y, поэтому вам нужно заменить S:

 Y -> adSc | bUc | adc | dc
 

на который вы оставили фактор

 Y -> adA | bUc | dc
A -> Sc | c
 

предоставление почти LL (1) грамматики:

 S -> bU | ad | d
U -> fYZ | bSZ
X -> fab | aSc
Y -> adA | bUc | dc
Z -> ε | XZ
A -> Sc | c
 

но теперь все застряло, поскольку правило эпсилона для Z означает, что нам нужно, чтобы FIRST (X) и FOLLOW (Z) были непересекающимися (чтобы выбрать между двумя правилами Z). Обычно это указывает на язык, отличный от языка LL, поскольку существует некоторый конечный контекст, который может быть связан с более чем одним правилом (через S -> bU -> bbSZ -> bbbUZ -> bbbbSZZ цепочку exapansion — конечные Zs могут быть распознаны, но либо могут быть пустыми). Часто вы все еще можете распознать этот язык с помощью простого синтаксического анализатора рекурсивного спуска (или таблицы состояний в стиле LL), просто разрешив двусмысленность / конфликт Z в пользу неэпилонского правила.

Комментарии:

1. Z -> ε | XZ Разве здесь не первое и последующее столкновение? FIRST(Z) -> f, a, ε FOLLOW(Z) -> f, a, c, $