Question

I am studying the C++ standard on how the C++ preprocessor handles macro substitution in detail (I need to implement a subset of the C++ preprocessor myself). And here is an example I created for my studying:

  #define a x
  #define x(x,y) x(x+a, y+1)

  a(x(90, 80), a(1,2))

By asking VC++ 2010 to generate the preprocessor output file, I found that the above a(x(90, 80), a(1,2)) becomes this:

90(90+x, 80+1)(90(90+x, 80+1)+x, 1(1+x, 2+1)+1);

But how does the preprocessor come up with this output? The rules are too complicated to comprehend. Can someone explain all the steps the preprocessor has done to come up with such a result?

Was it helpful?

Solution

Old answer, order is not exact (see edit):

Let's start from your expression:

a(x(90, 80), a(1, 2))

Now, since we have #define a x, it gets expanded to:

  x(x(90, 80), x(1, 2))
//  ^^^^^^^^^  ^^^^^^^
//   arg 'x'    arg 'y'

We can apply the definition of x(x,y), which is #define x(x,y) x(x+a, y+1):

x(90, 80)(x(90, 80)+a, x(1, 2)+1)

There is another pass that will expand x(...). You can also notice that the +a that > was in the previous expression was expanded to +x:

  90(90+a, 80+1)(90(90+a, 80+1)+x, 1(1+a, 2+1)+1)
//                             ^^
//                          expanded

Last: the +a that remains are expanded to +x:

  90(90+x, 80+1)(90(90+x, 80+1)+x, 1(1+x, 2+1)+1)
//     ^^             ^^              ^^
//  expanded       expanded        expanded

I hope there are no errors.

Please note that your definition of x(x,y) is quite ambiguous (for humans): the macro name and a parameter share the same name. Note that even withouth that, macros are not recursive, so if you had

#define x(u,v) x(u+a, b+1)

it would not expand to something like

x(u+a+a+a+a, b+1+1+1+1)

This is because when the macro x is defined, its name is not 'available' to the inner macro definition.

Another small note: for gcc, the output is not exactly the same, as gcc add spaces between replaced tokens (but if you remove them it will be the same as msvc).

EDIT: from the comments of dyp, this order is not the exact one. In fact, parameters are expanded first and then substituted in the macro expression. The last part of the sentence is important: that means that the macro parameter list is not re-evalued. Think of it as: macro gets expanded with placeholders in lieu of the parameters, then arguments are expanded, and then the placeholders are replaced by their respective argument. So, in short, that is equivalent to what I explained before, but here is the right order (detailed operations):

> Expansion of a(x(90, 80), a(1, 2))
    > Substitution of 'a' into 'x' (now: 'x(x(90, 80), a(1, 2))')
    > Expansion of x(x(90, 80), a(1, 2)) [re-scan]
        > Macro 'x(X, Y)' is expanded to 'X(X+a,Y+1)'
        > Expansion of 'x(90,80)' (first argument)
            > Macro 'x(X,Y)' is expanded to 'X(X+a,Y+1)'
            > Argument '90' does not need expansion (ie, expanded to same)
            > Argument '80' does not need expansion (ie, expanded to same)
            > Substitution with 'X=90' and 'Y=80': '90(90+a, 80+1)'
            > Re-scan of result (ignoring macro name 'x')
                > Substitution of 'a' into 'x': '90(90+x, 80+1)'
        > Expansion of 'a(1,2)' (second argument)
            > Substitution of 'a' into 'x'
            > Expansion of 'x(1,2)' [re-scan]
                > Macro 'x(X,Y)' is expanded to 'X(X+a,Y+1)'
                > Argument '1' does not need expansion (ie, expanded to same)
                > Argument '2' does not need expansion (ie, expanded to same)
                > Substitution with 'X=1' and 'Y=2': '1(1+a, 2+1)'
                > Re-scan of result (ignoring macro name 'x')
                    > Substitution of 'a' into 'x': '1(1+x, 2+1)'
        > Substitution with X='90(90+x, 80+1)' and Y='1(1+x, 2+1)'
          Result: '90(90+x, 80+1)(90(90+x, 80+1)+a, 1(1+x, 2+1)+1)'
        > Re-scan of result
            > Substitution of 'a' into 'x'
              Result: '90(90+x, 80+1)(90(90+x, 80+1)+x, 1(1+x, 2+1)+1)'
Last result is result of whole expansion:
    90(90+x, 80+1)(90(90+x, 80+1)+x, 1(1+x, 2+1)+1)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top