Next: , Previous: Improved exch, Up: Answers


17.2 Solution for forloop

The forloop macro (see Forloop) as presented earlier can go into an infinite loop if given an iterator that is not parsed as a macro name. It does not do any sanity checking on its numeric bounds, and only permits decimal numbers for bounds. Here is an improved version, shipped as m4-1.4.8/examples/forloop2.m4; this version also optimizes based on the fact that the starting bound does not need to be passed to the helper _forloop.

     undivert(`forloop2.m4')dnl
     =>divert(`-1')
     =># forloop(var, from, to, stmt) - improved version:
     =>#   works even if VAR is not a strict macro name
     =>#   performs sanity check that FROM is larger than TO
     =>#   allows complex numerical expressions in TO and FROM
     =>define(`forloop', `ifelse(eval(`($3) >= ($2)'), `1',
     =>  `pushdef(`$1', eval(`$2'))_forloop(`$1',
     =>    eval(`$3'), `$4')popdef(`$1')')')
     =>define(`_forloop',
     =>  `$3`'ifelse(indir(`$1'), `$2', `',
     =>    `define(`$1', incr(indir(`$1')))$0($@)')')
     =>divert`'dnl
     include(`forloop2.m4')
     =>
     forloop(`i', `2', `1', `no iteration occurs')
     =>
     forloop(`', `1', `2', ` odd iterator name')
     => odd iterator name odd iterator name
     forloop(`i', `5 + 5', `0xc', ` 0x`'eval(i, `16')')
     => 0xa 0xb 0xc
     forloop(`i', `a', `b', `non-numeric bounds')
     error-->m4:stdin:6: bad expression in eval (bad input): (b) >= (a)
     =>

Of course, it is possible to make even more improvements, such as adding an optional step argument, or allowing iteration through descending sequences. GNU Autoconf provides some of these additional bells and whistles in its m4_for macro.