m4: Stacks

 
 6.6 Working with definition stacks
 ==================================
 
 Thanks to 'pushdef', manipulation of a stack is an intrinsic operation
 in 'm4'.  Normally, only the topmost definition in a stack is important,
 but sometimes, it is desirable to manipulate the entire definition
 stack.
 
  -- Composite: stack_foreach (MACRO, ACTION)
  -- Composite: stack_foreach_lifo (MACRO, ACTION)
      For each of the 'pushdef' definitions associated with MACRO, invoke
      the macro ACTION with a single argument of that definition.
      'stack_foreach' visits the oldest definition first, while
      'stack_foreach_lifo' visits the current definition first.  ACTION
      should not modify or dereference MACRO.  There are a few special
      macros, such as 'defn', which cannot be used as the MACRO
      parameter.
 
    A sample implementation of these macros is distributed in the file
 'm4-1.4.18/examples/stack.m4'.
 
      $ m4 -I examples
      include(`stack.m4')
      =>
      pushdef(`a', `1')pushdef(`a', `2')pushdef(`a', `3')
      =>
      define(`show', ``$1'
      ')
      =>
      stack_foreach(`a', `show')dnl
      =>1
      =>2
      =>3
      stack_foreach_lifo(`a', `show')dnl
      =>3
      =>2
      =>1
 
    Now for the implementation.  Note the definition of a helper macro,
 '_stack_reverse', which destructively swaps the contents of one stack of
 definitions into the reverse order in the temporary macro 'tmp-$1'.  By
 calling the helper twice, the original order is restored back into the
 macro '$1'; since the operation is destructive, this explains why '$1'
 must not be modified or dereferenced during the traversal.  The caller
 can then inject additional code to pass the definition currently being
 visited to '$2'.  The choice of helper names is intentional; since '-'
 is not valid as part of a macro name, there is no risk of conflict with
 a valid macro name, and the code is guaranteed to use 'defn' where
 necessary.  Finally, note that any macro used in the traversal of a
 'pushdef' stack, such as 'pushdef' or 'defn', cannot be handled by
 'stack_foreach', since the macro would temporarily be undefined during
 the algorithm.
 
      $ m4 -I examples
      undivert(`stack.m4')dnl
      =>divert(`-1')
      =># stack_foreach(macro, action)
      =># Invoke ACTION with a single argument of each definition
      =># from the definition stack of MACRO, starting with the oldest.
      =>define(`stack_foreach',
      =>`_stack_reverse(`$1', `tmp-$1')'dnl
      =>`_stack_reverse(`tmp-$1', `$1', `$2(defn(`$1'))')')
      =># stack_foreach_lifo(macro, action)
      =># Invoke ACTION with a single argument of each definition
      =># from the definition stack of MACRO, starting with the newest.
      =>define(`stack_foreach_lifo',
      =>`_stack_reverse(`$1', `tmp-$1', `$2(defn(`$1'))')'dnl
      =>`_stack_reverse(`tmp-$1', `$1')')
      =>define(`_stack_reverse',
      =>`ifdef(`$1', `pushdef(`$2', defn(`$1'))$3`'popdef(`$1')$0($@)')')
      =>divert`'dnl