DOC HOME SITE MAP MAN PAGES GNU INFO SEARCH
 

(m4.info.gz) Loops

Info Catalog (m4.info.gz) Ifelse (m4.info.gz) Conditionals
 
 5.3 Loops and recursion
 =======================
 
 There is no direct support for loops in `m4', but macros can be
 recursive.  There is no limit on the number of recursion levels, other
 than those enforced by your hardware and operating system.
 
    Loops can be programmed using recursion and the conditionals
 described previously.
 
    There is a builtin macro, `shift', which can, among other things, be
 used for iterating through the actual arguments to a macro:
 
  -- Builtin: shift (ARG1, ...)
      Takes any number of arguments, and expands to all its arguments
      except ARG1, separated by commas, with each argument quoted.
 
      The macro `shift' is recognized only with parameters.
 
      shift
      =>shift
      shift(`bar')
      =>
      shift(`foo', `bar', `baz')
      =>bar,baz
 
    An example of the use of `shift' is this macro:
 
  -- Composite: reverse (...)
      Takes any number of arguments, and reverse their order.
 
    It is implemented as:
 
      define(`reverse', `ifelse(`$#', `0', , `$#', `1', ``$1'',
                                `reverse(shift($@)), `$1'')')
      =>
      reverse
      =>
      reverse(`foo')
      =>foo
      reverse(`foo', `bar', `gnats', `and gnus')
      =>and gnus, gnats, bar, foo
 
    While not a very interesting macro, it does show how simple loops
 can be made with `shift', `ifelse' and recursion.  It also shows that
 `shift' is usually used with `$@'.
 
    Here is an example of a loop macro that implements a simple for loop.
 
  -- Composite: forloop (ITERATOR, START, END, TEXT)
      Takes the name in ITERATOR, which must be a valid macro name, and
      successively assign it each integer value from START to END,
      inclusive.  For each assignment to ITERATOR, append TEXT to the
      expansion of the `forloop'.  TEXT may refer to ITERATOR.  Any
      definition of ITERATOR prior to this invocation is restored.
 
    It can, for example, be used for simple counting:
 
      include(`forloop.m4')
      =>
      forloop(`i', `1', `8', `i ')
      =>1 2 3 4 5 6 7 8
 
    For-loops can be nested, like:
 
      include(`forloop.m4')
      =>
      forloop(`i', `1', `4', `forloop(`j', `1', `8', ` (i, j)')
      ')
      => (1, 1) (1, 2) (1, 3) (1, 4) (1, 5) (1, 6) (1, 7) (1, 8)
      => (2, 1) (2, 2) (2, 3) (2, 4) (2, 5) (2, 6) (2, 7) (2, 8)
      => (3, 1) (3, 2) (3, 3) (3, 4) (3, 5) (3, 6) (3, 7) (3, 8)
      => (4, 1) (4, 2) (4, 3) (4, 4) (4, 5) (4, 6) (4, 7) (4, 8)
      =>
 
    The implementation of the `forloop' macro is fairly straightforward.
 The `forloop' macro itself is simply a wrapper, which saves the
 previous definition of the first argument, calls the internal macro
 `_forloop', and re-establishes the saved definition of the first
 argument.
 
    The macro `_forloop' expands the fourth argument once, and tests to
 see if it is finished.  If it has not finished, it increments the
 iteration variable (using the predefined macro `incr',  Incr),
 and recurses.
 
    Here is the actual implementation of `forloop', distributed as
 `examples/forloop.m4' in this package:
 
      undivert(`forloop.m4')
      =>divert(`-1')
      =># forloop(var, from, to, stmt)
      =>define(`forloop',
      =>  `pushdef(`$1', `$2')_forloop(`$1', `$2', `$3', `$4')popdef(`$1')')
      =>define(`_forloop',
      =>  `$4`'ifelse($1, `$3', ,
      =>    `define(`$1', incr($1))_forloop(`$1', `$2', `$3', `$4')')')
      =>divert`'dnl
      =>
 
    Notice the careful use of quotes.  Only three macro arguments are
 unquoted, each for its own reason.  Try to find out _why_ these three
 arguments are left unquoted, and see what happens if they are quoted.
 
    Now, even though these two macros are useful, they are still not
 robust enough for general use. They lack even basic error handling of
 cases like start value less than final value, and the first argument
 not being a name.  Correcting these errors are left as an exercise to
 the reader.
 
Info Catalog (m4.info.gz) Ifelse (m4.info.gz) Conditionals
automatically generated byinfo2html