I\'ve read related questions like this and this, and other pages, but they don\'t really answer my question.
Basically, I see code like the following.
For identifiers adjacent underscores (e.g. __attribute__ or __declspec) and a leading underscore followed by an upper case character (e.g. _Bool or _Thread_local) are (generally) reserved for future use and use by the compiler. That means that the normal language rules don't apply for your example as the compiler is free to extend the language. (C.f. "What are the rules about using an underscore in a C++ identifier?")
Have a look at the huge list of language extensions of GCC: https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html#C-Extensions
And the input is really only parsed after the preprocessing. SOME_MACRO also could contain X; class for all good it would do.