[1]: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/m...
1. built-in macro names that require arguments such as `define' are not "expanded" if you don't follow them with parentheses
2. there's an option to require a magic sigil character to invoke macros, such as % or something; this turns out to have been required in the original gpm and its bell labs clone m6. this helps enormously with complicated macros
however, the fact that the output of your macro is always immediately run as new code (as opposed to m6 and gpm, where this was optional on a per-call basis) makes m4 just ridiculously error-prone. i feel like trauma from debugging m4 macros was a major consideration in the design of the weak-ass c preprocessor
Why not use SSI[1]? It's inspired by the CPP's syntax, but is supported directly by most HTTP servers (and is more powerful, to boot).
Because hacking is fun, and it's still fun if it's a bad idea
I ended up using a Perl preprocessor, but it seems like cpp would work ok-ish for certain use cases that don’t require, say, strict tabs like Python among a few other things mentioned on the cpp manual.
I've used it in the past for wrangling the definitions of a multitude of SQL triggers I was using to generate a real-time materialized view. The fact that you can modify its syntax is very helpful for making it work with non-C syntaxes (like SQL or even LaTeX).
It even has an HTML mode built-in, which you can customize to your needs, but looks like:
<#define x|y>
<#macro arg|...>
which works better for certain WYSIWYG editors. You could modify the syntax to be <!--#define x y-->
<!--#macro(arg, ...)-->