From: Eric Blake Date: Thu, 7 Aug 2008 03:22:06 +0000 (-0600) Subject: Partial m4sugar merge from autoconf: m4_shiftn. X-Git-Tag: v2.4~28 X-Git-Url: https://git.saurik.com/bison.git/commitdiff_plain/a3764451d3188132ed22f622ba0d35edd6e386cd?ds=sidebyside Partial m4sugar merge from autoconf: m4_shiftn. * data/m4sugar/m4sugar.m4 (m4_shiftn): Faster implementation. (m4_shift2, m4_shift3): New macros. (m4_case, m4_bmatch, m4_bpatsubsts, m4_join): Adjust clients. * data/c.m4 (b4_c_function_def, b4_c_ansi_function_def) (b4_c_ansi_function_decl, b4_c_function_call): Likewise. * data/java.m4 (b4_remove_comma): Likewise. Signed-off-by: Eric Blake --- diff --git a/ChangeLog b/ChangeLog index 114f5e2c..5af268ee 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,13 @@ 2008-08-06 Eric Blake + Partial m4sugar merge from autoconf: m4_shiftn. + * data/m4sugar/m4sugar.m4 (m4_shiftn): Faster implementation. + (m4_shift2, m4_shift3): New macros. + (m4_case, m4_bmatch, m4_bpatsubsts, m4_join): Adjust clients. + * data/c.m4 (b4_c_function_def, b4_c_ansi_function_def) + (b4_c_ansi_function_decl, b4_c_function_call): Likewise. + * data/java.m4 (b4_remove_comma): Likewise. + Partial m4sugar merge from autoconf: m4_wrap vs. m4 1.6. * data/m4sugar/m4sugar.m4 (m4_unquote, m4_wrap_lifo): New macros. (m4_wrap): Guarantee FIFO order, in spite of m4 1.6. diff --git a/data/c.m4 b/data/c.m4 index dbec53c6..ced2b1e2 100644 --- a/data/c.m4 +++ b/data/c.m4 @@ -1,7 +1,8 @@ -*- Autoconf -*- # C M4 Macros for Bison. -# Copyright (C) 2002, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. +# Copyright (C) 2002, 2004, 2005, 2006, 2007, 2008 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 @@ -228,8 +229,8 @@ m4_define([b4_c_function_def], b4_c_ansi_function_def($@) #else $2 -$1 (b4_c_knr_formal_names(m4_shiftn(2, $@))) -b4_c_knr_formal_decls(m4_shiftn(2, $@)) +$1 (b4_c_knr_formal_names(m4_shift2($@))) +b4_c_knr_formal_decls(m4_shift2($@)) #endif[]dnl ]) @@ -239,7 +240,7 @@ b4_c_knr_formal_decls(m4_shiftn(2, $@)) # Declare the function NAME in ANSI. m4_define([b4_c_ansi_function_def], [$2 -$1 (b4_c_ansi_formals(m4_shiftn(2, $@)))[]dnl +$1 (b4_c_ansi_formals(m4_shift2($@)))[]dnl ]) @@ -301,7 +302,7 @@ $2 $1 (); # ---------------------------------------------------------------- # Declare the function NAME. m4_define([b4_c_ansi_function_decl], -[$2 $1 (b4_c_ansi_formals(m4_shiftn(2, $@)));[]dnl +[$2 $1 (b4_c_ansi_formals(m4_shift2($@)));[]dnl ]) @@ -316,7 +317,7 @@ m4_define([b4_c_ansi_function_decl], # ----------------------------------------------------------- # Call the function NAME with arguments NAME1, NAME2 etc. m4_define([b4_c_function_call], -[$1 (b4_c_args(m4_shiftn(2, $@)))[]dnl +[$1 (b4_c_args(m4_shift2($@)))[]dnl ]) diff --git a/data/java.m4 b/data/java.m4 index 3f259fd5..13876941 100644 --- a/data/java.m4 +++ b/data/java.m4 @@ -2,7 +2,7 @@ # Java language support for Bison -# Copyright (C) 2007 Free Software Foundation, Inc. +# Copyright (C) 2007, 2008 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 @@ -75,7 +75,7 @@ m4_define([b4_identification], m4_define([b4_int_type], [m4_if(b4_ints_in($@, [-128], [127]), [1], [byte], b4_ints_in($@, [-32768], [32767]), [1], [short], - [int])]) + [int])]) # b4_int_type_for(NAME) # --------------------- @@ -205,7 +205,7 @@ m4_define([b4_param_decls], [m4_map([b4_param_decl], [$@])]) m4_define([b4_param_decl], [, $1]) -m4_define([b4_remove_comma], [m4_ifval($1, [$1, ], [])m4_shiftn(2, $@)]) +m4_define([b4_remove_comma], [m4_ifval($1, [$1, ], [])m4_shift2($@)]) diff --git a/data/m4sugar/m4sugar.m4 b/data/m4sugar/m4sugar.m4 index 4fa54b39..97b38a4d 100644 --- a/data/m4sugar/m4sugar.m4 +++ b/data/m4sugar/m4sugar.m4 @@ -366,7 +366,7 @@ m4_define([m4_case], [$#], 1, [], [$#], 2, [$2], [$1], [$2], [$3], - [$0([$1], m4_shiftn(3, $@))])]) + [$0([$1], m4_shift3($@))])]) # m4_bmatch(SWITCH, RE1, VAL1, RE2, VAL2, ..., DEFAULT) @@ -388,7 +388,7 @@ m4_define([m4_bmatch], [m4_if([$#], 0, [m4_fatal([$0: too few arguments: $#])], [$#], 1, [m4_fatal([$0: too few arguments: $#: $1])], [$#], 2, [$2], - [m4_if(m4_bregexp([$1], [$2]), -1, [$0([$1], m4_shiftn(3, $@))], + [m4_if(m4_bregexp([$1], [$2]), -1, [$0([$1], m4_shift3($@))], [$3])])]) @@ -445,13 +445,19 @@ m4_define([m4_map_sep], # I would have liked to name this macro `m4_bpatsubst', unfortunately, # due to quotation problems, I need to double quote $1 below, therefore # the anchors are broken :( I can't let users be trapped by that. +# +# Recall that m4_shift3 always results in an argument. Hence, we need +# to distinguish between a final deletion vs. ending recursion. m4_define([m4_bpatsubsts], [m4_if([$#], 0, [m4_fatal([$0: too few arguments: $#])], [$#], 1, [m4_fatal([$0: too few arguments: $#: $1])], - [$#], 2, [m4_builtin([patsubst], $@)], + [$#], 2, [m4_unquote(m4_builtin([patsubst], [[$1]], [$2]))], + [$#], 3, [m4_unquote(m4_builtin([patsubst], [[$1]], [$2], [$3]))], + [_$0($@m4_if(m4_eval($# & 1), 0, [,]))])]) +m4_define([_m4_bpatsubsts], +[m4_if([$#], 2, [$1], [$0(m4_builtin([patsubst], [[$1]], [$2], [$3]), - m4_shiftn(3, $@))])]) - + m4_shift3($@))])]) # m4_do(STRING, ...) @@ -555,14 +561,45 @@ m4_define([m4_noquote], # m4_shiftn(N, ...) # ----------------- # Returns ... shifted N times. Useful for recursive "varargs" constructs. +# +# Autoconf does not use this macro, because it is inherently slower than +# calling the common cases of m4_shift2 or m4_shift3 directly. But it +# might as well be fast for other clients, such as Libtool. One way to +# do this is to expand $@ only once in _m4_shiftn (otherwise, for long +# lists, the expansion of m4_if takes twice as much memory as what the +# list itself occupies, only to throw away the unused branch). The end +# result is strictly equivalent to +# m4_if([$1], 1, [m4_shift(,m4_shift(m4_shift($@)))], +# [_m4_shiftn(m4_decr([$1]), m4_shift(m4_shift($@)))]) +# but with the final `m4_shift(m4_shift($@)))' shared between the two +# paths. The first leg uses a no-op m4_shift(,$@) to balance out the (). m4_define([m4_shiftn], -[m4_assert(($1 >= 0) && ($# > $1))dnl -_m4_shiftn($@)]) +[m4_assert(0 < $1 && $1 < $#)_$0($@)]) m4_define([_m4_shiftn], -[m4_if([$1], 0, - [m4_shift($@)], - [_m4_shiftn(m4_eval([$1]-1), m4_shift(m4_shift($@)))])]) +[m4_if([$1], 1, [m4_shift(], + [$0(m4_decr([$1])]), m4_shift(m4_shift($@)))]) + +# m4_shift2(...) +# m4_shift3(...) +# ----------------- +# Returns ... shifted twice, and three times. Faster than m4_shiftn. +m4_define([m4_shift2], [m4_shift(m4_shift($@))]) +m4_define([m4_shift3], [m4_shift(m4_shift(m4_shift($@)))]) + +# _m4_shift2(...) +# _m4_shift3(...) +# --------------- +# Like m4_shift2 or m4_shift3, except include a leading comma unless shifting +# consumes all arguments. Why? Because in recursion, it is nice to +# distinguish between 1 element left and 0 elements left, based on how many +# arguments this shift expands to. +m4_define([_m4_shift2], +[m4_if([$#], [2], [], + [, m4_shift(m4_shift($@))])]) +m4_define([_m4_shift3], +[m4_if([$#], [3], [], + [, m4_shift(m4_shift(m4_shift($@)))])]) # m4_undefine(NAME) @@ -717,7 +754,9 @@ m4_if($1, [$2], [], # Hence the design below. # # The M4 manual now includes a chapter devoted to this issue, with -# the lessons learned from m4sugar. +# the lessons learned from m4sugar. And still, this design is only +# optimal for M4 1.6; see foreach.m4 for yet more comments on why +# M4 1.4.x uses yet another implementation. # m4_foreach(VARIABLE, LIST, EXPRESSION) @@ -1524,13 +1563,24 @@ m4_define([m4_normalize], # m4_join(SEP, ARG1, ARG2...) # --------------------------- -# Produce ARG1SEPARG2...SEPARGn. -m4_defun([m4_join], -[m4_case([$#], - [1], [], - [2], [[$2]], - [[$2][$1]$0([$1], m4_shiftn(2, $@))])]) - +# Produce ARG1SEPARG2...SEPARGn. Avoid back-to-back SEP when a given ARG +# is the empty string. No expansion is performed on SEP or ARGs. +# +# Since the number of arguments to join can be arbitrarily long, we +# want to avoid having more than one $@ in the macro definition; +# otherwise, the expansion would require twice the memory of the already +# long list. Hence, m4_join merely looks for the first non-empty element, +# and outputs just that element; while _m4_join looks for all non-empty +# elements, and outputs them following a separator. The final trick to +# note is that we decide between recursing with $0 or _$0 based on the +# nested m4_if ending with `_'. +m4_define([m4_join], +[m4_if([$#], [1], [], + [$#], [2], [[$2]], + [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift2($@))])]) +m4_define([_m4_join], +[m4_if([$#$2], [2], [], + [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift2($@))])]) # m4_append(MACRO-NAME, STRING, [SEPARATOR])