m4-patches
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: documentation ideas from autoconf


From: Eric Blake
Subject: Re: documentation ideas from autoconf
Date: Thu, 18 Dec 2008 17:37:50 +0000 (UTC)
User-agent: Loom/3.14 (http://gmane.org/)

Eric Blake <ebb9 <at> byu.net> writes:

> 
> I'm committing this to branch-1.6 and master; it documents some slick m4 
tricks 
> learned recently in autoconf's m4sugar.

And in trying to backport it to branch-1.4, I noticed a typo in stack.m4:

> +
> address@hidden Composite stack_foreach (@var{macro}, @var{action})
> address@hidden Composite stack_foreach_lifo (@var{macro}, @var{action})

> +++ b/examples/stack.m4
> @@ -0,0 +1,16 @@
> +divert(`-1')
> +# stack_foreach(action, macro)

as well as a limitation in M4 1.4.x that has already been fixed in branch-1.6 - 
passing a builtin token through curry flattens to the empty string with older 
m4:

curry(`define',`mylen')(defn(`len'))
mylen(`abc') => `' (not the expected `3')

Fortunately, autoconf had already resolved the issue, as a side effect of 
writing a more efficient copy algorithm.  So I'm applying this followup to 
branch-1.6 and master, then backporting the series of doc patches to branch-1.4:

From: Eric Blake <address@hidden>
Date: Thu, 18 Dec 2008 10:28:06 -0700
Subject: [PATCH] Deal with M4 1.4.x limitation on builtin tokens.

* doc/m4.texinfo (Composition): Mention limitation on curry.
(Improved copy): New node.
(Stacks): Fix typo.
* examples/stack.m4: Likewise.
* examples/stack_sep.m4: New file.
* examples/Makefile.am (EXTRA_DIST): Distribute it.

Signed-off-by: Eric Blake <address@hidden>
---
 ChangeLog             |   10 ++++
 doc/m4.texinfo        |  113 +++++++++++++++++++++++++++++++++++++++++++++++-
 examples/Makefile.am  |    1 +
 examples/stack.m4     |    4 +-
 examples/stack_sep.m4 |   17 +++++++
 5 files changed, 140 insertions(+), 5 deletions(-)
 create mode 100644 examples/stack_sep.m4

diff --git a/ChangeLog b/ChangeLog
index 63a0516..895d17a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2008-12-18  Eric Blake  <address@hidden>
+
+       Deal with M4 1.4.x limitation on builtin tokens.
+       * doc/m4.texinfo (Composition): Mention limitation on curry.
+       (Improved copy): New node.
+       (Stacks): Fix typo.
+       * examples/stack.m4: Likewise.
+       * examples/stack_sep.m4: New file.
+       * examples/Makefile.am (EXTRA_DIST): Distribute it.
+
 2008-12-10  Eric Blake  <address@hidden>
 
        Double size of temp file cache.
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 7c6bf56..50d0ace 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -272,6 +272,7 @@ Top
 * Improved exch::               Solution for @code{exch}
 * Improved forloop::            Solution for @code{forloop}
 * Improved foreach::            Solution for @code{foreach}
+* Improved copy::               Solution for @code{copy}
 * Improved m4wrap::             Solution for @code{m4wrap}
 * Improved cleardivert::        Solution for @code{cleardivert}
 * Improved capitalize::         Solution for @code{capitalize}
@@ -3742,13 +3743,13 @@ Stacks
 $ @kbd{m4 -I examples}
 undivert(`stack.m4')dnl
 @result{}divert(`-1')
address@hidden stack_foreach(action, macro)
address@hidden stack_foreach(macro, action)
 @result{}# Invoke ACTION with a single argument of each definition
 @result{}# from the definition stack of MACRO, starting with the oldest.
 @result{}define(`stack_foreach',
 @result{}`_stack_reverse(`$1', `tmp-$1')'dnl
 @result{}`_stack_reverse(`tmp-$1', `$1', `$2(defn(`$1'))')')
address@hidden stack_foreach_lifo(action, macro)
address@hidden stack_foreach_lifo(macro, action)
 @result{}# Invoke ACTION with a single argument of each definition
 @result{}# from the definition stack of MACRO, starting with the newest.
 @result{}define(`stack_foreach_lifo',
@@ -3885,6 +3886,23 @@ Composition
 @result{}divert`'dnl
 @end example
 
+Unfortunately, with M4 1.4.x, @code{curry} is unable to handle builtin
+tokens, which are silently flattened to the empty string when passed
+through another text macro.  The following example demonstrates a usage
+of @code{curry} that works in M4 1.6, but is not portable to earlier
+versions:
+
address@hidden examples
address@hidden
+$ @kbd{m4 -I examples}
+include(`curry.m4')
address@hidden
+curry(`define', `mylen')(defn(`len'))
address@hidden
+mylen(`abc')
address@hidden
address@hidden example
+
 @cindex renaming macros
 @cindex copying macros
 @cindex macros, copying
@@ -3900,7 +3918,10 @@ Composition
 via this macro.
 @end deffn
 
-The implementation is relatively straightforward:
+The implementation is relatively straightforward (although since it uses
address@hidden, it is unable to copy builtin macros when used with M4
+1.4.x.  See if you can design a portable version that works across all
+M4 versions, or @pxref{Improved copy, , Answers}).
 
 @comment examples
 @example
@@ -8101,6 +8122,7 @@ Answers
 * Improved exch::               Solution for @code{exch}
 * Improved forloop::            Solution for @code{forloop}
 * Improved foreach::            Solution for @code{foreach}
+* Improved copy::               Solution for @code{copy}
 * Improved m4wrap::             Solution for @code{m4wrap}
 * Improved cleardivert::        Solution for @code{cleardivert}
 * Improved capitalize::         Solution for @code{capitalize}
@@ -8709,6 +8731,91 @@ Improved foreach
 
 @end ignore
 
address@hidden Improved copy
address@hidden Solution for @code{copy}
+
+The macro @code{copy} presented above works with M4 1.6 and newer, but
+is unable to handle builtin tokens with M4 1.4.x, because it tries to
+pass the builtin token through the macro @code{curry}, where it is
+silently flattened to an empty string (@pxref{Composition}).  Rather
+than using the problematic @code{curry} to work around the limitation
+that @code{stack_foreach} expects to invoke a macro that takes exactly
+one argument, we can write a new macro that lets us form the exact
+two-argument @code{pushdef} call sequence needed, so that we are no
+longer passing a builtin token through a text macro.
+
address@hidden Composite stack_foreach_sep (@var{macro}, @var{pre}, @var{post}, 
@
+  @var{sep})
address@hidden Composite stack_foreach_sep_lifo (@var{macro}, @var{pre}, @
+  @var{post}, @var{sep})
+For each of the @code{pushdef} definitions associated with @var{macro},
+expand the sequence @address@hidden'definition`'@var{post}}.
+Additionally, expand @var{sep} between definitions.
address@hidden visits the oldest definition first, while
address@hidden visits the current definition first.  The
+expansion may dereference @var{macro}, but should not modify it.  There
+are a few special macros, such as @code{defn}, which cannot be used as
+the @var{macro} parameter.
address@hidden deffn
+
+Note that @code{stack_foreach(address@hidden', address@hidden')} is
+equivalent to @code{stack_foreach_sep(address@hidden', address@hidden(',
+`)')}.  By supplying explicit parentheses, split among the @var{pre} and
address@hidden arguments to @code{stack_foreach_sep}, it is now possible to
+construct macro calls with more than one argument, without passing
+builtin tokens through a macro call.  It is likewise possible to
+directly reference the stack definitions without a macro call, by
+leaving @var{pre} and @var{post} empty.  The new macro also adds a
+separator that is only output after the first iteration of the helper
address@hidden, implemented by prepending the original
address@hidden to @var{pre} and omitting a @var{sep} argument in subsequent
+iterations.  As an added bonus, using @code{stack_foreach_sep} to
+implement @code{copy} performs fewer macro invocations.  The improved
+stack walking macros are available in
address@hidden@value{VERSION}/@/examples/@/stack_sep.m4}:
+
address@hidden examples
address@hidden
+$ @kbd{m4 -I examples}
+include(`stack_sep.m4')
address@hidden
+define(`copy', `ifdef(`$2', `errprint(`$2 already defined
+')m4exit(`1')',
+   `stack_foreach_sep(`$1', `pushdef(`$2',', `)')')')dnl
+pushdef(`a', `1')pushdef(`a', defn(`divnum'))
address@hidden
+copy(`a', `b')
address@hidden
+b
address@hidden
+popdef(`b')
address@hidden
+b
address@hidden
+pushdef(`c', `1')pushdef(`c', `2')
address@hidden
+stack_foreach_sep_lifo(`c', `', `', `, ')
address@hidden, 1
+undivert(`stack_sep.m4')dnl
address@hidden(`-1')
address@hidden stack_foreach_sep(macro, pre, post, sep)
address@hidden Invoke PRE`'defn`'POST with a single argument of each definition
address@hidden from the definition stack of MACRO, starting with the oldest, and
address@hidden separated by SEP between definitions.
address@hidden(`stack_foreach_sep',
address@hidden(`$1', `tmp-$1')'dnl
address@hidden(`tmp-$1', `$1', `$2`'defn(`$1')$3', `$4')')
address@hidden stack_foreach_sep_lifo(macro, pre, post, sep)
address@hidden Like stack_foreach_sep, but starting with the newest definition.
address@hidden(`stack_foreach_sep_lifo',
address@hidden(`$1', `tmp-$1', `$2`'defn(`$1')$3', `$4')'dnl
address@hidden(`tmp-$1', `$1')')
address@hidden(`_stack_reverse_sep',
address@hidden(`$1', `pushdef(`$2', defn(`$1'))$3`'popdef(`$1')$0(
address@hidden  `$1', `$2', `$4`'$3')')')
address@hidden'dnl
address@hidden example
+
 @node Improved m4wrap
 @section Solution for @code{m4wrap}
 
diff --git a/examples/Makefile.am b/examples/Makefile.am
index 1a97347..0db3a88 100644
--- a/examples/Makefile.am
+++ b/examples/Makefile.am
@@ -58,6 +58,7 @@ quote.m4 \
 regexp.m4 \
 reverse.m4 \
 stack.m4 \
+stack_sep.m4 \
 stackovf.sh \
 sync-lines.m4 \
 sysv-args.m4 \
diff --git a/examples/stack.m4 b/examples/stack.m4
index ae3c48e..c1b9833 100644
--- a/examples/stack.m4
+++ b/examples/stack.m4
@@ -1,11 +1,11 @@
 divert(`-1')
-# stack_foreach(action, macro)
+# 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(action, macro)
+# 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',
diff --git a/examples/stack_sep.m4 b/examples/stack_sep.m4
new file mode 100644
index 0000000..b11bc83
--- /dev/null
+++ b/examples/stack_sep.m4
@@ -0,0 +1,17 @@
+divert(`-1')
+# stack_foreach_sep(macro, pre, post, sep)
+# Invoke PRE`'defn`'POST with a single argument of each definition
+# from the definition stack of MACRO, starting with the oldest, and
+# separated by SEP between definitions.
+define(`stack_foreach_sep',
+`_stack_reverse_sep(`$1', `tmp-$1')'dnl
+`_stack_reverse_sep(`tmp-$1', `$1', `$2`'defn(`$1')$3', `$4')')
+# stack_foreach_sep_lifo(macro, pre, post, sep)
+# Like stack_foreach_sep, but starting with the newest definition.
+define(`stack_foreach_sep_lifo',
+`_stack_reverse_sep(`$1', `tmp-$1', `$2`'defn(`$1')$3', `$4')'dnl
+`_stack_reverse_sep(`tmp-$1', `$1')')
+define(`_stack_reverse_sep',
+`ifdef(`$1', `pushdef(`$2', defn(`$1'))$3`'popdef(`$1')$0(
+  `$1', `$2', `$4`'$3')')')
+divert`'dnl
-- 
1.6.0.4








reply via email to

[Prev in Thread] Current Thread [Next in Thread]