m4: Forloop

1 
1 6.4 Iteration by counting
1 =========================
1 
1 Here is an example of a loop macro that implements a simple for loop.
1 
1  -- Composite: forloop (ITERATOR, START, END, TEXT)
1      Takes the name in ITERATOR, which must be a valid macro name, and
1      successively assign it each integer value from START to END,
1      inclusive.  For each assignment to ITERATOR, append TEXT to the
1      expansion of the 'forloop'.  TEXT may refer to ITERATOR.  Any
1      definition of ITERATOR prior to this invocation is restored.
1 
1    It can, for example, be used for simple counting:
1 
1      $ m4 -I examples
1      include(`forloop.m4')
1      =>
1      forloop(`i', `1', `8', `i ')
1      =>1 2 3 4 5 6 7 8 
1 
1    For-loops can be nested, like:
1 
1      $ m4 -I examples
1      include(`forloop.m4')
1      =>
1      forloop(`i', `1', `4', `forloop(`j', `1', `8', ` (i, j)')
1      ')
1      => (1, 1) (1, 2) (1, 3) (1, 4) (1, 5) (1, 6) (1, 7) (1, 8)
1      => (2, 1) (2, 2) (2, 3) (2, 4) (2, 5) (2, 6) (2, 7) (2, 8)
1      => (3, 1) (3, 2) (3, 3) (3, 4) (3, 5) (3, 6) (3, 7) (3, 8)
1      => (4, 1) (4, 2) (4, 3) (4, 4) (4, 5) (4, 6) (4, 7) (4, 8)
1      =>
1 
1    The implementation of the 'forloop' macro is fairly straightforward.
1 The 'forloop' macro itself is simply a wrapper, which saves the previous
1 definition of the first argument, calls the internal macro '_forloop',
1 and re-establishes the saved definition of the first argument.
1 
1    The macro '_forloop' expands the fourth argument once, and tests to
1 see if the iterator has reached the final value.  If it has not
1 finished, it increments the iterator (using the predefined macro 'incr',
1 ⇒Incr), and recurses.
1 
1    Here is an actual implementation of 'forloop', distributed as
1 'm4-1.4.18/examples/forloop.m4' in this package:
1 
1      $ m4 -I examples
1      undivert(`forloop.m4')dnl
1      =>divert(`-1')
1      =># forloop(var, from, to, stmt) - simple version
1      =>define(`forloop', `pushdef(`$1', `$2')_forloop($@)popdef(`$1')')
1      =>define(`_forloop',
1      =>       `$4`'ifelse($1, `$3', `', `define(`$1', incr($1))$0($@)')')
1      =>divert`'dnl
1 
1    Notice the careful use of quotes.  Certain macro arguments are left
1 unquoted, each for its own reason.  Try to find out _why_ these
1 arguments are left unquoted, and see what happens if they are quoted.
1 (As presented, these two macros are useful but not very robust for
1 general use.  They lack even basic error handling for cases like START
1 less than END, END not numeric, or ITERATOR not being a macro name.  See
1 if you can improve these macros; or ⇒Answers Improved forloop.).
1