m4-commit
[Top][All Lists]
Advanced

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

[SCM] GNU M4 source repository branch, master, updated. cvs-readonly-63-


From: Eric Blake
Subject: [SCM] GNU M4 source repository branch, master, updated. cvs-readonly-63-g5d083e4
Date: Sat, 16 Feb 2008 13:55:46 +0000

This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU M4 source repository".

http://git.sv.gnu.org/gitweb/?p=m4.git;a=commitdiff;h=5d083e4726ed578b093aaf82e2a5a542f5815dcd

The branch, master has been updated
       via  5d083e4726ed578b093aaf82e2a5a542f5815dcd (commit)
      from  7f0b47b96e8872513aae3a4e3819aef6d799e6bd (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 5d083e4726ed578b093aaf82e2a5a542f5815dcd
Author: Eric Blake <address@hidden>
Date:   Fri Feb 15 22:12:03 2008 -0700

    Stage 15: return argv refs back to collect_arguments.
    
    * m4/m4private.h (CHAR_ARGV): New input engine sentinel.
    (enum m4__token_type): Add M4_TOKEN_ARGV.
    (struct m4__symbol_chain): Add skip_last member to argv link.
    (m4__next_token): Add parameter.
    * m4/input.c (peek_char, file_peek, builtin_peek, string_peek)
    (composite_peek, m4__next_token): Add new parameter.
    (composite_read, append_quote_token): Support argv in quotes.
    (init_argv_symbol): New function.
    (m4__push_symbol, match_input, consume_syntax)
    (m4__next_token_is_open, m4_print_token): Adjust callers.
    * m4/macro.c (m4_macro_expand_input, m4__arg_adjust_refcount)
    (arg_mark, m4_arg_text, make_argv_ref): Likewise.
    (expand_argument, collect_arguments): Handle new token.
    (arg_symbol): Drill through $@ reference.
    * m4/syntax.c (set_quote_age): Detect disabled comments.
    * m4/symtab.c (dump_symbol_CB) [DEBUG_SYM]: Fix debug code.
    
    Signed-off-by: Eric Blake <address@hidden>

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog      |   26 +++++++
 m4/input.c     |  207 +++++++++++++++++++++++++++++++++++++++++---------------
 m4/m4private.h |    9 ++-
 m4/macro.c     |  114 ++++++++++++++++++++++++-------
 m4/symtab.c    |    2 +-
 m4/syntax.c    |    8 ++-
 6 files changed, 277 insertions(+), 89 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 0e3c93e..d0ba987 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2008-02-16  Eric Blake  <address@hidden>
+
+       Stage 15: return argv refs back to collect_arguments.
+       Collect an entire $@ reference at once rather than one argument at
+       a time, outside of quotes (but inside quotes, $@ is still
+       flattened for now).  The skip_last field allows concatenation of
+       $@ with other text when collecting arguments.
+       Memory impact: noticeable improvement, due to better reuse of 
address@hidden
+       Speed impact: noticeable improvement, due to less parsing.
+       * m4/m4private.h (CHAR_ARGV): New input engine sentinel.
+       (enum m4__token_type): Add M4_TOKEN_ARGV.
+       (struct m4__symbol_chain): Add skip_last member to argv link.
+       (m4__next_token): Add parameter.
+       * m4/input.c (peek_char, file_peek, builtin_peek, string_peek)
+       (composite_peek, m4__next_token): Add new parameter.
+       (composite_read, append_quote_token): Support argv in quotes.
+       (init_argv_symbol): New function.
+       (m4__push_symbol, match_input, consume_syntax)
+       (m4__next_token_is_open, m4_print_token): Adjust callers.
+       * m4/macro.c (m4_macro_expand_input, m4__arg_adjust_refcount)
+       (arg_mark, m4_arg_text, make_argv_ref): Likewise.
+       (expand_argument, collect_arguments): Handle new token.
+       (arg_symbol): Drill through $@ reference.
+       * m4/syntax.c (set_quote_age): Detect disabled comments.
+       * m4/symtab.c (dump_symbol_CB) [DEBUG_SYM]: Fix debug code.
+
 2008-02-15  Eric Blake  <address@hidden>
 
        * modules/gnu.c (regexp_compile): Use a fastmap for regex speed.
diff --git a/m4/input.c b/m4/input.c
index 025ae0d..b5d50a1 100644
--- a/m4/input.c
+++ b/m4/input.c
@@ -92,20 +92,20 @@
    maintains its own notion of the current file and line, so swapping
    between input blocks must update the context accordingly.  */
 
-static int     file_peek               (m4_input_block *, m4 *);
+static int     file_peek               (m4_input_block *, m4 *, bool);
 static int     file_read               (m4_input_block *, m4 *, bool, bool);
 static void    file_unget              (m4_input_block *, int);
 static bool    file_clean              (m4_input_block *, m4 *, bool);
 static void    file_print              (m4_input_block *, m4 *, m4_obstack *);
-static int     builtin_peek            (m4_input_block *, m4 *);
+static int     builtin_peek            (m4_input_block *, m4 *, bool);
 static int     builtin_read            (m4_input_block *, m4 *, bool, bool);
 static void    builtin_unget           (m4_input_block *, int);
 static void    builtin_print           (m4_input_block *, m4 *, m4_obstack *);
-static int     string_peek             (m4_input_block *, m4 *);
+static int     string_peek             (m4_input_block *, m4 *, bool);
 static int     string_read             (m4_input_block *, m4 *, bool, bool);
 static void    string_unget            (m4_input_block *, int);
 static void    string_print            (m4_input_block *, m4 *, m4_obstack *);
-static int     composite_peek          (m4_input_block *, m4 *);
+static int     composite_peek          (m4_input_block *, m4 *, bool);
 static int     composite_read          (m4_input_block *, m4 *, bool, bool);
 static void    composite_unget         (m4_input_block *, int);
 static bool    composite_clean         (m4_input_block *, m4 *, bool);
@@ -116,12 +116,14 @@ static    void    append_quote_token      (m4 *, 
m4_obstack *,
                                         m4_symbol_value *);
 static bool    match_input             (m4 *, const char *, bool);
 static int     next_char               (m4 *, bool, bool);
-static int     peek_char               (m4 *);
+static int     peek_char               (m4 *, bool);
 static bool    pop_input               (m4 *, bool);
 static void    unget_input             (int);
 static bool    consume_syntax          (m4 *, m4_obstack *, unsigned int);
 
 #ifdef DEBUG_INPUT
+# include "quotearg.h"
+
 static int m4_print_token (const char *, m4__token_type, m4_symbol_value *);
 #endif
 
@@ -129,8 +131,9 @@ static int m4_print_token (const char *, m4__token_type, 
m4_symbol_value *);
 struct input_funcs
 {
   /* Peek at input, return an unsigned char, CHAR_BUILTIN if it is a
-     builtin, or CHAR_RETRY if none available.  */
-  int  (*peek_func)    (m4_input_block *, m4 *);
+     builtin, or CHAR_RETRY if none available.  If ALLOW_ARGV, then
+     CHAR_ARGV may be returned.  */
+   int (*peek_func)    (m4_input_block *, m4 *, bool);
 
   /* Read input, return an unsigned char, CHAR_BUILTIN if it is a
      builtin, or CHAR_RETRY if none available.  If ALLOW_QUOTE, then
@@ -254,7 +257,8 @@ static struct input_funcs composite_funcs = {
 
 /* Input files, from command line or [s]include.  */
 static int
-file_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED)
+file_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED,
+          bool allow_argv M4_GNUC_UNUSED)
 {
   int ch;
 
@@ -389,7 +393,8 @@ m4_push_file (m4 *context, FILE *fp, const char *title, 
bool close_file)
 
 /* Handle a builtin macro token.  */
 static int
-builtin_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED)
+builtin_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED,
+             bool allow_argv M4_GNUC_UNUSED)
 {
   if (me->u.u_b.read)
     return CHAR_RETRY;
@@ -474,7 +479,8 @@ m4_push_builtin (m4 *context, m4_symbol_value *token)
 
 /* Handle string expansion text.  */
 static int
-string_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED)
+string_peek (m4_input_block *me, m4 *context M4_GNUC_UNUSED,
+            bool allow_argv M4_GNUC_UNUSED)
 {
   return me->u.u_s.len ? to_uchar (*me->u.u_s.str) : CHAR_RETRY;
 }
