True, I know all about that. My Zortech C and C++ compiler was one pass (after the multiple preprocessing passes). The ground up ImportC C compiler completed a couple years ago has a separate parse pass.
So I well know the tradeoffs. The parser being stand-alone means it is much simpler to understand and unittest. I found no advantage to a single pass compiler. It isn't any faster.
> simply adding things onto C gets you C++
C++ doesn't allow forward declarations either.
Successfully doing a parse-only on C code doesn't quite work. It turns out the grammar relies on a symbol table. Fortunately, only a symbol table of the typedefs. Once adding that in, ImportC worked. (I really tried to make it work without the typedef symbol table!)
C++ added a bunch more syntax that relies on the symbol table. I would not even try fixing it to work as parse-only.
> in C you don't solve problems by adding features, but by writing more code in C
The trouble with such sayings is like following a google map that says cross this bridge, but wasn't updated with news that the bridge is out.
> Those things aren't that obvious,
They are once you use another language that doesn't have those restrictions.
> and I'd rather not have them added to C.
C adds new things all the time to the Standard, like normalized Unicode identifiers, which are a complete waste of time. Every C compiler also adds a boatload of extensions, some good, some wacky, many ineptly documented, all incompatible with every other C compiler extensions.