Удаление левой рекурсии
следующая грамматика оставила рекурсию
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);