2

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                    
NoComprende
  • 731
  • 4
  • 14

1 Answers1

1

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
William Pursell
  • 204,365
  • 48
  • 270
  • 300
  • Thanks William that clears it up for me. A simpler example makes it clearer. Setting define(`xx',`ifelse($#,1,$1,incr($2))') and calling xx(8) shows the error. – NoComprende Sep 25 '21 at 12:38