bart <
bc@freeuk.com> writes:
On 11/12/2024 22:06, Keith Thompson wrote:
bart <bc@freeuk.com> writes:
[...]
You need input from a symbol table in order to parse C, a table that
the parser needs to maintain as it processes source code. That will
tell you whether a particular identifier is a typename or not.
Yes. (I've mentioned this a number of times.)
There are issues also with keywords like 'break'.
What issues?
>
I see that the C grammar treats both kinds of 'break' as a jump.
Sure, because they're both jumps, and the still would be if they
used different keywords.
I for
one generate two separate constructs for the two kinds. That requires
keeping track of the stack of nested switch/while/for/dowhile
statements.
C compilers have to keep track of that anyway.
Sure, using two different keywords is perfectly valid, and
IMHO preferable, for any non-C language anyone cares to invent.
For that matter, if a language's equivalent of C's switch statement
doesn't have fallthrough by default, there's less need for a special
statement to terminate a switch, and again, "break" would apply
only to loop statements.
(Removing the switch statement's fallthrough behavior would break
existing code. It could be addressed by adding a new kind of
statement, but I personally think it would be ugly and insufficiently
useful.)
Are you bothered by the fact that "break" applies to all three
kinds of iteration statements (while, do, for)?
If you're referring to the fact that break can apply either to a loop or
to a switch, that's a potential source of confusion, but it shouldn't be
a problem once you're aware of it.
>
It can be very much a problem. Suppose you have an if-else chain
within a loop that contains loop-break. Later you upgrade it to
switch. Now it no longer jumps to the end of the loop, but the end of
the switch.
So what do you want to do about it? You could have discussed ways to
deal with the issue.
Yes, you have to be careful when refactoring code.
Even if aware of it, now you're stuck for getting to the end of the
loop. It can also happen in reverse when you downgrade a switch to
if-else. And to a lesser extent when you wrap a case-block containing
'break' with a loop.
>
I don't know why two different keywords weren't used for this instead
of having to share.
B used "break" for both purposes. C just inherited that. (Yes,
Ritchie could have changed it. He didn't.) I'm not saying it was
the best choice, but it's what we have.
I certainly wouldn't have minded if C had used two different
keywords (the csh shell uses "break" and "breaksw", for example).
And I definitely wouldn't have minded if C's switch statement didn't
fall through by default, but that can't be fixed.
Sure, the fact that "break" is overloaded can be slightly
inconvenient. So can the fact that "break" only exits the
*innermost* enclosing loop or switch.
Using two different keywords (which, to be clear, is unlikely to
happen in any language called "C") would only solve a small part of
the problem. What I'd really like to see is a mechanism for "break"
(or "continue") to apply to a *named* enclosing construct, something
I've found very useful in other languages that support it. It would
provide an easy solution to the scenario you mentioned above.
There's a proposal to add such a feature to C++ :
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3879.pdfThere's a 2021 proposal to add a similar feature to C, but using "break
break" rather than "break NAME" :
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2859.pdf(Personally, I greatly prefer the "break NAME" construct. Computers
are really good at counting things; don't make me do it myself.)
In the absence of multi-level "break", you can always use "goto".
Please, let's assume we've already had the lengthy discussion of
how bad "goto" is.
But as a C programmer, I find it far more useful to understand and
discuss how the C language is defined, and how to use it, than to
complain about its *widely acknowledged* shortcomings.
-- Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.comvoid Void(void) { Void(); } /* The recursive call of the void */