linuxgnum4

GNU M4 seems to access unnecessary value in ifelse


I'm trying out the m4 CLI on linux and trying to create a for(begin, end, step) macro that will print out a comma separated list of numbers in the given range. I also want it to support a default step of 1. I tried the following

[tom@sp4 ~]$ m4
define(`for',`ifelse($#,2,`for($1,$2,1)',eval($1+$3>$2),1,$1,`$1, for(eval($1+$3),$2,$3)')')

for(3,9)
m4:stdin:3: bad expression in eval: 3+>9
3, 4, 5, 6, 7, 8, 9

While it works OK I can't understand why I get the error message as $3 is only blank on first pass. Why is it even bothering to read the eval($1+$3>$2) when $#==2?

EDIT: Using the information William gave me in his answer I've came up with the macro below. It accepts 0 to 3 parameters and allows count down as well as up. I have learned a lot from messing with this one example.

[tom@sp4 ~]$ m4
define(`for',
    `ifelse(
        $#,0,``for'',
        eval($#==1 && $1+0>0),1,`for(1,$1,1)',
        $#,1,,
        $#,2,`for($1,$2,ifelse(eval($1+0>$2+0),1,-1,1))',
        eval($3+0==0 || $3+0>0 && $1+0>$2+0 || $3+0<0 && $1+0<$2+0),1,,
        eval($1+0+($3+0)ifelse(eval($3+0<0),1,<,>)$2+0),1,$1,
        `$1, for(eval($1+$3),$2,$3)'dnl
    )'dnl
)


for
for
for(0)

for(5)
1, 2, 3, 4, 5                
for(5,-23,-5)
5, 0, -5, -10, -15, -20                    
for(5,9)
5, 6, 7, 8, 9                
for(6,1)
6, 5, 4, 3, 2, 1                    

Solution

  • When m4 encounters foo(3,9), it expands that to the text of the ifelse as defined in the macro. In order to invoke ifelse, it has to pass arguments to it. To determine those arguments, it has to expand eval. Hence the error message.

    You can avoid the error message with:

    define(`for',
    `ifelse(
            `$#', `2', `for(`$1', `$2', `1')',
            eval(`$1' + ifelse(`$3', `', `0', `1') > `$2'), `1', `$1',
            `$1, for(eval(`$1' + `$3'), `$2', `$3')'dnl
    )')dnl