manpagez: man pages & more
info m4
Home | html | info | man

File: m4.info,  Node: Stacks,  Next: Composition,  Prev: Foreach,  Up: Conditionals

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.20/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

© manpagez.com 2000-2025
Individual documents may contain additional copyright information.