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