CVSROOT: /sources/m4
Module name: m4
Branch: branch-1_4
Changes by: Eric Blake <ericb> 06/10/19 16:12:46
Index: doc/m4.texinfo
===================================================================
RCS file: /sources/m4/m4/doc/m4.texinfo,v
retrieving revision 1.1.1.1.2.88
retrieving revision 1.1.1.1.2.89
diff -u -b -r1.1.1.1.2.88 -r1.1.1.1.2.89
--- doc/m4.texinfo 16 Oct 2006 13:15:32 -0000 1.1.1.1.2.88
+++ doc/m4.texinfo 19 Oct 2006 16:12:46 -0000 1.1.1.1.2.89
@@ -190,7 +190,9 @@
* Ifdef:: Testing if a macro is defined
* Ifelse:: If-else construct, or multibranch
-* Loops:: Loops and recursion in m4
+* Shift:: Recursion in @code{m4}
+* Forloop:: Iteration by counting
+* Foreach:: Iteration by list contents
How to debug macros and input
@@ -262,6 +264,8 @@
Correct version of some examples
* Improved exch:: Solution for @code{exch}
+* Improved forloop:: Solution for @code{forloop}
+* Improved foreach:: Solution for @code{foreach}
* Improved cleardivert:: Solution for @code{cleardivert}
* Improved fatal_error:: Solution for @code{fatal_error}
@@ -1913,7 +1917,9 @@
@menu
* Ifdef:: Testing if a macro is defined
* Ifelse:: If-else construct, or multibranch
-* Loops:: Loops and recursion in m4
+* Shift:: Recursion in @code{m4}
+* Forloop:: Iteration by counting
+* Foreach:: Iteration by list contents
@end menu
@node Ifdef
@@ -2042,8 +2048,8 @@
examples. A common use of @code{ifelse} is in macros implementing loops
of various kinds.
[EMAIL PROTECTED] Loops
[EMAIL PROTECTED] Loops and recursion
[EMAIL PROTECTED] Shift
[EMAIL PROTECTED] Recursion in @code{m4}
@cindex recursive macros
@cindex macros, recursive
@@ -2077,7 +2083,7 @@
An example of the use of @code{shift} is this macro:
@deffn Composite reverse (@dots{})
-Takes any number of arguments, and reverse their order.
+Takes any number of arguments, and reverses their order.
@end deffn
It is implemented as:
@@ -2096,7 +2102,70 @@
While not a very interesting macro, it does show how simple loops can be
made with @code{shift}, @code{ifelse} and recursion. It also shows
-that @code{shift} is usually used with @samp{$@@}.
+that @code{shift} is usually used with @samp{$@@}. Sometimes, a
+recursive algorithm requires adding quotes to each element:
+
[EMAIL PROTECTED] Composite quote (@dots{})
[EMAIL PROTECTED] Composite dquote (@dots{})
[EMAIL PROTECTED] Composite dquote_elt (@dots{})
+Takes any number of arguments, and adds quoting. With @code{quote},
+only one level of quoting is added, effectively removing whitespace
+after commas and turning multiple arguments into a single string. With
[EMAIL PROTECTED], two levels of quoting are added, one around each element,
+and one around the list. And with @code{dquote_elt}, two levels of
+quoting are added around each element.
[EMAIL PROTECTED] deffn
+
+An actual implementation of these three macros is distributed as
[EMAIL PROTECTED]@value{VERSION}/@/examples/@/quote.m4} in this package. First,
+let's examine their usage:
+
[EMAIL PROTECTED]
+include(`quote.m4')
[EMAIL PROTECTED]
+-quote-dquote-dquote_elt-
[EMAIL PROTECTED]
+-quote()-dquote()-dquote_elt()-
[EMAIL PROTECTED]'-`'-
+-quote(`1')-dquote(`1')-dquote_elt(`1')-
[EMAIL PROTECTED]'-`1'-
+-quote(`1', `2')-dquote(`1', `2')-dquote_elt(`1', `2')-
[EMAIL PROTECTED],2-`1',`2'-`1',`2'-
+define(`n', `$#')dnl
+-n(quote(`1', `2'))-n(dquote(`1', `2'))-n(dquote_elt(`1', `2'))-
[EMAIL PROTECTED]
+dquote(dquote_elt(`1', `2'))
[EMAIL PROTECTED]'',``2''
+dquote_elt(dquote(`1', `2'))
[EMAIL PROTECTED]',`2''
[EMAIL PROTECTED] example
+
+The last two lines show that when given two arguments, @code{dquote}
+results in one string, while @code{dquote_elt} results in two. Now,
+examine the implementation. Note that @code{quote} and
[EMAIL PROTECTED] make decisions based on their number of arguments, so
+that when called without arguments, they result in nothing instead of a
+quoted empty string; this is so that it is possible to distinquish
+between no arguments and an empty first argument. @code{dquote}, on the
+other hand, results in a string no matter what, since it is still
+possible to tell whether it was invoked without arguments based on the
+resulting string.
+
[EMAIL PROTECTED]
+undivert(`quote.m4')dnl
[EMAIL PROTECTED](`-1')
[EMAIL PROTECTED] quote(args) - convert args to single-quoted string
[EMAIL PROTECTED](`quote', `ifelse(`$#', `0', `', ``$*'')')
[EMAIL PROTECTED] dquote(args) - convert args to quoted list of quoted strings
[EMAIL PROTECTED](`dquote', ``$@@'')
[EMAIL PROTECTED] dquote_elt(args) - convert args to list of double-quoted
strings
[EMAIL PROTECTED](`dquote_elt', `ifelse(`$#', `0', `', `$#', `1', ```$1''',
[EMAIL PROTECTED] ```$1'',$0(shift($@@))')')
[EMAIL PROTECTED]'dnl
[EMAIL PROTECTED] example
+
[EMAIL PROTECTED] Forloop
[EMAIL PROTECTED] Iteration by counting
@cindex for loops
@cindex loops, counting
@@ -2142,35 +2211,36 @@
the first argument.
The macro @code{_forloop} expands the fourth argument once, and tests
-to see if it is finished. If it has not finished, it increments
-the iteration variable (using the predefined macro @code{incr},
[EMAIL PROTECTED]), and recurses.
+to see if the iterator has reached the final value. If it has not
+finished, it increments the iterator (using the predefined macro
[EMAIL PROTECTED], @pxref{Incr}), and recurses.
-Here is the actual implementation of @code{forloop}, distributed as
+Here is an actual implementation of @code{forloop}, distributed as
@[EMAIL PROTECTED]/@/examples/@/forloop.m4} in this package:
@example
-undivert(`forloop.m4')
+undivert(`forloop.m4')dnl
@result{}divert(`-1')
[EMAIL PROTECTED] forloop(var, from, to, stmt)
[EMAIL PROTECTED](`forloop',
[EMAIL PROTECTED] `pushdef(`$1', `$2')_forloop(`$1', `$2', `$3',
`$4')popdef(`$1')')
[EMAIL PROTECTED] forloop(var, from, to, stmt) - simple version
[EMAIL PROTECTED](`forloop', `pushdef(`$1', `$2')_forloop($@@)popdef(`$1')')
@result{}define(`_forloop',
[EMAIL PROTECTED] `$4`'ifelse($1, `$3', ,
[EMAIL PROTECTED] `define(`$1', incr($1))_forloop(`$1', `$2', `$3', `$4')')')
[EMAIL PROTECTED] `$4`'ifelse($1, `$3', `', `define(`$1',
incr($1))$0($@@)')')
@result{}divert`'dnl
[EMAIL PROTECTED]
@end example
-Notice the careful use of quotes. Only three macro arguments are
+Notice the careful use of quotes. Certain macro arguments are left
unquoted, each for its own reason. Try to find out @emph{why} these
-three arguments are left unquoted, and see what happens if they are
-quoted.
+arguments are left unquoted, and see what happens if they are quoted.
+(As presented, these two macros are useful but not very robust for
+general use. They lack even basic error handling for cases like
[EMAIL PROTECTED] less than @var{end}, @var{end} not numeric, or
[EMAIL PROTECTED] not being a macro name. See if you can improve these
+macros; or @pxref{Improved forloop, , Answers}).
+
[EMAIL PROTECTED] Foreach
[EMAIL PROTECTED] Iteration by list contents
-Now, even though these two macros are useful, they are still not robust
-enough for general use. They lack even basic error handling of cases
-like start value less than final value, and the first argument not being
-a name. Correcting these errors are left as an exercise to the reader.
+FIXME - Fill out this section.
@node Debugging
@chapter How to debug macros and input
@@ -3952,7 +4022,7 @@
@result{}300
@end example
-Using the @code{forloop} macro defined earlier (@pxref{Loops}), this
+Using the @code{forloop} macro defined earlier (@pxref{Forloop}), this
example shows how @code{format} can be used to produce tabular output.
@example
@@ -5202,6 +5272,8 @@
@menu
* Improved exch:: Solution for @code{exch}
+* Improved forloop:: Solution for @code{forloop}
+* Improved foreach:: Solution for @code{foreach}
* Improved cleardivert:: Solution for @code{cleardivert}
* Improved fatal_error:: Solution for @code{fatal_error}
@end menu
@@ -5224,6 +5296,54 @@
@result{}expansion text
@end example
[EMAIL PROTECTED] Improved forloop
[EMAIL PROTECTED] Solution for @code{forloop}
+
+The @code{forloop} macro (@pxref{Forloop}) as presented earlier can go
+into an infinite loop if given an iterator that is not parsed as a macro
+name. It does not do any sanity checking on its numeric bounds, and
+only permits decimal numbers for bounds. Here is an improved version,
+shipped as @[EMAIL PROTECTED]/@/examples/@/forloop2.m4}; this
+version also optimizes based on the fact that the starting bound does
+not need to be passed to the helper @code{_forloop}.
+
[EMAIL PROTECTED]
+undivert(`forloop2.m4')dnl
[EMAIL PROTECTED](`-1')
[EMAIL PROTECTED] forloop(var, from, to, stmt) - improved version:
[EMAIL PROTECTED] works even if VAR is not a strict macro name
[EMAIL PROTECTED] performs sanity check that FROM is larger than TO
[EMAIL PROTECTED] allows complex numerical expressions in TO and FROM
[EMAIL PROTECTED](`forloop', `ifelse(eval(`($3) >= ($2)'), `1',
[EMAIL PROTECTED] `pushdef(`$1', eval(`$2'))_forloop(`$1',
[EMAIL PROTECTED] eval(`$3'), `$4')popdef(`$1')')')
[EMAIL PROTECTED](`_forloop',
[EMAIL PROTECTED] `$3`'ifelse(indir(`$1'), `$2', `',
[EMAIL PROTECTED] `define(`$1', incr(indir(`$1')))$0($@@)')')
[EMAIL PROTECTED]'dnl
+include(`forloop2.m4')
[EMAIL PROTECTED]
+forloop(`i', `2', `1', `no iteration occurs')
[EMAIL PROTECTED]
+forloop(`', `1', `2', ` odd iterator name')
[EMAIL PROTECTED] odd iterator name odd iterator name
+forloop(`i', `5 + 5', `0xc', ` 0x`'eval(i, `16')')
[EMAIL PROTECTED] 0xa 0xb 0xc
+forloop(`i', `a', `b', `non-numeric bounds')
[EMAIL PROTECTED]:stdin:6: bad expression in eval (bad input): (b) >= (a)
[EMAIL PROTECTED]
[EMAIL PROTECTED] example
+
+Of course, it is possible to make even more improvements, such as
+adding an optional step argument, or allowing iteration through
+descending sequences. @acronym{GNU} Autoconf provides some of these
+additional bells and whistles in its @code{m4_for} macro.
+
[EMAIL PROTECTED] Improved foreach
[EMAIL PROTECTED] Solution for @code{foreach}
+
+FIXME - add content.
+
@node Improved cleardivert
@section Solution for @code{cleardivert}