I hesitate to use the word MACRO since my background is computer science although I can see how it can be thought of as that.My understanding is M-codes are Macros, which in a lot of cases can become machine application specific. While there are standards, the more I see both G and M codes vary with machine and application.
If you note Fusion, SW, Mastercam and others have options to specify the machine to tweak the conversational language to write machine specific code. Generic is a good starting point, but machine specific is what is required.
Macro (computer science) - Wikipedia
en.wikipedia.org
If it were a MACRO from the programming perspective then the M6 instruction would be expanded into a number of other G-Code instructions. But in many ways the enhancement of an Mx command is more like a function or subroutine call that exists in another file rather than the current one. The M98 and M99 branch and return from a different section of the existing G-Code program so the G-Code interpreter has to locate the O4000 statement when it sees the M98 P4000 line. It returns to the next line when it encounters the M99.
That makes the M98 more like an assembly language subtroutine CALL and the M99 the RET instruction. Or in BASIC GOSUB and RETURN.
If it were a true MACRO for a sequence of G-Codes then a new file would first be created from the source file and at each location of the MACRO there might be an extra 100 lines of G-Code representing the MACRO expansion. I don't think G-Code interpreters do it that way.
But I'm new to this.