Re: A little m4 puzzle

Eric Blake <[email protected]> Mon, 12 Nov 2018 11:49:31 -0600
Newsgroups gmane.comp.gnu.m4.general
Organization Red Hat, Inc.
Message-ID <[email protected]>
On 11/10/18 12:01 PM, Doug McIlroy wrote:
> Consider this predicate on strings.
> 
>     define(eq,`define(`_$1',F)define(`_2',T)_$1')

Underquoted.  I highly recommend using full quoting:

define(`eq', `define(`_$1', `F')define(`_2', `T')_$1')

Also, did you mean for that _2 to be _$2 instead?  And do you want to 
undef your temporary variable(s) after the fact?

> 
> eq(x,y) yields T or F according as strings x and y are
> the same or different. (The strings may contain only
> characters allowed in macro names).

So you are (trying to) exploit the fact that if the strings are 
different, you define two separate temporary variables (assuming you 
meant _$2); if they are equal, you redefine a single temporary variable.

> 
> The puzzle: If you omit inner quotes from the definition,
> eq(A,A) yields T as intended. But what happens when you
> repeat the test?

You mean, as in:

define(eq, `define(_$1, F)define(_$2, T)_$1')

If so, then it's pretty easy to trace:

The first eq(A,A) expands to:

define(_A, F)define(_A, T)_A

which results in defining the macro "_A" to be "F" before expanding:

define(_A, T)_A

which is the same as:

define(F, T)_A

which defines the "F" to be "T", then expands the macro _A into F, and 
the macro F into T.

The second eq(A,A) expands to:

define(_A, F)define(_A, T)_A

where the first define is now the same as:

define(T, T)define(_A, T)_A

which defines the macro "T" to "T".  At which point, ANY attempt to 
expand the macro T will infinitely recurse, which is exactly what 
happens when you reach the second define().

> 
> (Incidentally, you can replace T by `$3' and F by `$4'
> to make a near replacement for the builtin ifelse.)

Not with your lack of proper quoting.  And the builtin can handle any 
two strings, not just strings that are valid as part of a macro name.

-- 
Eric Blake, Principal Software Engineer
Red Hat, Inc.           +1-919-301-3266
Virtualization:  qemu.org | libvirt.org