На каждом шаге анализа, принимается решение о действии анализатора. Возможные действия:
Два типа конфликтов:
Чаще всего, конфликты свидетельствуют о неоднозначности грамматики. Реже – о том, что конкретный анализатор (использующий \(k\) символов предпросмотра) недостаточно мощный для данной грамматики.
Пусть \(I\) – множество пунктов грамматики \(G\). Тогда \(I^+\) – замыкание множества пунктов, соответствующее правилу:
Если \((A \to α . B β) \in I^+,\) и \(\exists (B \to γ),\) то \((B \to . γ) \in I^+\).
Любой LR-анализатор управляется:
a = getNextToken();
while(true) {
s = stack.top();
if(ACTION[s, a] = перенос) {
stack.push(GOTO[s, a]);
a = getNextToken();
} else if (ACTION[s, a] = свёртка A -> β) {
for (i in 1…|β|) stack.pop();
t = stack.top();
stack.push(GOTO[t, A]);
print("A -> β");
} else if (ACTION[s, a] = принятие) {
break;
} else { // ACTION[s, a] = ошибка
reportError();
}
}
GOTO
, содержащую переходы по нетерминалам, а информацию о новом состоянии GOTO[s, a]
при переносе помещают прямо в таблицу ACTION
:GOTO
, содержащую переходы по нетерминалам, а информацию о новом состоянии GOTO[s, a]
при переносе помещают прямо в таблицу ACTION
:a = getNextToken();
while(true) {
s = stack.top();
if(ACTION[s, a] = перенос) {
stack.push(GOTO[s, a]);
a = getNextToken();
} else if (ACTION[s, a] = свёртка A -> β) {
for (i in 1…|β|) stack.pop();
t = stack.top();
stack.push(GOTO[t, A]);
print("A -> β");
} else if (ACTION[s, a] = принятие) {
break;
} else { // ACTION[s, a] = ошибка
reportError();
}
}
a = getNextToken();
while(true) {
s = stack.top();
if(ACTION[s, a] = перенос j) {
stack.push(j); // j = GOTO[s, a]
a = getNextToken();
} else if (ACTION[s, a] = свёртка A -> β) {
for (i in 1…|β|) stack.pop();
t = stack.top();
stack.push(GOTO[t, A]);
print("A -> β");
} else if (ACTION[s, a] = принятие) {
break;
} else { // ACTION[s, a] = ошибка
reportError();
}
}
Таблица \(\mathrm{ACTION}[s, t]\) для “чистого” LR(0)-анализа строится тривиально:
Отметим, что \(\mathrm{ACTION}[s, t]\) для свёртки не зависит от \(t\). Следовательно, неизбежны конфликты.
Рассмотрим грамматику \[\begin{align} E & \to E + T | T \\ T & \to T * F | F \\ F & \to ( E ) | val \\ \end{align}\]
Расширим эту грамматику стартовым правилом: \[\begin{align} S & \to E \;\$ \\ E & \to E + T | T \\ T & \to T * F | F \\ F & \to ( E ) | val \\ \end{align}\]
Построим LR(0)-автомат для этой грамматики. Начальное состояние: \[\begin{array}{rll} I_0 = \{S \to .E \;\$\}^+ = \{ & S\to .E \;\$, \\ & E\to .E+T, \\ & E\to .T, \\ & T \to .T*F, \\ & T \to .F, \\ & F \to .(E), \\ & F \to .val \} \end{array}\]
\(\begin{align}I_0 & = \{ \\ & S\to .E \;\$, \\ & E\to .E+T, \\ & E\to .T, \\ & T \to .T*F, \\ & T \to .F, \\ & F \to .(E), \\ & F \to .val \\ \}\end{align}\) \( \mathrm{GOTO}(I_{0}, E) = I_{1} = \{\\ \begin{array}{l} S\to E.\;\$ \\ E\to E.+T \\ \hline \end{array}\\ \} \\ \) \( \mathrm{GOTO}(I_{0}, T) = I_{2} = \{\\ \begin{array}{l} E\to T. \\ T\to T.*F \\ \hline \end{array}\\ \} \\ \) \( \mathrm{GOTO}(I_{0}, F) = I_{3} = \{\\ \begin{array}{l} T \to F. \\ \hline \end{array}\\ \} \\ \)
\( \mathrm{GOTO}(I_{0}, val) = I_{5} = \{\\ \begin{array}{l} F \to val. \\ \hline \end{array}\\ \} \\ \) \( \mathrm{GOTO}(I_{0}, () = I_{4} = \{\\ \begin{array}{l} F \to (.E) \\ \hline E\to .E+T \\ E\to .T \\ T \to .T*F \\ T \to .F \\ F \to .(E) \\ F \to .val \end{array}\\ \} \\ \) \( \mathrm{GOTO}(I_{1}, +) = I_{6} = \{\\ \begin{array}{l} E \to E+.T \\ \hline T \to .T*F \\ T \to .F \\ F \to .(E) \\ F \to .val \\ \end{array}\\ \} \\ \)
\( \mathrm{GOTO}(I_{2}, *) = I_{7} = \{\\ \begin{array}{l} T\to T*.F \\ \hline F \to .(E) \\ F \to .val \\ \end{array}\\ \} \\ \) \( \mathrm{GOTO}(I_{4}, E) = I_{8} = \{\\ \begin{array}{l} F \to (E.) \\ E\to E.+T \\ \hline \end{array}\\ \} \\ \) \( \mathrm{GOTO}(I_{4}, T) = I_{2} \\ \) \( \mathrm{GOTO}(I_{4}, F) = I_{3} \\ \) \( \mathrm{GOTO}(I_{4}, () = I_{4} \\ \) \( \mathrm{GOTO}(I_{4}, val) = I_{5} \\ \) \( \mathrm{GOTO}(I_{6}, T) = I_{9} = \{\\ \begin{array}{l} E \to E+T. \\ T \to T.*F \\ \hline \end{array}\\ \} \\ \)
\( \mathrm{GOTO}(I_{6}, F) = I_{3} \\ \) \( \mathrm{GOTO}(I_{6}, () = I_{4} \\ \) \( \mathrm{GOTO}(I_{6}, val) = I_{5} \\ \) \( \mathrm{GOTO}(I_{7}, F) = I_{10} = \{\\ \begin{array}{l} T \to T*F. \\ \hline \end{array}\\ \} \\ \) \( \mathrm{GOTO}(I_{7}, () = I_{4} \\ \) \( \mathrm{GOTO}(I_{7}, val) = I_{5} \\ \) \( \mathrm{GOTO}(I_{8}, )) = I_{11} = \{\\ \begin{array}{l} F \to (E). \\ \hline \end{array}\\ \} \\ \) \( \mathrm{GOTO}(I_{8}, +) = I_{6} \\ \) \( \mathrm{GOTO}(I_{9}, *) = I_{7} \\ \)
Вычислим FOLLOW
для всех нетерминальных символов грамматики:
Пронумеруем продукции: \[\begin{align} E & \to E + T & (1) \\ E & \to T & (2)\\ T & \to T * F & (3)\\ T & \to F & (4)\\ F & \to ( E ) & (5) \\ F & \to val & (6)\\ \end{align}\]
ACTION | + | * | ( | ) | val | $ | GOTO | E | T | F |
---|---|---|---|---|---|---|---|---|---|---|
0 | s4 | s5 | 0 | 1 | 2 | 3 | ||||
1 | s6 | acc | 1 | |||||||
2 | r2 | s7 | r2 | r2 | 2 | |||||
3 | r4 | r4 | r4 | r4 | 3 | |||||
4 | s4 | s5 | 4 | 8 | 2 | 3 | ||||
5 | r6 | r6 | r6 | r6 | 5 | |||||
6 | s4 | s5 | 6 | 9 | 3 | |||||
7 | s4 | s5 | 7 | 10 | ||||||
8 | s6 | s11 | 8 | |||||||
9 | r1 | s7 | r1 | r1 | 9 | |||||
10 | r3 | r3 | r3 | r3 | 10 | |||||
11 | r5 | r5 | r5 | r5 | 11 |