autoconf-patches
[Top][All Lists]
Advanced

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

Re: document m4_foreach*/AC_FOREACH


From: Ralf Wildenhues
Subject: Re: document m4_foreach*/AC_FOREACH
Date: Thu, 16 Feb 2006 01:22:39 +0100
User-agent: Mutt/1.5.9i

Hi Paul,

Thanks for the review!

* Paul Eggert wrote on Wed, Feb 15, 2006 at 06:03:30AM CET:
> Ralf Wildenhues <address@hidden> writes:
> 
> > The following macros allow to implement loops in m4.
> 
> Please remove "allow to", and change "m4" to "M4".

Done.

[ regarding m4_for ]
> > @var{step} may be @samp{+1}, or @samp{-1}.
> 
> should mention that it defaults to +1
> 
> > If it is given, it has to match the order of the limits.
> 
> You can't iterate from 1 to 0 step +1?

Correct.  Iterating from 1 to 0 step +1 will invoke an m4 assertion.

> If so, this should be mentioned; if not then the point needs
> clarification.

Your comment made me look again.  First, I previously just misunderstood
the macro: step may actually be any integer, but needs to point in the
direction of (last - first).  This is enforced by the macro.  But also
the difference (last - first) had to be a multiple of step, otherwise m4
would iterate until you run out of memory.  :-/

So here's an updated patch which rewrites m4_for to fix that, adds tests,
and the fixed and adjusted documentation, and a couple of typos found on
the way.

> Other than that, it looks good; please install.

I'll wait a couple of days before installing the patch below.  It quotes
consistently.  Its result should not depend on C89 inexact negative
integer division truncation mode.  It may cause havoc if (last - first)
or (first - last) overflows though, but so does any code that uses
m4_cmp (and did the previous code).  To be fixed next.

Cheers,
Ralf

        * doc/autoconf.texi (Looping constructs): New node, to
        document m4_for, m4_foreach, m4_foreach_w, and mention
        obsolete AC_FOREACH.
        (Obsolete Macros): Document AC_FOREACH.
        * lib/m4sugar/m4sugar.m4 (_m4_for): Fix declaration comment.
        * tests/m4sugar.at: New test for m4_for, m4_foreach, and
        m4_foreach_w.

Index: doc/autoconf.texi
===================================================================
RCS file: /cvsroot/autoconf/autoconf/doc/autoconf.texi,v
retrieving revision 1.949
diff -u -r1.949 autoconf.texi
--- doc/autoconf.texi   15 Feb 2006 07:00:29 -0000      1.949
+++ doc/autoconf.texi   16 Feb 2006 00:02:21 -0000
@@ -437,6 +437,7 @@
 Programming in M4sugar
 
 * Redefined M4 Macros::         M4 builtins changed in M4sugar
+* Looping constructs::          Iteration in M4
 * Evaluation Macros::           More quotation and evaluation control
 * Forbidden Patterns::          Catching unexpanded macros
 
@@ -8781,6 +8782,7 @@
 
 @menu
 * Redefined M4 Macros::         M4 builtins changed in M4sugar
+* Looping constructs::          Iteration in M4
 * Evaluation Macros::           More quotation and evaluation control
 * Forbidden Patterns::          Catching unexpanded macros
 @end menu
@@ -8897,6 +8899,48 @@
 to recover the behavior of the builtin.
 @end defmac
 
+
+
address@hidden Looping constructs
address@hidden Looping constructs
+
+The following macros implement loops in M4.
+
address@hidden m4_for (@var{var}, @var{first}, @var{last}, @ovar{step}, 
@var{expression})
address@hidden
+Loop over the numeric values between @var{first} and @var{last}
+including bounds by increments of @var{step}.  For each iteration,
+expand @var{expression} with the numeric value assigned to @var{var}.
+If @var{step} is omitted, it defaults to @samp{1} or @samp{-1} depending
+on the order of the limits.  If given, @var{step} has to match this
+order.
address@hidden defmac
+
address@hidden m4_foreach (@var{var}, @var{list}, @var{expression})
address@hidden
+Loop over the comma-separated m4 list @var{list}, assigning each value
+to @var{var}, and expand @var{expression}.  The following example will
+output two lines:
+
address@hidden
+m4_foreach([myvar], [[foo], [bar, baz]],
+           [echo myvar
+])
+
address@hidden example
address@hidden defmac
+
address@hidden m4_foreach_w (@var{var}, @var{list}, @var{expression})
address@hidden
+Loop over the whitespace-separated list @var{list}, assigning each value
+to @var{var}, and expand @var{expression}.
+
+The deprecated macro @code{AC_FOREACH} is an alias of
address@hidden
address@hidden defmac
+
+
+
 @node Evaluation Macros
 @subsection Evaluation Macros
 
