Дана контекстно-свободная грамматика: S -> S + S | S * S | a | (S) ; покажите, что грамматика неоднозначна, приведите пример строки с двумя различными деревьями разбора, постройте неамбигуализированную грамматику, явно задающую приоритеты и ассоциативности (+ ниже * и левосторонняя ассоциативность), и опишите алгоритм синтаксического анализатора (LR/LL) для неё

12 Окт в 14:14
4 +1
0
Ответы
1

1) Демонстрация неоднозначности

Грамматика исходнаяисходнаяисходная S -> S + S | S * S | a | SSS

Строка-пример: a + a * a

Два различных дерева разбора.

Вариант A плюснаверхнемуровне:a+(a∗a)плюс на верхнем уровне: a + (a * a)плюснаверхнемуровне:a+(aa):

S
/|\
S + S
| /|\
a S * S
| |
a a

Соответствующий вывод:
S ⇒ S + S ⇒ a + S ⇒ a + S<em>SS <em> SS<em>S ⇒ a + a</em>aa </em> aa</em>a

Вариант B звёздочканаверхнемуровне:(a+a)∗aзвёздочка на верхнем уровне: (a + a) * aзвёздочканаверхнемуровне:(a+a)a:

S
/|\
S * S
/|\ |
S + S a
| | |
a a a

Вывод:
S ⇒ S S ⇒ S+SS + SS+S S ⇒ a+aa + aa+a * a

Поскольку получено два разных дерева разбора для одной и той же строки, грамматика неоднозначна.

2) Неамбигуализированная грамматика с приоритетами и левой ассоциативностью

Требование: * имеет более высокий приоритет, + — ниже; обе операции левосторонние.

Классическое неамбигуизированное правило:

E -> E + T | T
T -> T * F | F
F -> a | E E E

Здесь:

T соответствует произведениям болеевысокийприоритетболее высокий приоритетболеевысокийприоритет,E — суммам нижнийприоритетнижний приоритетнижнийприоритет,левая рекурсия E -> E + T и T -> T * F задаёт левую ассоциативность.

Эквивалентная форма, удобная для LL111 убираемлевуюрекурсиюубираем левую рекурсиюубираемлевуюрекурсию:

E -> T E'
E' -> + T E' | ε
T -> F T'
T' -> * F T' | ε
F -> a | E E E

3) Почему это однозначно и задаёт заданные приоритеты/ассоциативности

В этой грамматике операции образуются в поддеревьях T, которые находятся ниже по иерархии, чем E, поэтому связывается сильнее, чем +. Для строки a + a a единственный допустимый разбор по этой грамматике — E -> T E' с T->F и правой частью T' дающей aaaa — то есть a + a∗aa * aaa.Левая рекурсия E -> E + T гарантирует, что последовательность a + a + a разобьётся как a+aa + aa+a + a леваяассоциативностьлевая ассоциативностьлеваяассоциативность, а не как a + a+aa + aa+a.

4) Описание алгоритма синтаксического анализатора

Вариант A — LL111, рекурсивный нисходящий предиктивный парсер

Используем LL111-форму E,E′,T,T′,FE, E', T, T', FE,E,T,T,F.Построить таблицу предсказания по FIRST/FOLLOW (коротко: FIRST(+ T E') = '+', FIRST(T)= {'a','('}, FIRST(E') = {'+','ε'}, и т.д.). Эта грамматика является LL(1).Реализовать функции (псевдокод):

function parseE():
parseT()
parseEprime()

function parseEprime():
if current_token == '+':
consume('+')
parseT()
parseEprime()
else
// ε: вернуть

function parseT():
parseF()
parseTprime()

function parseTprime():
if current_token == '':
consume('')
parseF()
parseTprime()
else
// ε: вернуть

function parseF():
if current_token == 'a':
consume('a')
else if current_token == '(':
consume('(')
parseE()
expect(')') // consume ')' или ошибка
else
error()

Этот парсер читается слева направо, использует прогноз по одному символу (LL(1)). Постфикс вызовов гарантирует, что парсер отражает приоритеты: внутри E мы сначала распознаём T (вся цепочка * и F), затем уже разрешаем +.

Вариант B — LR (shift-reduce, LALR(1)/LR(1))

Можно строить стандартный LR(1)/LALR(1)-парсер для неамбигуализированной грамматики (E->E+T|T, T->T*F|F, F->a|(E)).Алгоритм (общая схема):
Построить множество состояний автомата LR(1) (канонические множества LR(1)-шпилек/пунктов) и таблицы action/goto.Парсер хранит стек состояний; на вход подаётся поток токенов.На каждом шаге берётся текущее состояние s (вершина стека) и текущий токен a:если action[s,a] = "shift t": поместить токен и состояние t в стек, прочитать следующий токен;если action[s,a] = "reduce A -> β": снять 2*|β| элементов со стека (символы и состояния), найти новое состояние s' = top(stack), поместить A и goto[s',A] в стек;если action[s,a] = "accept": успешно завершить;иначе — синтаксическая ошибка.Для нашей грамматики таблицы action/goto будут однозначными (без конфликта shift/reduce) — она принадлежит к классу LR(1) (и обычно к LALR(1)), поэтому парсер корректно обрабатывает приоритеты, заданные структурой грамматики.

Пример шагов (LR shift/reduce) для входа a + a * a (схематично):

shift 'a' ; reduce F->a ; reduce T->F ; (в зависимости от состояний можно сразу редьюсить) ; далее shift '+' ; shift 'a' ; shift '' ; shift 'a' ; reduce F->a ; reduce T->T F ; reduce E->E + T ; accept.
Точные состояния и действия зависят от построенной таблицы.

Резюме:

Исходная грамматика неоднозначна (пример a+a*a даёт два дерева).Неамбигуизированная версия с требуемыми приоритетами и левой ассоциативностью — стандартная E/T/F-иерархия:
E -> E + T | T ; T -> T F | F ; F -> a | ( E )
или LL(1)-эквивалент:
E->T E' ; E'-> + T E' | ε ; T->F T' ; T'-> F T' | ε ; F-> a | (E)Для неё можно реализовать либо предиктивный LL(1)-парсер (рекурсивный нисходящий), либо стандартный LR(1)/LALR(1) shift-reduce парсер; оба разбора однозначны и соблюдают требуемые приоритеты и ассоциативность.
12 Окт в 14:48
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир