Удаление левой рекурсии

следующая грамматика оставила рекурсию

E= E+T|T
T= T*F|F
F= a|b|c

Как удалить его? Существует ли какая-либо общая процедура для этого?

4 ответов


Да, существует общая процедура, см. например Википедия.

E = TE'
E'= (e) | +TE'
T = FT'
T'= (e) | *FT'
F = a | b | c

стоит отметить, что это изменяет ассоциативность + и * слева направо. То есть, где раньше a + b + c был трактован как (a + b) + c, теперь он разбирается как a + (b + c).

это не проблема для сложения и умножения, но это будет проблемой для вычитания и деления, например.

статья Википедии имеет более подробную информацию о Left-процедура удаления рекурсии и ее тонкости.


общая процедура находится в Википедия, например. Я продемонстрирую для E = E+T|T:

E является леворекурсивным не-терминалом. +T - ненулевая последовательность (Альфа). T - это последовательность, которая не начинается с E (beta).

создаем новый нетерминал для "отдыха", т. е. ненулевая последовательность. Это обрабатывает рекурсию.

E' = epsilon|+TE'

и мы модифицируем исходное правило для использования нового нетерминального для обработки рекурсии.

E = TE'


как указывали другие, существует общая процедура замены левой рекурсии правой рекурсией. Другие ответы хорошо показывают, как использовать эту общую процедуру для удаления левой рекурсии в данной грамматике.

вот решение, которое реструктурирует данную грамматику таким образом, который специфичен для этой грамматики.

E= T+E|T
T= F*T|F
F= a|b|c

производства

E = E+T
  | T
T = T*F
  | F
F = a|b|c

идет

E= T ('+' T)*
T= F ('*' F)*
F= a|b|c

для поддержания той же обработки, где кулак e дизъюнкт обрабатывается с A(E,T). новая версия использует:

ret = T1;
while(set.more()) ret = A(ret, set.pop_front().T);