@@ -14735,6 +14779,11 @@
 @code{AC_PATH_XTRA}
 @end defmac
 
address@hidden AC_FOREACH
address@hidden
address@hidden
address@hidden defmac
+
 @defmac AC_FUNC_CHECK
 @acindex{FUNC_CHECK}
 @code{AC_CHECK_FUNC}
@@ -15955,7 +16004,7 @@
 this scheme helps supporting more languages than plain C and C++.
 @end itemize
 
-In addition to the change of syntax, the philosphy has changed too:
+In addition to the change of syntax, the philosophy has changed too:
 while emphasis was put on speed at the expense of accuracy, today's
 Autoconf promotes accuracy of the testing framework at, address@hidden, the
 expense of speed.
Index: lib/m4sugar/m4sugar.m4
===================================================================
RCS file: /cvsroot/autoconf/autoconf/lib/m4sugar/m4sugar.m4,v
retrieving revision 2.96
diff -u -r2.96 m4sugar.m4
--- lib/m4sugar/m4sugar.m4      11 Jan 2006 08:05:55 -0000      2.96
+++ lib/m4sugar/m4sugar.m4      16 Feb 2006 00:02:21 -0000
@@ -568,21 +568,26 @@
 
 # m4_for(VARIABLE, FIRST, LAST, [STEP = +/-1], EXPRESSION)
 # --------------------------------------------------------
