See my test up on ideone--it seems that it compiles just fine, much to my surprise.
Basically what happens is: b-MONE -> lexer -> (b) (-) (MONE) -> preprocessor -> (b) (-) (-) (1) -> parser
And I think you expected: b-MONE -> preprocessor -> b--1 -> lexer -> (b) (--) (1) -> fail
PS. yeah, preprocessor+lexer are a bit more coupled, but that's the general idea
http://gcc.gnu.org/onlinedocs/cppinternals/Token-Spacing.htm...
I can't find anything in the C spec that says this is strictly required, but that doesn't mean it's not in there.
A pre-ANSI preprocessor would generally emit ‘--’, which the compiler would naturally recognize as a decrement operator. I'm not aware of any exceptions; pre-ANSI implementations diverged in various ways, but tended to follow either K&R 1 or Reiser (John, not Hans) CPP.