Visící jinde - Dangling else
The houpající se jinde je problém v programování ve kterém je volitelná klauzule else v Jestliže pak jinak) Výsledkem příkazu je, že vnořené podmínky jsou nejednoznačné. Formálně odkaz bezkontextová gramatika jazyka je dvojznačný, což znamená, že existuje více než jedna správná analyzovat strom.
V mnoha programovací jazyky jeden může napsat podmíněně provedený kód ve dvou formách: formulář if-then a formulář if-then-else - klauzule else je volitelná:
-li A pak s-li b pak s1 jiný s2
To vede k nejednoznačnosti interpretace, když existují vnořené příkazy, konkrétně kdykoli se formulář if-then objeví jako s1
ve formě if-then-else:
-li A pak -li b pak s jiný s2
V tomto příkladu s
je jednoznačně proveden, když A
je pravda a b
je pravda, ale člověk může interpretovat s2
jako prováděné, když A
je nepravdivé (tedy připojuje else k prvnímu if) nebo kdy A
je pravda a b
je nepravdivé (tedy připojením else k druhému if). Jinými slovy lze vidět předchozí příkaz jako jeden z následujících výrazů:
-li A pak (-li b pak s) jiný s2-li A pak (-li b pak s jiný s2)
Problém visícího jiného se datuje do ALGOL 60,[1] a byl vyřešen různými způsoby v následujících jazycích. v Analyzátory LR, visící jiný je archetypálním příkladem a konflikt zmenšení směny.
Vyhněte se nejednoznačnosti při zachování syntaxe
To je problém, který se často objevuje konstrukce kompilátoru, zvláště analýza bez skeneru. Konvencí při jednání s visícím jiným je připojit else k blízkému příkazu if,[2] umožňující zejména jednoznačné bezkontextové gramatiky. Programovací jazyky jako Pascal,[3] C[4] a Java[5] postupujte podle této konvence, takže v sémantice souboru není žádná nejednoznačnost Jazyk, i když použití generátoru syntaktických analyzátorů může vést k nejednoznačnosti gramatiky. V těchto případech je alternativní seskupení provedeno explicitními bloky, jako například začít ... konec
v Pascalu[6] a {...}
v C.
V závislosti na konstrukčním přístupu kompilátoru může člověk provést různá nápravná opatření, aby se vyhnul nejednoznačnosti:
- Pokud analyzátor produkuje SLR, LR (1) nebo LALR Analyzátor LR generátor, programátor se bude často spoléhat na generovanou funkci analyzátoru, že upřednostňuje posun před redukcí, kdykoli dojde ke konfliktu.[2] Alternativně lze gramatiku přepsat tak, aby se konflikt odstranil, na úkor zvětšení velikosti gramatiky (viz níže ).
- Pokud je analyzátor napsán ručně, může programátor použít a nejednoznačný bezkontextová gramatika. Alternativně se lze spolehnout na bezkontextovou gramatiku nebo a analýza gramatiky výrazu.
Vyhněte se nejednoznačnosti změnou syntaxe
Problém lze také vyřešit explicitním spojením mezi else a if v rámci syntaxe. To obvykle pomáhá vyhnout se lidským chybám.[7]
Možná řešení jsou:
- Mít prohlášení „konec, pokud“. Příklady takových jazyků jsou ALGOL 68, Ada, Eiffelova, PL / SQL a Visual Basic
- Zakázání příkazu, který následuje za „then“, aby byl „if“ sám (může to však být dvojice závorek příkazů obsahujících pouze klauzuli if-then). Na tento přístup navazuje ALGOL 60.[8]
- Vyžadování složených závorek (v závorkách), když za „if“ následuje „else“.[9] To skutečně platí v Krajta protože jeho pravidla pro odsazení ohraničují každý blok, nejen ty v příkazech „if“.
- Vyžaduje se spárování každého „pokud“ s „jiným“. Abyste se vyhnuli podobnému problému týkajícímu se spíše sémantiky než syntaxe, Raketa se odchyluje od Systém zvážením
-li
bez záložní klauzule jako chyby, což účinně rozlišuje podmíněné výrazy (tj-li
) z podmíněného prohlášení (tjkdyž
apokud
, které nemají záložní klauzule). - Použití různých klíčových slov pro výroky s jednou alternativou a dvěma alternativami „pokud“ S-algol používá
pokud to uděláme
pro případ jedné alternativy apokud e1, pak e2, jinak e3
pro obecný případ.[10] - Vyžadovat rovnátka bezpodmínečně, jako Rychlý a Modula-2. Chcete-li zmenšit výsledný nepořádek, Modula-2 odstraní otvírák bloků na nefunkčních úrovních.
Příklady
Následuje konkrétní příklad.
C
v C, gramatika zní, částečně:
prohlášení = ... | výběrové prohlášení výběrové prohlášení = ... | Příkaz IF (výraz) | Prohlášení IF (výraz) JINÉ prohlášení
Bez dalších pravidel tedy prohlášení
-li (A) -li (b) s; jiný s2;
lze nejednoznačně analyzovat, jako by to bylo buď:
-li (A){ -li (b) s; jiný s2;}
nebo:
-li (A){ -li (b) s;}jiný s2;
V praxi v C je vybrán první strom přidružením jiný
s nejbližšími -li
.
Vyhněte se konfliktu v analyzátorech LR
Výše uvedený příklad lze přepsat následujícím způsobem, aby se odstranila nejednoznačnost:
výpis: open_statement | closed_statement; open_statement: IF '(' expression ')' statement | IF '(' expression ')' closed_statement ELSE open_statement; closed_statement: non_if_statement | IF '(' expression ')' closed_statement ELSE closed_statement; non_if_statement: ...;
Jakákoli další pravidla gramatiky související s příkazy bude pravděpodobně nutné duplikovat tímto způsobem, pokud mohou přímo nebo nepřímo končit prohlášení
nebo výběrové prohlášení
nekoncový.
Dáme však gramatiku, která zahrnuje výroky if i while.
výpis: open_statement | closed_statement; open_statement: IF '(' expression ')' statement | IF '(' expression ')' closed_statement ELSE open_statement | WHILE '(' expression ')' open_statement; closed_statement: simple_statement | IF '(' expression ')' closed_statement ELSE closed_statement | WHILE '(' expression ')' closed_statement; simple_statement: ...;
Nakonec dáme gramatiku, která zakazuje nejednoznačné výroky IF.
výpis: open_statement | closed_statement; open_statement: IF '(' expression ')' simple_statement | IF '(' expression ')' open_statement | IF '(' expression ')' closed_statement ELSE open_statement | WHILE '(' expression ')' open_statement; closed_statement: simple_statement | IF '(' expression ')' closed_statement ELSE closed_statement | WHILE '(' expression ')' closed_statement; simple_statement: ...;
S touto gramatickou analýzou „if (a) if (b) c else d“ selže:
statementopen_statementIF '(' expression ')' closed_statement ELSE open_statement'if '' ('' a ')' closed_statement 'else' 'd'
a pak analýza selže při pokusu o shodu closed_statement
na „pokud (b) c“. Pokus s closed_statement
selže stejným způsobem.
Viz také
Reference
- ^ Abrahams, P. W. (1966). "Konečné řešení visícího jiného ALGOL 60 a souvisejících jazyků". Komunikace ACM. 9 (9): 679. doi:10.1145/365813.365821.
- ^ A b 5.2 Posun / snížení konfliktů z GNU operační systém webová stránka
- ^ ISO 7185: 1990 (Pascal) 6.8.3.4: Za příkazem if bez else-else nebude okamžitě následován token else.
- ^ ISO 9899: 1999 (C): 6.8.4.1 (3): "K lexikálně nejbližšímu předcházejícímu je přidružen jiný, pokud to umožňuje syntaxe.", K dispozici na WG14 N1256, str. 134
- ^ „Specifikace jazyka Java, vydání Java SE 9, 14.5. Prohlášení“.
- ^ Pascal, Nell Dale a Chip Weems, „Dangling Else“, str. 160–161
- ^ Nejednoznačnost visícího jiného: bezkontextové gramatiky jsou sémanticky neprůhledné
- ^ 4.5.1 Podmíněné příkazy - syntaxe v P. Nauer (ed.), Revidovaná zpráva o algoritmickém jazyce ALGOL 60, CACM 6,1, 1963, s. 1-17
- ^ Nejednoznačnost visícího jiného: vyžadovat složené závorky, pokud jinde následuje if
- ^ Davie, Antony J. T .; Ronald Morrison (1981), Brian Meek (ed.), Rekurzivní kompilace sestupu, Série Ellis Horwood v počítačích a jejich aplikacích, Chichester, West Sussex: Ellis Horwood, s. 20, ISBN 0-470-27270-8