dangling else является проблемой в компьютерном программировании, в котором необязательное предложение else в операторе if – then (–else) приводит к неоднозначности вложенных условий. Формально справочная контекстно-свободная грамматика языка неоднозначна, что означает, что существует более одного правильного дерева синтаксического анализа.
Во многих языках программирования можно написать условно исполняемый код в двух формах: форма if-then и форма if-then-else - предложение else является необязательным:
ifa then s ifb then s1 else s2
Это вызывает двусмысленность в интерпретации при наличии вложенных операторов, особенно когда форма «если-то» отображается как s1
в форме «если-то-еще»:
ifa затем ifb затем s else s2
В этом примере s
однозначно выполняется, когда a
истинно и b
истинно, но можно интерпретировать s2
как выполняемое, когда a
ложно (таким образом, присоединяя else к первому if) или когда a
истинно, а b
ложно (таким образом, добавляя else ко второму условию if). Другими словами, можно увидеть предыдущий оператор как одно из следующих выражений:
ifa затем (ifb затем s) else s2 ifa затем (ifb затем s else s2)
Проблема зависания else датируется АЛГОЛОМ 60 и была решена различными способами в последующих языках. В парсерах LR болтающийся else является типичным примером конфликта сдвиг-уменьшение.
Это проблема это часто встречается в конструкции компилятора, особенно в разборе без сканирования. При работе с висячим else принято присоединять else к ближайшему оператору if, что позволяет, в частности, использовать однозначные контекстно-свободные грамматики. Языки программирования, такие как Pascal, C и Java, следуют этому соглашению, поэтому нет двусмысленности в семантике языка, хотя использование генератора синтаксического анализатора может привести к неоднозначной грамматике. В этих случаях альтернативная группировка выполняется явными блоками, такими как begin... end
в Паскале и {...}
в C.
В зависимости от Подход к построению компилятора, можно предпринять различные корректирующие действия, чтобы избежать двусмысленности:
Проблема также может быть решена путем явной связи между и его if в синтаксисе. Обычно это помогает избежать человеческих ошибок.
Возможные решения:
if
без запасного предложения ошибкой, эффективно различая условные выражения (т. е. if
) из условных операторов (т. е. when
и кроме
, которые не имеют запасных предложений).if e do s
для одноальтернативного случая и если e1, то e2 else e3
для общего случая.Далее следуют конкретные примеры.
В C грамматика частично читается:
утверждение =... | оператор выбора оператор выбора =... | IF (выражение) оператор | IF (выражение) оператор ELSE оператор
Таким образом, без дополнительных правил, оператор
if (a) if (b) s; else s2;
может быть неоднозначно проанализирован, как если бы он был либо:
if (a) {if (b) s; else s2; }
или:
if (a) {if (b) s; } else s2;
На практике в C первое дерево выбирается путем связывания else
с ближайшим if
.
Приведенный выше пример можно переписать следующим образом способ устранить двусмысленность:
инструкция: open_statement | closed_statement; open_statement: оператор IF '(' выражение ')' | IF '(' выражение ')' closed_statement ELSE open_statement; closed_statement: non_if_statement | IF '(' выражение ')' closed_statement ELSE closed_statement; non_if_statement:...;
Любые другие правила грамматики, связанные с операторами, также могут быть дублированы таким образом, если они могут прямо или косвенно заканчиваться оператором или
оператором выбора
не- Терминал.
Однако мы даем грамматику, которая включает в себя инструкции if и while.
инструкция: open_statement | closed_statement; open_statement: оператор IF '(' выражение ')' | IF '(' выражение ')' closed_statement ELSE open_statement | WHILE '(' выражение ')' open_statement; closed_statement: simple_statement | IF '(' выражение ')' closed_statement ELSE closed_statement | WHILE '(' выражение ')' closed_statement; simple_statement:...;
Наконец, мы даем грамматику, запрещающую неоднозначные операторы IF.
инструкция: open_statement | closed_statement; open_statement: IF '(' выражение ')' простое_выражение | IF '(' выражение ')' open_statement | IF '(' выражение ')' closed_statement ELSE open_statement | WHILE '(' выражение ')' open_statement; closed_statement: simple_statement | IF '(' выражение ')' closed_statement ELSE closed_statement | WHILE '(' выражение ')' closed_statement; simple_statement:...;
С этим грамматическим синтаксическим анализом "if (a) if (b) c else d" не удается:
оператор open_statement IF '(' выражение ')' closed_statement ELSE open_statement 'if' '( '' a '') 'closed_statement' else '' d '
, а затем при синтаксическом анализе не удается сопоставить closed_statement
с «if (b) c». Попытка с closed_statement
терпит неудачу точно так же.