Next: Improved foreach, Previous: Improved exch, Up: Answers
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.