4

I wrote a small m4 script (test.m4) for testing purposes:

define(`test', `ifelse(`$#', `1', `$1', test(shift($@)))')
test(`arg1', `arg2')

and ran it with m4 test.m4 -t test -de1. The output was

m4trace: -1- test -> ifelse(`2', `1', `arg1', test(shift(`arg1',`arg2')))
m4trace: -2- test -> ifelse(`1', `1', `arg2', test(shift(`arg2')))
m4trace: -3- test -> ifelse(`1', `1', `', test(shift(`')))
m4trace: -4- test -> ifelse(`1', `1', `', test(shift(`')))
.
.
.

until execution was aborted due to an exceeded recursion limit. I wondered why this was so because actually 1 and 1 should compare equal and the if else macro should evaluate to `'.

However, I had the innovative idea to put the [not-equal] into quotation marks, so the macro looked like this:

define(`test', `ifelse(`$#', `1', `$1', `test(shift($@))')')
test(`arg1', `arg2')

and voilĂ , it worked like a charm (i.e., arg2 was printed out along with a leading newline).
The output (with the same invocation parameters):

NL
m4trace: -1- test -> ifelse(`2', `1', `arg1', `test(shift(`arg1',`arg2'))')
m4trace: -1- test -> ifelse(`1', `1', `arg2', `test(shift(`arg2'))')
arg2

(NL stands for "newline").

My conclusion: even though the two strings to compare are, in fact, equal, the preprocessor evaluates the [not-equal] branch nevertheless.

Does this have any specific purpose? IMO, it's just unintuitive. Or am I missing something?


1 -t test turns debug tracing for the macro test on. -de adds the definition of an invoked macro to the debugging output.

cadaniluk
  • 15,027
  • 2
  • 39
  • 67

1 Answers1

5

While the expressions are equal (besides quotes), their time of execution differs (owing to quotes).

In the first case test macro gets executed DURING macrosubstitution of the parent's test. So you experience a recursion: test inside test inside test and so on.

The second case makes the expression executed AFTERWARDS. So you don't have recursion. test after test after test.

This behaviour is very well described in the manual.

Section "16.3 Other incompatibilities":

In cases like this one, an interdiction for a macro to hold its own name would be a useless limitation. Of course, this leaves more rope for the GNU m4 user to hang himself!

akond
  • 15,865
  • 4
  • 35
  • 55