Path: csiph.com!eternal-september.org!feeder.eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail From: Tim Rentsch Newsgroups: comp.lang.c Subject: Re: Preprocessor and "empty" substitutions Date: Wed, 09 Oct 2019 06:34:20 -0700 Organization: A noiseless patient Spider Lines: 108 Message-ID: <86d0f682lf.fsf@linuxsc.com> References: <874l0kl3sm.fsf@bsb.me.uk> <87muecjcfo.fsf@bsb.me.uk> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Injection-Info: reader02.eternal-september.org; posting-host="c0077320ebba5bb8d2e49a5d4c287ef2"; logging-data="17932"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19ac4vDTCXP3QfWZJQG79rBdmWj5lxXzzM=" User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux) Cancel-Lock: sha1:AowtaoOCQt0J942LBlAWABeiRtE= sha1:Z0WssrHOB9wcciJV4Jew4ra/LPI= Xref: csiph.com comp.lang.c:146799 Andrey Tarasevich writes: > On 10/7/2019 5:41 PM, Ben Bacarisse wrote: > >>> we'll see that the above occurrence of macro name 'D' is ultimately >>> replaced by 'x', meaning that there is some kind of >>> _repetitive/recursive_ rescan involved. >> >> If that's how you like to think of it, then go for it. I just say that >> when a macro is expanded, that expansion is scanned for more macros. > > Well, the text of the standard seem to draw a pretty specific > distinction between how parameter values are substituted and how > nested macro invocations are substituted: > > * In case of parameters it states that first of all, any macro > substitutions inside the parameter value are processed. And only > when this process is complete (i.e. everything is exhaustively > substituted) the final result is planted into the parent macro. > > * In case of nested macro invocations it is the other way around: > the substitution list for the invoked macro is immediately planted > into the parent macro, and only afterwards that planted list is > rescanned for more macro invocations. > > This appears to be done for some specific reason. And the first > reason for that distinction that come to mind is that parameters > are intended to be processed out-of-context, while macro invocations > are intended to be handled (rescanned) in-context (in the context of > surrounding tokens). > >>> I presume that what you mean is that the rescan process is done >>> _locally_. >> >> Well, I meant what I said but it was obviously not clear. >> >>> 6.10.3/9 (http://port70.net/~nsz/c/c11/n1570.html#6.10.3p9) says >>> >>> "The replacement list is then rescanned for more macro names as >>> specified below." >>> >>> I initially assumed that the term "replacement list" in this quote is >>> referring to the entire replacement list of the top-level macro. >> >> To my mind, that would be an odd interpretation. It seems obvious that >> "the replacement list" refers to the one in the definition being >> expanded. > > May be. But in that case it is not clear why wouldn't they just > unify the specification of macro parameter substitution with the > specification of macro invocation: first, exhaustively substitute > everything that can be substituted in the replacement list and > only then plant the result into the target location. I think there are two points that are causing you confusion. One is the idea that macro calls are "nested". The other is the idea that how macro /arguments/ are expanded is somehow fundamentally different than how macro /definitions/ are expanded. Neither of these ideas is really right. The first is sometimes a convenient way to think about defining a macro but doesn't exactly match how expansion is done. The second is simply wrong. Let me see if I can explain. Macro calls are not "nested" because further calls are not expanded until the top-level expansion for the current call has been substituted. That matters because the top-level expansion may cause further calls to come into being, or it may cause tokens that look like they would be calls not actually to be calls. A lot of times it helps to think about macro definitions as having nested calls, but it's important to know that this view is a simplification and sometimes it breaks down. The second point may be more telling. How macro arguments are expanded is almost exactly the same as how macro definitions are expanded. There are some differences, and the differences are not trivial. However, it is not the case that macro arguments are "exhaustively substituted" before being plugged into a macro definition. The process is exactly the same as expanding a parameterless macro called at the end of a translation unit. It can be hard to see the sameness, because macro arguments are scanned a second time after being expanded, as part of processing the macro definition. Here is an example to help see what's going on, using the OUTPUT/EMPTY method used in your original posting: #define MYSTERY_GUEST OUTPUT EMPTY (3) #define OUTPUT(x) show x #define EMPTY #define TWO(x) ONE(x) #define ONE(x) ZERO(x) #define ZERO(x) #x ONE( MYSTERY_GUEST ) TWO( MYSTERY_GUEST ) Output of 'gcc -E -' (but leaving out the preprocessor line directives): "OUTPUT (3)" "show 3" This example shows that macro arguments are not exhaustively expanded before being substituted in the expanded macro body. Do you see why? Can you explain what is going on that causes this result to be produced?