[Top][All Lists]
[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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- Re: documentation ideas from autoconf,
Eric Blake <=