On Friday, 29 September 2017 at 10:32:02 UTC, Timon Gehr wrote:
On 29.09.2017 11:12, Don Clugston wrote:
Guess what this prints
----
import std.stdio;
void main()
{
int i = 0;
switch (i) for (i = 8; i < 10; ++i)
{
case 7:
writeln(i);
return;
default: ;
}
}
----
Why does this even compile? It's because the grammar is:
SwitchStatement:
switch ( Expression ) ScopeStatement
and ScopeStatement allows almost anything.
I think the only sane grammar is
SwitchStatement:
switch ( Expression ) BlockStatement
Initially I thought ScopeStatement was accepted in order to
enable Duff's device, but it isn't necessary for that. It
might have originally accepted ScopeStatement to support
E e; switch( e ) with (E) { .... }
Or it may have just been an accident.
It is very likely that this part of the grammar was
deliberately copied from C. It's also consistent with how all
other control flow constructs are parsed.
But regardless of the original motivation, it allows some
truly dreadful semantics.
I don't see what your proposed grammar change accomplishes:
switch(i){
for(i=8;i<10;++i){
case 7:
writeln(i);
return;
default:{}
}
}
I.e., you seem to have misidentified the culprit. Whether or
not to the curly braces are required by the parser has nothing
to do with switch semantics.
That case looks quite different to me.
It's rather more obvious that the `for` statement has been
skipped.
The problem I have with the original example is that it looks as
though the body of the `for` loop is the body of the switch
statement.
Can we disallow this silliness please?
Maybe this specific case can be disallowed during semantic (but
I don't really see why it helps, it mostly just makes the
language definition more complex).
I believe it makes it simpler. You cannot avoid the reference to
BlockStatement.
Note that: "A switch statement must have a default statement."
This is only possible only in two situations.
1. Silly degenerate case.
switch (i) default: ;
2. A statement which contains a BlockStatement.
It accepts unreachable code.
switch (i) if ( foo() ) {} else { default: ; }
A switch statement followed by anything other than a
BlockStatement is *always* wrong. Always.
We improved the switch statement a lot by disallowing implicit
fallthrough. But it still allows other nonsense that was
presumably inherited from the very early days of K&R C.
This example just struck me as exceedingly silly, and quite
misleading.