Нормализация структурных различий в грамматиках

Рассмотрим следующую грамматику:

S → A | B
A → xy
B → xyz

Это то, что я думаю, что парсер LR (0) будет делать с учетом ввода xyz:

    | xyz   → shift
  x | yz    → shift
 xy | z     → reduce
  A | z     → shift
 Az |       → fail

Если мое предположение верно, и мы изменили правило B следующим образом:

B → Az

теперь грамматика внезапно становится приемлемой парсером LR (0). Я предполагаю, что эта новая грамматика описывает тот же самый набор строк, что и первая грамматика в этом вопросе.

  • В чем разница между первой и второй грамматиками?
  • Как мы отделяем структурные различия в наших грамматиках от языка, который они описывают?
    • Через нормализацию?
    • Какая нормализация?

Для дальнейшего уточнения:

Я хочу описать язык для парсера, без структуры грамматики, играющей роль. Я хотел бы получить самое минимальное/фундаментальное описание набора строк. Для грамматик LR (k) я хотел бы свести к минимуму k.

Ответ 1

Я думаю, что ваш синтаксический анализатор LR(0) не является стандартным парсером:

Парсер LR (0) является парсером сдвига/уменьшения, который использует нулевые токены для определения того, какое действие нужно предпринять (следовательно, 0). Это означает, что в любой конфигурации анализатора парсер должен иметь однозначное действие для выбора - либо он сдвигает определенный символ, либо применяет конкретное сокращение. Если есть два или более вариантов, парсер терпит неудачу, и мы говорим, что грамматика не LR (0).

Итак, когда у вас есть:

S->A|B
A->xy
B->Az

или

S->A|B
A->xy
B->xyz

LR(0) никогда не будет проверять правило B, и для обоих из них он будет терпеть неудачу.

State0 - Clousure(S->°A):
   S->°A
   A->°xy

 Arcs:
  0 --> x --> 2
  0 --> A --> 1
-------------------------

State1 - Goto(State0,A):
   S->A°

 Arcs:
  1 --> $ --> Accept
-------------------------

State2 - Goto(State0,x):
   A->x°y

 Arcs:
  2 --> y --> 3
-------------------------

State3 - Goto(State2,y):
   A->xy°

 Arcs:
-------------------------

Но если у вас

I->S
S->A|B
A->xy
B->xyz                           or B->Az

Оба они будут принимать xyz, но в состояниях разности:

State0 - Clousure(I->°S):
   I->°S
   S->°A
   S->°B
   A->°xy                           A->°xy, $z
   B->°xyz                          B->°Az, $

 Arcs:
  0 --> x --> 4
  0 --> S --> 1
  0 --> A --> 2
  0 --> B --> 3
-------------------------

State1 - Goto(State0,S):
   I->S°

 Arcs:
  1 --> $ --> Accept
-------------------------

State2 - Goto(State0,A):
   S->A°                            S->A°, $ 
                                    B->A°z, $
 Arcs:                              2 --> z --> 5
-------------------------

State3 - Goto(State0,B):
   S->B°

 Arcs:
-------------------------

State4 - Goto(State0,x):
   A->x°y                            A->x°y, $z
   B->x°yz

 Arcs:
  4 --> y --> 5                     4 --> y --> 6
-------------------------

State5 - Goto(State4,y):            - Goto(State2,z):
   A->xy°                           B->Az°, $

 Arcs:
  5 --> z --> 6                     -<None>-
-------------------------

State6 - Goto(State5,z):            - Goto(State4,y)
   B->xyz°                          A->xy°, $z

 Arcs:
-------------------------

Вы можете видеть, что Goto Table и Action Table отличаются.

[B->xyz]                                  [B->Az]
  | Stack   | Input  | Action               | Stack   | Input  | Action
--+---------+--------+----------          --+---------+--------+----------
1 | 0       | xyz$   | Shift              1 | 0       | xyz$   | Shift 
2 | 0 4     | yz$    | Shift              2 | 0 4     | xy$    | Shift
3 | 0 4 5   | z$     | Shift              3 | 0 4 6   | z$     | Reduce A->xy
4 | 0 4 5 6 | $      | Reduce B->xyz      4 | 0 2     | z$     | Shift 
5 | 0 3     | $      | Reduce S->B        5 | 0 2 5   | $      | Reduce B->Az
6 | 0 1     | $      | Accept             6 | 0 3     | $      | Reduce S->B
                                          7 | 0 1     | $      | Accept

Просто, когда вы меняете B->xyz на B->Az, вы добавляете Action в свой LR Table, чтобы найти различия, которые вы можете проверить Action Table и Goto Table (Построение таблиц разбора LR (0))

  • Если у вас есть A->xy и B->xyz, тогда у вас есть две нижние дескрипторы [xy или xyz], но когда у вас есть B->Az, у вас есть только один нижний дескриптор [xy], может принимать дополнительные z.

  • Я думаю, что это связано с локальной оптимизацией -c = a + b; d = a + b → c = a + b; d = c- при использовании B->Az вы оптимизируете B->xyz.