Приведённая контекстно‑свободная грамматика для арифметических выражений S -> S + S | S * S | (S) | id неоднозначна и леворекурсивна; преобразуйте её в эквивалентную грамматику, пригодную для построения LL(1)‑парсера и для LALR‑parserа, поясните, как вы устраняете неоднозначность при соблюдении приоритетов операторов и ассоциативности?

20 Окт в 16:39
3 +3
0
Ответы
1
Коротко: нужно убрать левую рекурсию и явно зая­вить уровни приоритетов и ассоциативность. Привожу устойчивую LL(1)‑версию и вариант для LALR (через либо переработанную грамматику, либо декларации приоритетов).
1) LL(1)‑грамматика (без левой рекурсии, с приоритетом ′∗′>′+′'*' > '+'>+ и левой ассоциативностью):
E→T E′ E \to T\ E'
ET E
E′→+ T E′ ∣ ε E' \to +\ T\ E'\ \mid\ \varepsilon
E+ T E ε
T→F T′ T \to F\ T'
TF T
T′→∗ F T′ ∣ ε T' \to *\ F\ T'\ \mid\ \varepsilon
T F T ε
F→( E ) ∣ id F \to (\ E\ )\ \mid\ id
F( E ) id

Пояснения:
- Уровни соответствуют нетерминалам: EEE — выражение с суммой, TTT — терм (умножение), FFF — фактор. Это гарантирует, что операторы ∗* связываются сильнее, чем +++, потому что в EEE сначала полностью распознаётся TTT (включая все ∗*), и только затем возможны «+».
- Ассоциативность «влево» реализуется хвостовой рекурсией E′→+ T E′E' \to +\ T\ E'E+ T E и T′→∗ F T′T' \to *\ F\ T'T F T: при построении AST принято сворачивать последовательность справа налево в левую цепочку, что даёт семантику (a+b)+c(a+b)+c(a+b)+c и (a∗b)∗c(a*b)*c(ab)c.
- Грамматика не содержит левой рекурсии и удовлетворяет условиям LL(1): для каждого нетерминала множества FIRST альтернатив и FOLLOW при ε\varepsilonε являются разделимыми.
2) Вариант для LALR (две возможности)
a) Использовать ту же грамматику, что и для LL(1). Она подходит и для LALR(1) парсеров (нет неоднозначности).
b) Если хотите оставить исходную компактную форму (удобно в Yacc/Bison), разрешить неоднозначности с помощью приоритетов и ассоциативности:
Пример в стиле Yacc/Bison (псевдосинтаксис; порядок деклараций определяет приоритет — более поздние выше):
%left '+'
%left '*'
%%
S : S '+' S
| S '*' S
| '(' S ')'
| id
;
Пояснения:
- Директивы `%left` устанавливают левую ассоциативность для указанных токенов.
- Порядок деклараций делает `*` более приоритетным, чем `+` (в Bison/Yacc позднее объявленные токены имеют больший приоритет).
- При возникновении конфликтов shift/reduce парсер использует эти декларации: при конфликте между `+` и `*` выберется соответствующее разрешение по приоритету; при конфликте с одинаковым приоритетом и `%left` — произойдёт reduce (что даёт левую ассоциативность).
Итого:
- Для LL(1) и детерминированного парсинга безопасно применять приведённую «разложенную» грамматику E,T,FE,T,FE,T,F.
- Для генераторов LALR можно либо использовать ту же неамбициозную грамматику, либо оставить компактную и разрешать конфликты через объявления приоритета/ассоциативности.
20 Окт в 17:05
Не можешь разобраться в этой теме?
Обратись за помощью к экспертам
Гарантированные бесплатные доработки в течение 1 года
Быстрое выполнение от 2 часов
Проверка работы на плагиат
Поможем написать учебную работу
Прямой эфир