-# Expand EXPRESSION defining VARIABLE to FROM, FROM + 1, ..., TO.
-# Both limits are included, and bounds are checked for consistency.
+# Expand EXPRESSION defining VARIABLE to FROM, FROM + STEP, ..., up to
+# the last value in the interval [FIRST, LAST].  Both limits are
+# included, and STEP is checked for consistency, or set consistently.
 m4_define([m4_for],
-[m4_case(m4_sign(m4_eval($3 - $2)),
-        1, [m4_assert(m4_sign(m4_default($4, 1)) == 1)],
-       -1, [m4_assert(m4_sign(m4_default($4, -1)) == -1)])dnl
-m4_pushdef([$1], [$2])dnl
-m4_if(m4_eval([$3 > $2]), 1,
-      [_m4_for([$1], [$3], m4_default([$4], 1), [$5])],
-      [_m4_for([$1], [$3], m4_default([$4], -1), [$5])])dnl
+[m4_pushdef([$1], [$2])dnl
+m4_case(m4_cmp([$3], [$2]),
+        1, [m4_pushdef([_m4_step], m4_default([$4], 1))dnl
+m4_assert(m4_sign(_m4_step) == 1)dnl
+_m4_for([$1], m4_eval(([$3 - $2]) / _m4_step * _m4_step + [$2]), _m4_step, 
[$5])],
+       -1, [m4_pushdef([_m4_step], m4_default([$4], -1))dnl
+m4_assert(m4_sign(_m4_step) == -1)dnl
+_m4_for([$1], m4_eval(([$2 - $3]) / -(_m4_step) * _m4_step + [$2]), _m4_step, 
[$5])],
+        0, [m4_pushdef([_m4_step], [])dnl
+$5])[]dnl
+m4_popdef([_m4_step])dnl
 m4_popdef([$1])])
 
 
-# _m4_for(VARIABLE, FIRST, LAST, STEP, EXPRESSION)
-# ------------------------------------------------
+# _m4_for(VARIABLE, LAST, STEP, EXPRESSION)
+# -----------------------------------------
 # Core of the loop, no consistency checks.
 m4_define([_m4_for],
 [$4[]dnl
Index: tests/m4sugar.at
===================================================================
RCS file: /cvsroot/autoconf/autoconf/tests/m4sugar.at,v
retrieving revision 1.28
diff -u -r1.28 m4sugar.at
--- tests/m4sugar.at    14 May 2005 07:00:40 -0000      1.28
+++ tests/m4sugar.at    16 Feb 2006 00:02:21 -0000
@@ -2,7 +2,7 @@
 
 AT_BANNER([M4sugar.])
 
-# Copyright (C) 2000, 2001, 2002, 2005 Free Software Foundation, Inc.
+# Copyright (C) 2000, 2001, 2002, 2005, 2006 Free Software Foundation, Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -20,8 +20,8 @@
 # 02110-1301, USA.
 
 
-# AT_CHECK_M4SUGAR_TEXT(CODE, STDOUT, STDER)
-# ------------------------------------------
+# AT_CHECK_M4SUGAR_TEXT(CODE, STDOUT, STDERR)
+# -------------------------------------------
 # Check that m4sugar CODE expands to STDOUT and emits STDERR.
 m4_define([AT_CHECK_M4SUGAR_TEXT],
 [
@@ -204,3 +204,79 @@
 AT_CHECK_M4RE([m4_re_string], address@hidden)
 
 AT_CLEANUP
+
+## ---------- ##
+## M4 Loops.  ##
+## ---------- ##
+
+AT_SETUP([M4 loops])
+
+AT_CHECK_M4SUGAR_TEXT([[dnl
+m4_define([myvar], [outer value])dnl
+m4_for([myvar], 1, 3, 1, [ myvar])
+m4_for([myvar], 1, 3,  , [ myvar])
+m4_for([myvar], 3, 1,-1, [ myvar])
+m4_for([myvar], 3, 1,  , [ myvar])
+m4_for([myvar], 1, 3, 2, [ myvar])
+m4_for([myvar], 3, 1,-2, [ myvar])
+m4_for([myvar],-1,-3,-2, [ myvar])
+m4_for([myvar],-3,-1, 2, [ myvar])
+dnl Make sure we recalculate the bounds correctly:
+m4_for([myvar], 1, 3, 3, [ myvar])
+m4_for([myvar], 1, 6, 3, [ myvar])
+m4_for([myvar],22,-7,-5, [ myvar])
+m4_for([myvar],-2,-7,-4, [ myvar])
+m4_for([myvar],-7,-2, 4, [ myvar])
+dnl Make sure we are not exposed to division truncation:
+m4_for([myvar], 2, 5, 2, [ myvar])
+m4_for([myvar],-5,-2, 2, [ myvar])
+m4_for([myvar], 5, 2,-2, [ myvar])
+m4_for([myvar],-2,-5,-2, [ myvar])
+dnl Make sure we do not divide by zero:
+m4_for([myvar], 1, 1,  , [ myvar])
+m4_for([myvar], 1, 1,+2, [ myvar])
+m4_for([myvar], 1, 1,-2, [ myvar])
+m4_foreach([myvar], [[a], [b, c], [d], [e
+],[f]], [ myvar|])
+m4_foreach_w([myvar], [a  b c, d,e f
+g], [ myvar|])
+myvar
+]],
+[[ 1 2 3
+ 1 2 3
+ 3 2 1
+ 3 2 1
+ 1 3
+ 3 1
+ -1 -3
+ -3 -1
+ 1
+ 1 4
+ 22 17 12 7 2 -3
+ -2 -6
+ -7 -3
+ 2 4
+ -5 -3
+ 5 3
+ -2 -4
+ 1
+ 1
+ 1
+ a| b, c| d| e
+| f|
+ a| b| c,| d,e| f| g|
+outer value
+]], [])
+
+AT_DATA_M4SUGAR([script.4s],
+[[m4_init
+m4_divert_push([0])m4_wrap([m4_divert_pop([0])[]])dnl
+m4_for([myvar], 1, 3,-1, [ myvar])
+]])
+
+AT_CHECK_M4SUGAR([], 1, [],
+[[script.4s:3: error: assert failed: -1 == 1
+script.4s:3: the top level
+autom4te: m4 failed with exit status: 1
+]])
+AT_CLEANUP




reply via email to

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