Восходящие анализаторы
Таблица LALR-анализатора для грамматики G1
Теперь можно построить таблицу LR-анализатора:
State | action | goto | |||
---|---|---|---|---|---|
a | b | $ | S | A | |
0 | s3 | s4 | 1 | 2 | |
1 | accept | ||||
2 | s6 | s7 | 5 | ||
3 | s3 | s4 | 8 | ||
4 | r3 | r3 | |||
5 | r1 | ||||
6 | s6 | s7 | 9 | ||
8 | r2 | r2 | |||
9 | r2 |
Нетрудно заметить, что пары состояний 3 и 6, 4 и 7, 8 и 9 различаются только вторыми компонентами, определяющих их ситуаций. Поэтому мы можем "склеить" эти пары. В результате получится таблица LALR-анализатора:
State | action | goto | |||
---|---|---|---|---|---|
a | b | $ | S | A | |
0 | s36 | s47 | 1 | 2 | |
1 | accept | ||||
2 | s36 | s47 | 5 | ||
36 | s36 | s47 | 89 | ||
47 | r3 | r3 | r3 | ||
5 | r1 | ||||
89 | r2 | r2 | r2 |
Пример LR(1)-грамматики
Таким образом, LALR анализатор имеет значительное преимущество в размере таблиц по сравнению с LR. Однако, существуют грамматики, которые можно обработать LR анализатором, но нельзя LALR анализатором. LALR анализатор будет считать их неоднозначными, а LR анализатор не будет.
S -> aAd S -> bBd S -> aBe S -> bAe A -> c B -> c
не является LALR грамматикой, поскольку для входной цепочки ac мы можем выполнить свертку либо по правилу A -> c (если текущий входной символ d ) либо по правилу B -> c (если текущий входной символ e ).
Однако на практике большинство таких неоднозначностей можно устранить. Перейдем к рассмотрению различных возможных неоднозначностей и методов их устранения.
Неоднозначные грамматики. Конфликты "перенос-свертка"
Вопрос неоднозначности становится особенно важным в процессе построения управляющей таблицы анализатора LR(k)-языка, так как неоднозначность грамматики приводит к конфликтам при построении таблицы.
Рассмотрим сначала конфликты типа перенос-свертка ( shift/reduce ). Конфликты данного типа возникают, когда в процессе работы анализатора возникает выбор между переносом текущего символа на вершину стека и сверткой последовательности, расположенной на вершине стека.
Пример.Пусть дана грамматика G1, имеющая следующий набор правил:
(1) | stmt | -> | if expr then stmt |
(2) | stmt | -> | if expr then stmt else stmt |
(3) | stmt | -> | other |
(1) | stmt | -> | if expr then stmt |
(2) | stmt | -> | if expr then stmt else stmt |
(3) | stmt | -> | other |
, где other мы используем для обозначения других операторов.
На следующем слайде рассмотрим, что происходит при анализе следующей входной цепочки:
if E1 then if E2 then S1 else S2.