@@ -662,7 +668,7 @@ m4__push_symbol (m4 *context, m4_symbol_value *value, 
size_t level, bool inuse)
       next->u.u_c.end = chain;
       if (chain->type == M4__CHAIN_ARGV)
        {
-         assert (!chain->u.u_a.comma);
+         assert (!chain->u.u_a.comma && !chain->u.u_a.skip_last);
          inuse |= m4__arg_adjust_refcount (context, chain->u.u_a.argv, true);
        }
       else if (chain->type == M4__CHAIN_STR && chain->u.u_s.level < SIZE_MAX)
@@ -718,9 +724,11 @@ m4_push_string_finish (void)
    in FIFO order, even though the obstack allocates memory in LIFO
    order.  */
 static int
-composite_peek (m4_input_block *me, m4 *context)
+composite_peek (m4_input_block *me, m4 *context, bool allow_argv)
 {
   m4__symbol_chain *chain = me->u.u_c.chain;
+  size_t argc;
+
   while (chain)
     {
       switch (chain->type)
@@ -730,12 +738,16 @@ composite_peek (m4_input_block *me, m4 *context)
            return to_uchar (chain->u.u_s.str[0]);
          break;
        case M4__CHAIN_ARGV:
-         /* TODO - figure out how to pass multiple arguments to
-            macro.c at once.  */
-         if (chain->u.u_a.index == m4_arg_argc (chain->u.u_a.argv))
+         argc = m4_arg_argc (chain->u.u_a.argv);
+         if (chain->u.u_a.index == argc)
            break;
          if (chain->u.u_a.comma)
            return ','; /* FIXME - support M4_SYNTAX_COMMA.  */
+         /* Only return a reference in the quoting is correct and the
+            reference has more than one argument left.  */
+         if (allow_argv && chain->quote_age == m4__quote_age (M4SYNTAX)
+             && chain->u.u_a.quotes && chain->u.u_a.index + 1 < argc)
+           return CHAR_ARGV;
          /* Rather than directly parse argv here, we push another
             input block containing the next unparsed argument from
             argv.  */
@@ -745,7 +757,7 @@ composite_peek (m4_input_block *me, m4 *context)
          chain->u.u_a.index++;
          chain->u.u_a.comma = true;
          m4_push_string_finish ();
-         return peek_char (context);
+         return peek_char (context, allow_argv);
        default:
          assert (!"composite_peek");
          abort ();
@@ -761,9 +773,7 @@ composite_read (m4_input_block *me, m4 *context, bool 
allow_quote, bool safe)
   m4__symbol_chain *chain = me->u.u_c.chain;
   while (chain)
     {
-      /* TODO also support returning $@ as CHAR_QUOTE.  */
-      if (allow_quote && chain->quote_age == m4__quote_age (M4SYNTAX)
-         && chain->type == M4__CHAIN_STR)
+      if (allow_quote && chain->quote_age == m4__quote_age (M4SYNTAX))
        return CHAR_QUOTE;
       switch (chain->type)
        {
@@ -779,8 +789,6 @@ composite_read (m4_input_block *me, m4 *context, bool 
allow_quote, bool safe)
            m4__adjust_refcount (context, chain->u.u_s.level, false);
          break;
        case M4__CHAIN_ARGV:
-         /* TODO - figure out how to pass multiple arguments to
-            macro.c at once.  */
          if (chain->u.u_a.index == m4_arg_argc (chain->u.u_a.argv))
            {
              m4__arg_adjust_refcount (context, chain->u.u_a.argv, false);
@@ -996,7 +1004,7 @@ pop_input (m4 *context, bool cleanup)
   assert (isp);
   if (isp->funcs->clean_func
       ? !isp->funcs->clean_func (isp, context, cleanup)
-      : (isp->funcs->peek_func (isp, context) != CHAR_RETRY))
+      : (isp->funcs->peek_func (isp, context, true) != CHAR_RETRY))
     return false;
 
   if (tmp != NULL)
@@ -1073,18 +1081,28 @@ append_quote_token (m4 *context, m4_obstack *obs, 
m4_symbol_value *value)
 {
   m4__symbol_chain *src_chain = isp->u.u_c.chain;
   m4__symbol_chain *chain;
-  assert (isp->funcs == &composite_funcs && obs && m4__quote_age (M4SYNTAX)
-         && src_chain->type == M4__CHAIN_STR
-         && src_chain->u.u_s.level <= SIZE_MAX);
+  assert (isp->funcs == &composite_funcs && obs && m4__quote_age (M4SYNTAX));
   isp->u.u_c.chain = src_chain->next;
 
   /* Speed consideration - for short enough symbols, the speed and
      memory overhead of parsing another INPUT_CHAIN link outweighs the
      time to inline the symbol text.  */
-  if (src_chain->u.u_s.len <= INPUT_INLINE_THRESHOLD)
+  if (src_chain->type == M4__CHAIN_STR
+      && src_chain->u.u_s.len <= INPUT_INLINE_THRESHOLD)
     {
+      assert (src_chain->u.u_s.level <= SIZE_MAX);
       obstack_grow (obs, src_chain->u.u_s.str, src_chain->u.u_s.len);
       m4__adjust_refcount (context, src_chain->u.u_s.level, false);
+      return;
+    }
+
+  /* TODO preserve $@ through quotes.  */
+  if (src_chain->type == M4__CHAIN_ARGV)
+    {
+      m4_arg_print (obs, src_chain->u.u_a.argv, src_chain->u.u_a.index,
+                   src_chain->u.u_a.quotes, NULL, false);
+      m4__arg_adjust_refcount (context, src_chain->u.u_a.argv, false);
+      return;
     }
 
   if (value->type == M4_SYMBOL_VOID)
@@ -1103,6 +1121,65 @@ append_quote_token (m4 *context, m4_obstack *obs, 
m4_symbol_value *value)
   chain->next = NULL;
 }
 
+/* When an ARGV token is seen, convert VALUE to point to it via a
+   composite chain.  Use OBS for any additional allocations
+   needed.  */
+static void
+init_argv_symbol (m4 *context, m4_obstack *obs, m4_symbol_value *value)
+{
+  m4__symbol_chain *src_chain;
+  m4__symbol_chain *chain;
+  int ch = next_char (context, true, true);
+  const m4_string_pair *comments = m4_get_syntax_comments (M4SYNTAX);
+
+  assert (ch == CHAR_QUOTE && value->type == M4_SYMBOL_VOID
+         && isp->funcs == &composite_funcs
+         && isp->u.u_c.chain->type == M4__CHAIN_ARGV
+         && obs && obstack_object_size (obs) == 0);
+
+  src_chain = isp->u.u_c.chain;
+  isp->u.u_c.chain = src_chain->next;
+  value->type = M4_SYMBOL_COMP;
+  /* Clone the link, since the input will be discarded soon.  */
+  chain = (m4__symbol_chain *) obstack_copy (obs, src_chain, sizeof *chain);
+  value->u.u_c.chain = value->u.u_c.end = chain;
+  chain->next = NULL;
+
+  /* If the next character is not ',' or ')', then unlink the last
+     argument from argv and schedule it for reparsing.  This way,
+     expand_argument never has to deal with concatenation of argv with
+     arbitrary text.  Note that the implementation of safe_quotes
+     ensures peek_input won't return CHAR_ARGV if the user is perverse
+     enough to mix comment delimiters with argument separators:
+
+       define(n,`$#')define(echo,$*)changecom(`,,',`)')n(echo(a,`,b`)'',c))
+       => 2 (not 3)
+
+     Therefore, we do not have to worry about calling MATCH, and thus
+     do not have to worry about pop_input being called and
+     invalidating the argv reference.
+
+     When the $@ ref is used unchanged, we completely bypass the
+     decrement of the argv refcount in next_char, since the ref is
+     still live via the current collect_arguments.  However, when the
+     last element of the $@ ref is reparsed, we must increase the argv
+     refcount here, to compensate for the fact that it will be
+     decreased once the final element is parsed.  */
+  assert (!comments->len1
+         || (!m4_has_syntax (M4SYNTAX, *comments->str1,
+                             M4_SYNTAX_COMMA | M4_SYNTAX_CLOSE)
+             && *comments->str1 != *src_chain->u.u_a.quotes->str1));
+  ch = peek_char (context, false);
+  if (!m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_COMMA | M4_SYNTAX_CLOSE))
+    {
+      isp->u.u_c.chain = src_chain;
+      src_chain->u.u_a.index = m4_arg_argc (chain->u.u_a.argv) - 1;
+      src_chain->u.u_a.comma = true;
+      chain->u.u_a.skip_last = true;
+      m4__arg_adjust_refcount (context, chain->u.u_a.argv, true);
+    }
+}
+
 
 /* Low level input is done a character at a time.  The function
    next_char () is used to read and advance the input to the next
@@ -1146,9 +1223,10 @@ next_char (m4 *context, bool allow_quote, bool retry)
 
 /* The function peek_char () is used to look at the next character in
    the input stream.  At any given time, it reads from the input_block
-   on the top of the current input stack.  */
+   on the top of the current input stack.  If ALLOW_ARGV, then return
+   CHAR_ARGV if an entire $@ reference is available for use.  */
 static int
-peek_char (m4 *context)
+peek_char (m4 *context, bool allow_argv)
 {
   int ch;
   m4_input_block *block = isp;
@@ -1159,7 +1237,8 @@ peek_char (m4 *context)
        return CHAR_EOF;
 
       assert (block->funcs->peek_func);
-      if ((ch = block->funcs->peek_func (block, context)) != CHAR_RETRY)
+      ch = block->funcs->peek_func (block, context, allow_argv);
+      if (ch != CHAR_RETRY)
        {
 /*       if (IS_IGNORE (ch)) */
 /*         return next_char (context, false, true); */
@@ -1228,7 +1307,7 @@ match_input (m4 *context, const char *s, bool consume)
   m4_obstack *st;
   bool result = false;
 
-  ch = peek_char (context);
+  ch = peek_char (context, false);
   if (ch != to_uchar (*s))
     return false;                      /* fail */
 
@@ -1240,7 +1319,7 @@ match_input (m4 *context, const char *s, bool consume)
     }
 
   next_char (context, false, true);
-  for (n = 1, t = s++; (ch = peek_char (context)) == to_uchar (*s++); )
+  for (n = 1, t = s++; (ch = peek_char (context, false)) == to_uchar (*s++); )
     {
       next_char (context, false, true);
       n++;
@@ -1297,7 +1376,7 @@ consume_syntax (m4 *context, m4_obstack *obs, unsigned 
int syntax)
        }
       if (ch == CHAR_RETRY || ch == CHAR_QUOTE)
        {
-         ch = peek_char (context);
+         ch = peek_char (context, false);
          if (m4_has_syntax (M4SYNTAX, ch, syntax))
            {
              assert (ch < CHAR_EOF);
@@ -1355,8 +1434,10 @@ m4_input_exit (void)
    with a description of what TOKEN will contain.  If LINE is not
    NULL, set *LINE to the line number where the token starts.  If OBS,
    expand safe tokens (strings and comments) directly into OBS rather
-   than in a temporary staging area.  Report errors (unterminated
-   comments or strings) on behalf of CALLER, if non-NULL.
+   than in a temporary staging area.  If ALLOW_ARGV, OBS must be
+   non-NULL, and an entire series of arguments can be returned if a $@
+   reference is encountered.  Report errors (unterminated comments or
+   strings) on behalf of CALLER, if non-NULL.
 
    If OBS is NULL or the token expansion is unknown, the token text is
    collected on the obstack token_stack, which never contains more
@@ -1365,7 +1446,7 @@ m4_input_exit (void)
    m4__next_token () is called.  */
 m4__token_type
 m4__next_token (m4 *context, m4_symbol_value *token, int *line,
-               m4_obstack *obs, const char *caller)
+               m4_obstack *obs, bool allow_argv, const char *caller)
 {
   int ch;
   int quote_level;
@@ -1388,7 +1469,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int 
*line,
 
     /* Must consume an input character, but not until CHAR_BUILTIN is
        handled.  */
-    ch = peek_char (context);
+    ch = peek_char (context, allow_argv && m4__quote_age (M4SYNTAX));
     if (ch == CHAR_EOF)                        /* EOF */
       {
 #ifdef DEBUG_INPUT
@@ -1407,6 +1488,14 @@ m4__next_token (m4 *context, m4_symbol_value *token, int 
*line,
 #endif
        return M4_TOKEN_MACDEF;
       }
+    if (ch == CHAR_ARGV)
+      {
+       init_argv_symbol (context, obs, token);
+#ifdef DEBUG_INPUT
+       m4_print_token ("next_token", M4_TOKEN_ARGV, token);
+#endif
+       return M4_TOKEN_ARGV;
+      }
 
     /* Consume character we already peeked at.  */
     next_char (context, false, true);
@@ -1644,7 +1733,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int 
*line,
 bool
 m4__next_token_is_open (m4 *context)
 {
-  int ch = peek_char (context);
+  int ch = peek_char (context, false);
 
   if (ch == CHAR_EOF || ch == CHAR_BUILTIN
       || m4_has_syntax (M4SYNTAX, ch, (M4_SYNTAX_BCOMM | M4_SYNTAX_ESCAPE
@@ -1667,55 +1756,61 @@ m4_print_token (const char *s, m4__token_type type, 
m4_symbol_value *token)
   m4_obstack obs;
   size_t len;
 
-  obstack_init (&obs);
   if (!s)
     s = "m4input";
-  obstack_grow (&obs, s, strlen (s));
-  obstack_1grow (&obs, ':');
-  obstack_1grow (&obs, ' ');
+  xfprintf (stderr, "%s: ", s);
   switch (type)
     {                          /* TOKSW */
     case M4_TOKEN_EOF:
-      obstack_grow (&obs, "eof", strlen ("eof"));
+      fputs ("eof", stderr);
       token = NULL;
       break;
     case M4_TOKEN_NONE:
-      obstack_grow (&obs, "none", strlen ("none"));
+      fputs ("none", stderr);
       token = NULL;
       break;
     case M4_TOKEN_STRING:
-      obstack_grow (&obs, "string\t", strlen ("string\t"));
+      fputs ("string\t", stderr);
       break;
     case M4_TOKEN_SPACE:
-      obstack_grow (&obs, "space\t", strlen ("space\t"));
+      fputs ("space\t", stderr);
       break;
     case M4_TOKEN_WORD:
-      obstack_grow (&obs, "word\t", strlen ("word\t"));
+      fputs ("word\t", stderr);
       break;
     case M4_TOKEN_OPEN:
-      obstack_grow (&obs, "open\t", strlen ("open\t"));
+      fputs ("open\t", stderr);
       break;
     case M4_TOKEN_COMMA:
-      obstack_grow (&obs, "comma\t", strlen ("comma\t"));
+      fputs ("comma\t", stderr);
       break;
     case M4_TOKEN_CLOSE:
-      obstack_grow (&obs, "close\t", strlen ("close\t"));
+      fputs ("close\t", stderr);
       break;
     case M4_TOKEN_SIMPLE:
-      obstack_grow (&obs, "simple\t", strlen ("simple\t"));
+      fputs ("simple\t", stderr);
       break;
     case M4_TOKEN_MACDEF:
-      obstack_grow (&obs, "builtin\t", strlen ("builtin\t"));
+      fputs ("builtin\t", stderr);
+      break;
+    case M4_TOKEN_ARGV:
+      fputs ("argv\t", stderr);
       break;
     default:
       abort ();
     }
   if (token)
-    m4_symbol_value_print (token, &obs, true, "\"", "\"", SIZE_MAX, NULL);
-  obstack_1grow (&obs, '\n');
-  len = obstack_object_size (&obs);
-  fwrite (obstack_finish (&obs), 1, len, stderr);
-  obstack_free (&obs, NULL);
+    {
+      obstack_init (&obs);
+      m4_symbol_value_print (token, &obs, NULL, NULL, true);
+      len = obstack_object_size (&obs);
+      xfprintf (stderr, "%s\n", quotearg_style_mem (c_maybe_quoting_style,
+                                                   obstack_finish (&obs),
+                                                   len));
+      obstack_free (&obs, NULL);
+    }
+  else
+    fputc ('\n', stderr);
   return 0;
 }
 #endif /* DEBUG_INPUT */
diff --git a/m4/m4private.h b/m4/m4private.h
index 77590f3..a2b78b8 100644
--- a/m4/m4private.h
+++ b/m4/m4private.h
@@ -221,6 +221,7 @@ struct m4__symbol_chain
       size_t index;                    /* Argument index within argv.  */
       bool_bitfield flatten : 1;       /* True to treat builtins as text.  */
       bool_bitfield comma : 1;         /* True when `,' is next input.  */
+      bool_bitfield skip_last : 1;     /* True if last argument omitted.  */
       const m4_string_pair *quotes;    /* NULL for $*, quotes for 
address@hidden  */
     } u_a;                     /* M4__CHAIN_ARGV.  */
   } u;
@@ -397,7 +398,8 @@ extern void m4__symtab_remove_module_references 
(m4_symbol_table*,
 #define CHAR_EOF       256     /* Character return on EOF.  */
 #define CHAR_BUILTIN   257     /* Character return for BUILTIN token.  */
 #define CHAR_QUOTE     258     /* Character return for quoted string.  */
-#define CHAR_RETRY     259     /* Character return for end of input block.  */
+#define CHAR_ARGV      259     /* Character return for $@ reference.  */
+#define CHAR_RETRY     260     /* Character return for end of input block.  */
 
 #define DEF_LQUOTE     "`"     /* Default left quote delimiter.  */
 #define DEF_RQUOTE     "\'"    /* Default right quote delimiter.  */
@@ -475,7 +477,8 @@ typedef enum {
   M4_TOKEN_COMMA,      /* Argument separator, M4_SYMBOL_TEXT.  */
   M4_TOKEN_CLOSE,      /* Argument list end, M4_SYMBOL_TEXT.  */
   M4_TOKEN_SIMPLE,     /* Single character, M4_SYMBOL_TEXT.  */
-  M4_TOKEN_MACDEF      /* Macro's definition (see "defn"), M4_SYMBOL_FUNC.  */
+  M4_TOKEN_MACDEF,     /* Macro's definition (see "defn"), M4_SYMBOL_FUNC.  */
+  M4_TOKEN_ARGV                /* A series of parameters, M4_SYMBOL_COMP.  */
 } m4__token_type;
 
 extern void            m4__make_text_link (m4_obstack *, m4__symbol_chain **,
@@ -483,7 +486,7 @@ extern      void            m4__make_text_link (m4_obstack 
*, m4__symbol_chain **,
 extern bool            m4__push_symbol (m4 *, m4_symbol_value *, size_t,
                                         bool);
 extern m4__token_type  m4__next_token (m4 *, m4_symbol_value *, int *,
-                                       m4_obstack *, const char *);
+                                       m4_obstack *, bool, const char *);
 extern bool            m4__next_token_is_open (m4 *);
 
 /* Fast macro versions of macro argv accessor functions,
diff --git a/m4/macro.c b/m4/macro.c
index 708be58..d6f81d8 100644
--- a/m4/macro.c
+++ b/m4/macro.c
@@ -183,7 +183,7 @@ m4_macro_expand_input (m4 *context)
   m4_set_symbol_value_text (&empty_symbol, "", 0, 0);
   VALUE_MAX_ARGS (&empty_symbol) = -1;
 
-  while ((type = m4__next_token (context, &token, &line, NULL, NULL))
+  while ((type = m4__next_token (context, &token, &line, NULL, false, NULL))
         != M4_TOKEN_EOF)
     expand_token (context, NULL, type, &token, line, true);
 }
@@ -311,7 +311,7 @@ expand_argument (m4 *context, m4_obstack *obs, 
m4_symbol_value *argp,
   /* Skip leading white space.  */
   do
     {
-      type = m4__next_token (context, &token, NULL, obs, caller);
+      type = m4__next_token (context, &token, NULL, obs, true, caller);
     }
   while (type == M4_TOKEN_SPACE);
 
@@ -389,6 +389,20 @@ expand_argument (m4 *context, m4_obstack *obs, 
m4_symbol_value *argp,
            argp->type = M4_SYMBOL_TEXT;
          break;
 
+       case M4_TOKEN_ARGV:
+         assert (paren_level == 0 && argp->type == M4_SYMBOL_VOID
+                 && obstack_object_size (obs) == 0
+                 && token.u.u_c.chain == token.u.u_c.end
+                 && token.u.u_c.chain->type == M4__CHAIN_ARGV);
+         argp->type = M4_SYMBOL_COMP;
+         argp->u.u_c.chain = argp->u.u_c.end = token.u.u_c.chain;
+         type = m4__next_token (context, &token, NULL, NULL, false, caller);
+         if (argp->u.u_c.chain->u.u_a.skip_last)
+           assert (type == M4_TOKEN_COMMA);
+         else
+           assert (type == M4_TOKEN_COMMA || type == M4_TOKEN_CLOSE);
+         return type == M4_TOKEN_COMMA;
+
        default:
          assert (!"expand_argument");
          abort ();
@@ -396,7 +410,7 @@ expand_argument (m4 *context, m4_obstack *obs, 
m4_symbol_value *argp,
 
       if (argp->type != M4_SYMBOL_VOID || obstack_object_size (obs))
        first = false;
-      type = m4__next_token (context, &token, NULL, obs, caller);
+      type = m4__next_token (context, &token, NULL, obs, first, caller);
     }
 }
 
@@ -583,7 +597,7 @@ collect_arguments (m4 *context, const char *name, size_t 
len,
   if (m4__next_token_is_open (context))
     {
       /* Gobble parenthesis, then collect arguments.  */
-      m4__next_token (context, &token, NULL, NULL, name);
+      m4__next_token (context, &token, NULL, NULL, false, name);
       do
        {
          tokenp = (m4_symbol_value *) obstack_alloc (arguments,
@@ -608,12 +622,22 @@ collect_arguments (m4 *context, const char *name, size_t 
len,
              && m4_get_symbol_value_quote_age (tokenp) != args.quote_age)
            args.quote_age = 0;
          else if (tokenp->type == M4_SYMBOL_COMP)
-           args.has_ref = true;
+           {
+             args.has_ref = true;
+             if (tokenp->u.u_c.chain->type == M4__CHAIN_ARGV)
+               {
+                 args.argc += (tokenp->u.u_c.chain->u.u_a.argv->argc
+                               - tokenp->u.u_c.chain->u.u_a.index
+                               - tokenp->u.u_c.chain->u.u_a.skip_last - 1);
+                 args.wrapper = true;
+               }
+           }
        }
       while (more_args);
     }
   argv = (m4_macro_args *) obstack_finish (argv_stack);
   argv->argc = args.argc;
+  argv->wrapper = args.wrapper;
   argv->has_ref = args.has_ref;
   if (args.quote_age != m4__quote_age (M4SYNTAX))
     argv->quote_age = 0;
@@ -981,9 +1005,22 @@ m4__arg_adjust_refcount (m4 *context, m4_macro_args 
*argv, bool increase)
          chain = argv->array[i]->u.u_c.chain;
          while (chain)
            {
-             assert (chain->type == M4__CHAIN_STR);
-             if (chain->u.u_s.level < SIZE_MAX)
-               m4__adjust_refcount (context, chain->u.u_s.level, increase);
+             switch (chain->type)
+               {
+               case M4__CHAIN_STR:
+                 if (chain->u.u_s.level < SIZE_MAX)
+                   m4__adjust_refcount (context, chain->u.u_s.level,
+                                        increase);
+                 break;
+               case M4__CHAIN_ARGV:
+                 assert (chain->u.u_a.argv->inuse);
+                 m4__arg_adjust_refcount (context, chain->u.u_a.argv,
+                                          increase);
+                 break;
+               default:
+                 assert (!"m4__arg_adjust_refcount");
+                 abort ();
+               }
              chain = chain->next;
            }
        }
@@ -996,15 +1033,25 @@ m4__arg_adjust_refcount (m4 *context, m4_macro_args 
*argv, bool increase)
 static void
 arg_mark (m4_macro_args *argv)
 {
+  size_t i;
+  m4__symbol_chain *chain;
+
+  if (argv->inuse)
+    return;
   argv->inuse = true;
   if (argv->wrapper)
     {
-      /* TODO for now we support only a single-length $@ chain.  */
-      assert (argv->arraylen == 1
-             && argv->array[0]->type == M4_SYMBOL_COMP
-             && !argv->array[0]->u.u_c.chain->next
-             && argv->array[0]->u.u_c.chain->type == M4__CHAIN_ARGV);
-      argv->array[0]->u.u_c.chain->u.u_a.argv->inuse = true;
+      for (i = 0; i < argv->arraylen; i++)
+       if (argv->array[i]->type == M4_SYMBOL_COMP)
+         {
+           chain = argv->array[i]->u.u_c.chain;
+           while (chain)
+             {
+               if (chain->type == M4__CHAIN_ARGV && !chain->u.u_a.argv->inuse)
+                 arg_mark (chain->u.u_a.argv);
+               chain = chain->next;
+             }
+         }
     }
 }
 
@@ -1022,12 +1069,13 @@ make_argv_ref (m4_symbol_value *value, m4_obstack *obs, 
size_t level,
   m4__symbol_chain *chain;
 
   assert (obstack_object_size (obs) == 0);
-  if (argv->wrapper)
+  if (argv->wrapper && argv->arraylen == 1)
     {
-      /* TODO support concatenation with $@ refs.  */
-      assert (argv->arraylen == 1 && argv->array[0]->type == M4_SYMBOL_COMP);
+      /* TODO support $@ ref alongside other arguments.  */
+      assert (argv->array[0]->type == M4_SYMBOL_COMP);
       chain= argv->array[0]->u.u_c.chain;
-      assert (!chain->next && chain->type == M4__CHAIN_ARGV);
+      assert (!chain->next && chain->type == M4__CHAIN_ARGV
+             && !chain->u.u_a.skip_last);
       argv = chain->u.u_a.argv;
       index += chain->u.u_a.index - 1;
     }
@@ -1044,6 +1092,7 @@ make_argv_ref (m4_symbol_value *value, m4_obstack *obs, 
size_t level,
   chain->u.u_a.index = index;
   chain->u.u_a.flatten = flatten;
   chain->u.u_a.comma = false;
+  chain->u.u_a.skip_last = false;
   if (quotes)
     {
       /* Clone the quotes into the obstack, since changequote can
@@ -1081,12 +1130,14 @@ arg_symbol (m4_macro_args *argv, size_t index, size_t 
*level)
   for (i = 0; i < argv->arraylen; i++)
     {
       value = argv->array[i];
-      if (value->type == M4_SYMBOL_COMP)
+      if (value->type == M4_SYMBOL_COMP
+         && value->u.u_c.chain->type == M4__CHAIN_ARGV)
        {
          m4__symbol_chain *chain = value->u.u_c.chain;
          /* TODO - for now we support only a single $@ chain.  */
-         assert (!chain->next && chain->type == M4__CHAIN_ARGV);
-         if (index < chain->u.u_a.argv->argc - (chain->u.u_a.index - 1))
+         assert (!chain->next);
+         if (index <= (chain->u.u_a.argv->argc - chain->u.u_a.index
+                       - chain->u.u_a.skip_last))
            {
              value = arg_symbol (chain->u.u_a.argv,
                                  chain->u.u_a.index - 1 + index, level);
@@ -1094,7 +1145,8 @@ arg_symbol (m4_macro_args *argv, size_t index, size_t 
*level)
                value = &empty_symbol;
              break;
            }
-         index -= chain->u.u_a.argv->argc - chain->u.u_a.index;
+         index -= (chain->u.u_a.argv->argc - chain->u.u_a.index
+                   - chain->u.u_a.skip_last);
        }
       else if (--index == 0)
        break;
@@ -1154,15 +1206,25 @@ m4_arg_text (m4 *context, m4_macro_args *argv, size_t 
index)
   value = m4_arg_symbol (argv, index);
   if (m4_is_symbol_value_text (value))
     return m4_get_symbol_value_text (value);
-  /* TODO - concatenate argv refs and functions?  For now, we assume
-     all chain elements are text.  */
+  /* TODO - concatenate functions.  */
   assert (value->type == M4_SYMBOL_COMP);
   chain = value->u.u_c.chain;
   obs = m4_arg_scratch (context);
   while (chain)
     {
-      assert (chain->type == M4__CHAIN_STR);
-      obstack_grow (obs, chain->u.u_s.str, chain->u.u_s.len);
+      switch (chain->type)
+       {
+       case M4__CHAIN_STR:
+         obstack_grow (obs, chain->u.u_s.str, chain->u.u_s.len);
+         break;
+       case M4__CHAIN_ARGV:
+         m4_arg_print (obs, chain->u.u_a.argv, chain->u.u_a.index,
+                       chain->u.u_a.quotes, NULL, false);
+         break;
+       default:
+         assert (!"m4_arg_text");
+         abort ();
+       }
       chain = chain->next;
     }
   obstack_1grow (obs, '\0');
diff --git a/m4/symtab.c b/m4/symtab.c
index f302fe8..9636f9d 100644
--- a/m4/symtab.c
+++ b/m4/symtab.c
@@ -845,7 +845,7 @@ dump_symbol_CB (m4_symbol_table *symtab, const char *name,
     {
       m4_obstack obs;
       obstack_init (&obs);
-      m4_symbol_value_print (value, &obs, false, NULL, NULL, SIZE_MAX, true);
+      m4_symbol_value_print (value, &obs, NULL, NULL, true);
       xfprintf (stderr, "%s", (char *) obstack_finish (&obs));
       obstack_free (&obs, NULL);
     }
diff --git a/m4/syntax.c b/m4/syntax.c
index aff6444..8a7b0d1 100644
--- a/m4/syntax.c
+++ b/m4/syntax.c
@@ -743,9 +743,11 @@ set_quote_age (m4_syntax_table *syntax, bool reset, bool 
change)
                          | M4_SYNTAX_COMMA | M4_SYNTAX_CLOSE
                          | M4_SYNTAX_SPACE))
       && *syntax->quote.str1 != *syntax->quote.str2
-      && *syntax->comm.str1 != *syntax->quote.str2
-      && !m4_has_syntax (syntax, *syntax->comm.str1,
-                        M4_SYNTAX_OPEN | M4_SYNTAX_COMMA | M4_SYNTAX_CLOSE)
+      && (!syntax->comm.len1
+          || (*syntax->comm.str1 != *syntax->quote.str2
+              && !m4_has_syntax (syntax, *syntax->comm.str1,
+                                 (M4_SYNTAX_OPEN | M4_SYNTAX_COMMA
+                                  | M4_SYNTAX_CLOSE))))
       && m4_has_syntax (syntax, ',', M4_SYNTAX_COMMA))
     {
       syntax->quote_age = ((local_syntax_age << 16)


hooks/post-receive
--
GNU M4 source repository




reply via email to

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