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