In reply to TG:
I don’t agree with the results you are seeing (at least two other simulators don’t either).
The macro preprocesor only understands identifiers, string literals, other macros, and escape sequences ``, `". There are referred to as ‘tokens’. Everything else is just text and white space.
An identifier starts with alphabetic character a-Z or _, and continues until hitting a non-alphanumeric character. (alphanumeric also includes $ and _). An identifier can also start with \ and continues until hitting a space (the \ and space are part of identifier). This is known as an escaped identifier.
Within a macro, is a token joining operator. It joins the two tokens on either side of the
into a single token, but after macro argument replacement.
If we look at the third macro
`define C(x) sub \\``base_``x* ();
The first token is the identifier sub. The second token is the start of an escaped identifier \. Remember that any character after the first \ is part of the identifier up the the first whitespace. So the first two chars are \. The third token is base_. Since we have not hit whitespace, we continue with the fourth token the identifier x. but before joining, we see that the identifier x matches the macro argument x, so the macro will replace x with the text of the actual argument C. The we continue with the token joining, adding the * and finally getting to the whitespace. The remainder of the macro is the text ();.
The proper macro replacement is
sub \\base_C* ();
The reason for the last error is because the macro expansion is looking for another macro with the escaped name \x* , which does not exist.