m4-commit
[Top][All Lists]
Advanced

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

[SCM] GNU M4 source repository branch, branch-1_4, updated. branch-cvs-r


From: Eric Blake
Subject: [SCM] GNU M4 source repository branch, branch-1_4, updated. branch-cvs-readonly-53-g7319157
Date: Sat, 16 Feb 2008 13:55:47 +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=7319157ccd7cd65f72c0a456c3091252a13f558a

The branch, branch-1_4 has been updated
       via  7319157ccd7cd65f72c0a456c3091252a13f558a (commit)
      from  950807234e3ffd376ad51b2a21cd276dd8b4e59c (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 7319157ccd7cd65f72c0a456c3091252a13f558a
Author: Eric Blake <address@hidden>
Date:   Thu Nov 1 09:28:46 2007 -0600

    Stage 15: return argv refs back to collect_arguments.
    
    * src/m4.h (enum token_type): Add TOKEN_ARGV.
    (struct token_chain): Add skip_last member to argv link.
    (next_token): Update prototype.
    * src/input.c (CHAR_ARGV): New placeholder input character.
    (peek_input): Add parameter, to pass $@ at once.
    (next_char_1, append_quote_token): Handle $@ inside quotes.
    (init_argv_token): New function.
    (push_token, match_input, next_token, peek_token, lex_debug):
    Update callers.
    * src/macro.c (expand_input, collect_arguments): Likewise.
    (expand_argument): Handle incoming $@ token.
    (arg_adjust_refcount, arg_token, arg_text, make_argv_ref_token):
    Handle nested $@ refs.
    * src/symtab.c (symtab_debug): Update caller.
    * examples/null.m4: Document more tests that are needed.  Add
    tests for NUL with divert, patsubst, and regexp.
    * examples/null.out: Update for new tests.
    * doc/m4.texinfo (Syntax): Add test for m4exit and NUL.
    * checks/get-them (AWK): Give a default value.
    * checks/check-them: Allow tests to invoke child processes with
    same include path.  Perform message normalization on stderr.
    
    (cherry picked from commit 1fecefc8b990254aa667a01d12c6c7a2d716df06)
    
    Signed-off-by: Eric Blake <address@hidden>

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

Summary of changes:
 ChangeLog         |   31 +++++++++
 checks/check-them |   10 ++-
 checks/get-them   |    4 +-
 doc/m4.texinfo    |    8 ++-
 examples/null.m4  |  Bin 3671 -> 5764 bytes
 examples/null.out |  Bin 338 -> 400 bytes
 src/input.c       |  177 +++++++++++++++++++++++++++++++++++++++++------------
 src/m4.h          |    7 ++-
 src/macro.c       |  112 +++++++++++++++++++++++++--------
 src/symtab.c      |    2 +-
 10 files changed, 275 insertions(+), 76 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index c455abc..0baa3c1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,34 @@
+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.
+       * src/m4.h (enum token_type): Add TOKEN_ARGV.
+       (struct token_chain): Add skip_last member to argv link.
+       (next_token): Update prototype.
+       * src/input.c (CHAR_ARGV): New placeholder input character.
+       (peek_input): Add parameter, to pass $@ at once.
+       (next_char_1, append_quote_token): Handle $@ inside quotes.
+       (init_argv_token): New function.
+       (push_token, match_input, next_token, peek_token, lex_debug):
+       Update callers.
+       * src/macro.c (expand_input, collect_arguments): Likewise.
+       (expand_argument): Handle incoming $@ token.
+       (arg_adjust_refcount, arg_token, arg_text, make_argv_ref_token):
+       Handle nested $@ refs.
+       * src/symtab.c (symtab_debug): Update caller.
+       * examples/null.m4: Document more tests that are needed.  Add
+       tests for NUL with divert, patsubst, and regexp.
+       * examples/null.out: Update for new tests.
+       * doc/m4.texinfo (Syntax): Add test for m4exit and NUL.
+       * checks/get-them (AWK): Give a default value.
+       * checks/check-them: Allow tests to invoke child processes with
+       same include path.  Perform message normalization on stderr.
+
 2008-02-15  Eric Blake  <address@hidden>
 
        Use fastmaps for better regex performance.
diff --git a/checks/check-them b/checks/check-them
index daa1b00..9fca39b 100755
--- a/checks/check-them
+++ b/checks/check-them
@@ -1,6 +1,6 @@
 #!/bin/sh
 # Check GNU m4 against examples from the manual source.
-# Copyright (C) 1992, 2006, 2007 Free Software Foundation, Inc.
+# Copyright (C) 1992, 2006, 2007, 2008 Free Software Foundation, Inc.
 
 # Sanity check what we are testing
 m4 --version
@@ -68,7 +68,7 @@ do
   echo "Checking $file"
   options=`sed -ne '3s/^dnl @ extra options: //p;3q' "$file"`
   sed -e '/^dnl @/d' -e '/^\^D$/q' "$file" \
-    | LC_MESSAGES=C m4 -d -I "$examples" $options - >$out 2>$err
+    | LC_MESSAGES=C M4PATH=$examples m4 -d $options - >$out 2>$err
   stat=$?
 
   xstat=`sed -ne '2s/^dnl @ expected status: //p;2q' "$file"`
@@ -96,9 +96,11 @@ do
 
   xerrfile=`sed -n 's/^dnl @ expected error: //p' "$file"`
   if test -z "$xerrfile" ; then
-    sed -e '/^dnl @error{}/!d' -e 's///' -e "s|^m4:|$m4:|" "$file" > $xerr
+    sed '/^dnl @error{}/!d; s///; '"s|^m4:|$m4:|; s|\.\./examples|$examples|" \
+      "$file" > $xerr
   else
-    cp "$examples/$xerrfile" $xerr
+    sed "s|^m4:|$m4:|; s|\.\./examples|$examples|" \
+      "$examples/$xerrfile" > $xerr
   fi
 
   # For the benefit of mingw, normalize \r\n line endings
diff --git a/checks/get-them b/checks/get-them
index e034962..803f413 100755
--- a/checks/get-them
+++ b/checks/get-them
@@ -1,11 +1,13 @@
 #!/bin/sh
 # -*- AWK -*-
 # Extract all examples from the manual source.
-# Copyright (C) 1992, 2005, 2006, 2007 Free Software Foundation, Inc.
+# Copyright (C) 1992, 2005, 2006, 2007, 2008 Free Software Foundation,
+# Inc.
 
 # This script is for use with GNU awk.
 
 FILE=${1-/dev/null}
+: ${AWK=awk}
 
 $AWK '
 
diff --git a/doc/m4.texinfo b/doc/m4.texinfo
index 69cfb62..32cb0a9 100644
--- a/doc/m4.texinfo
+++ b/doc/m4.texinfo
@@ -933,7 +933,13 @@ exception of the @sc{nul} character (the zero byte 
@samp{'\0'}).
 @comment xout: null.out
 @comment xerr: null.err
 @example
-include(`null.m4')dnl
+define(`m4exit')include(`null.m4')dnl
address@hidden example
+
address@hidden status: 2
address@hidden
+include(`null.m4')
address@hidden This file tests m4 behavior on NUL bytes.
 @end example
 @end ignore
 
diff --git a/examples/null.m4 b/examples/null.m4
index 904a6ef..2632522 100644
Binary files a/examples/null.m4 and b/examples/null.m4 differ
diff --git a/examples/null.out b/examples/null.out
index 6e8a114..c42e03c 100644
Binary files a/examples/null.out and b/examples/null.out differ
diff --git a/src/input.c b/src/input.c
index a0de36f..e320c72 100644
--- a/src/input.c
+++ b/src/input.c
@@ -154,6 +154,7 @@ static bool input_change;
 #define CHAR_EOF       256     /* Character return on EOF.  */
 #define CHAR_MACRO     257     /* Character return for MACRO token.  */
 #define CHAR_QUOTE     258     /* Character return for quoted string.  */
+#define CHAR_ARGV      259     /* Character return for $@ reference.  */
 
 /* Quote chars.  */
 string_pair curr_quote;
@@ -446,7 +447,7 @@ push_token (token_data *token, int level, bool inuse)
       next->u.u_c.end = chain;
       if (chain->type == CHAIN_ARGV)
        {
-         assert (!chain->u.u_a.comma);
+         assert (!chain->u.u_a.comma && !chain->u.u_a.skip_last);
          inuse |= arg_adjust_refcount (chain->u.u_a.argv, true);
        }
       else if (chain->type == CHAIN_STR && chain->u.u_s.level >= 0)
@@ -712,17 +713,18 @@ input_print (struct obstack *obs, const input_block 
*input)
 }
 
 
-/*-----------------------------------------------------------------.
-| Low level input is done a character at a time.  The function     |
-| peek_input () 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.  The return value is an unsigned |
-| char, or CHAR_EOF if there is no more input, or CHAR_MACRO if a  |
-| builtin token occurs next.                                       |
-`-----------------------------------------------------------------*/
+/*------------------------------------------------------------------.
+| Low level input is done a character at a time.  The function      |
+| peek_input () 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.  The return value is an unsigned  |
+| char, CHAR_EOF if there is no more input, CHAR_MACRO if a builtin |
+| token occurs next, or CHAR_ARGV if ALLOW_ARGV and the input is    |
+| visiting an argv reference with the correct quoting.              |
+`------------------------------------------------------------------*/
 
 static int
-peek_input (void)
+peek_input (bool allow_argv)
 {
   int ch;
   input_block *block = isp;
@@ -757,6 +759,7 @@ peek_input (void)
          chain = block->u.u_c.chain;
          while (chain)
            {
+             unsigned int argc;
              switch (chain->type)
                {
                case CHAIN_STR:
@@ -764,11 +767,17 @@ peek_input (void)
                    return to_uchar (*chain->u.u_s.str);
                  break;
                case CHAIN_ARGV:
-                 /* TODO - pass multiple arguments to macro.c at once.  */
-                 if (chain->u.u_a.index == arg_argc (chain->u.u_a.argv))
+                 argc = arg_argc (chain->u.u_a.argv);
+                 if (chain->u.u_a.index == argc)
                    break;
                  if (chain->u.u_a.comma)
                    return ',';
+                 /* Only return a reference if the quoting is correct
+                    and the reference has more than one argument
+                    left.  */
+                 if (allow_argv && chain->quote_age == current_quote_age
+                     && 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.  */
@@ -778,7 +787,7 @@ peek_input (void)
                  chain->u.u_a.index++;
                  chain->u.u_a.comma = true;
                  push_string_finish ();
-                 return peek_input ();
+                 return peek_input (allow_argv);
                default:
                  assert (!"peek_input");
                  abort ();
@@ -871,9 +880,7 @@ next_char_1 (bool allow_quote)
          chain = isp->u.u_c.chain;
          while (chain)
            {
-             /* TODO also support returning $@ as CHAR_QUOTE.  */
-             if (allow_quote && chain->quote_age == current_quote_age
-                 && chain->type == CHAIN_STR)
+             if (allow_quote && chain->quote_age == current_quote_age)
                return CHAR_QUOTE;
              switch (chain->type)
                {
@@ -889,7 +896,6 @@ next_char_1 (bool allow_quote)
                    adjust_refcount (chain->u.u_s.level, false);
                  break;
                case CHAIN_ARGV:
-                 /* TODO - pass multiple arguments to macro.c at once.  */
                  if (chain->u.u_a.index == arg_argc (chain->u.u_a.argv))
                    {
                      arg_adjust_refcount (chain->u.u_a.argv, false);
@@ -956,7 +962,6 @@ skip_line (const char *name)
   if (file != current_file || line != current_line)
     input_change = true;
 }
-
 
 /*-------------------------------------------------------------------.
 | When a MACRO token is seen, next_token () uses init_macro_token () |
@@ -983,20 +988,30 @@ append_quote_token (struct obstack *obs, token_data *td)
   token_chain *src_chain = isp->u.u_c.chain;
   token_chain *chain;
 
-  assert (isp->type == INPUT_CHAIN && obs && current_quote_age
-         && src_chain->type == CHAIN_STR && src_chain->u.u_s.level >= 0);
+  assert (isp->type == INPUT_CHAIN && obs && current_quote_age);
   isp->u.u_c.chain = src_chain->next;
 
   /* Speed consideration - for short enough tokens, the speed and
      memory overhead of parsing another INPUT_CHAIN link outweighs the
      time to inline the token text.  */
-  if (src_chain->u.u_s.len <= INPUT_INLINE_THRESHOLD)
+  if (src_chain->type == CHAIN_STR
+      && src_chain->u.u_s.len <= INPUT_INLINE_THRESHOLD)
     {
+      assert (src_chain->u.u_s.level >= 0);
       obstack_grow (obs, src_chain->u.u_s.str, src_chain->u.u_s.len);
       adjust_refcount (src_chain->u.u_s.level, false);
       return;
     }
 
+  /* TODO preserve $@ through a quoted context.  */
+  if (src_chain->type == CHAIN_ARGV)
+    {
+      arg_print (obs, src_chain->u.u_a.argv, src_chain->u.u_a.index,
+                src_chain->u.u_a.quotes, NULL);
+      arg_adjust_refcount (src_chain->u.u_a.argv, false);
+      return;
+    }
+
   if (TOKEN_DATA_TYPE (td) == TOKEN_VOID)
     {
       TOKEN_DATA_TYPE (td) = TOKEN_COMP;
@@ -1013,6 +1028,65 @@ append_quote_token (struct obstack *obs, token_data *td)
   chain->next = NULL;
 }
 
+
+/*-------------------------------------------------------------------.
+| When an ARGV token is seen, convert TD to point to it via a       |
+| composite token.  Use OBS for any additional allocations needed to |
+| store the token chain.                                            |
+`-------------------------------------------------------------------*/
+static void
+init_argv_token (struct obstack *obs, token_data *td)
+{
+  token_chain *src_chain;
+  token_chain *chain;
+  int ch = next_char (true);
+
+  assert (ch == CHAR_QUOTE && TOKEN_DATA_TYPE (td) == TOKEN_VOID
+         && isp->type == INPUT_CHAIN && isp->u.u_c.chain->type == CHAIN_ARGV
+         && obs && obstack_object_size (obs) == 0);
+
+  src_chain = isp->u.u_c.chain;
+  isp->u.u_c.chain = src_chain->next;
+  TOKEN_DATA_TYPE (td) = TOKEN_COMP;
+  /* Clone the link, since the input will be discarded soon.  */
+  chain = (token_chain *) obstack_copy (obs, src_chain, sizeof *chain);
+  td->u.u_c.chain = td->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_1, 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 (*curr_comm.str1 != ',' && *curr_comm.str1 != ')'
+         && *curr_comm.str1 != *curr_quote.str1);
+  ch = peek_input (false);
+  if (ch != ',' && ch != ')')
+    {
+      isp->u.u_c.chain = src_chain;
+      src_chain->u.u_a.index = arg_argc (chain->u.u_a.argv) - 1;
+      src_chain->u.u_a.comma = true;
+      chain->u.u_a.skip_last = true;
+      arg_adjust_refcount (chain->u.u_a.argv, true);
+    }
+}
+
+
 /*------------------------------------------------------------------.
 | This function is for matching a string against a prefix of the    |
 | input stream.  If the string S matches the input and CONSUME is   |
@@ -1029,7 +1103,7 @@ match_input (const char *s, bool consume)
   const char *t;
   bool result = false;
 
-  ch = peek_input ();
+  ch = peek_input (false);
   if (ch != to_uchar (*s))
     return false;                      /* fail */
 
@@ -1041,7 +1115,7 @@ match_input (const char *s, bool consume)
     }
 
   next_char (false);
-  for (n = 1, t = s++; (ch = peek_input ()) == to_uchar (*s++); )
+  for (n = 1, t = s++; (ch = peek_input (false)) == to_uchar (*s++); )
     {
       next_char (false);
       n++;
@@ -1320,18 +1394,20 @@ safe_quotes (void)
 
 
 /*--------------------------------------------------------------------.
-| Parse a single token from the input stream, set TD to its           |
-| contents, and return its type.  A token is TOKEN_EOF if the         |
+| Parse a single token from the input stream, set TD to its          |
+| contents, and return its type.  A token is TOKEN_EOF if the        |
 | input_stack is empty; TOKEN_STRING for a quoted string or comment;  |
-| TOKEN_WORD for something that is a potential macro name; and        |
+| TOKEN_WORD for something that is a potential macro name; and       |
 | TOKEN_SIMPLE for any single character that is not a part of any of  |
 | the previous types.  If LINE is not NULL, set *LINE to the line     |
 | where the token starts.  If OBS is not NULL, expand TOKEN_STRING    |
 | directly into OBS rather than in token_stack temporary storage      |
-| area, and TD could be a TOKEN_COMP instead of the usual             |
-| TOKEN_TEXT.  Report errors (unterminated comments or strings) on    |
-| behalf of CALLER, if non-NULL.                                      |
-|                                                                     |
+| area, and TD could be a TOKEN_COMP instead of the usual            |
+| TOKEN_TEXT.  If ALLOW_ARGV, OBS must be non-NULL, and an entire     |
+| series of arguments can be returned as TOKEN_ARGV when a $@        |
+| reference is encountered.  Report errors (unterminated comments or  |
+| strings) on behalf of CALLER, if non-NULL.                         |
+|                                                                    |
 | Next_token () returns the token type, and passes back a pointer to  |
 | the token data through TD.  Non-string token text is collected on   |
 | the obstack token_stack, which never contains more than one token   |
@@ -1340,7 +1416,8 @@ safe_quotes (void)
 `--------------------------------------------------------------------*/
 
 token_type
-next_token (token_data *td, int *line, struct obstack *obs, const char *caller)
+next_token (token_data *td, int *line, struct obstack *obs, bool allow_argv,
+           const char *caller)
 {
   int ch;
   int quote_level;
@@ -1362,7 +1439,7 @@ next_token (token_data *td, int *line, struct obstack 
*obs, const char *caller)
 
   /* Can't consume character until after CHAR_MACRO is handled.  */
   TOKEN_DATA_TYPE (td) = TOKEN_VOID;
-  ch = peek_input ();
+  ch = peek_input (allow_argv && current_quote_age);
   if (ch == CHAR_EOF)
     {
 #ifdef DEBUG_INPUT
@@ -1381,6 +1458,17 @@ next_token (token_data *td, int *line, struct obstack 
*obs, const char *caller)
 #endif /* DEBUG_INPUT */
       return TOKEN_MACDEF;
     }
+  if (ch == CHAR_ARGV)
+    {
+      init_argv_token (obs, td);
+#ifdef DEBUG_INPUT
+      xfprintf (stderr, "next_token -> ARGV (%d args)\n",
+               (arg_argc (td->u.u_c.chain->u.u_a.argv)
+                - td->u.u_c.chain->u.u_a.index
+                - (td->u.u_c.chain->u.u_a.skip_last ? 1 : 0)));
+#endif
+      return TOKEN_ARGV;
+    }
 
   next_char (false); /* Consume character we already peeked at.  */
   file = current_file;
@@ -1409,7 +1497,8 @@ next_token (token_data *td, int *line, struct obstack 
*obs, const char *caller)
   else if (default_word_regexp && (isalpha (ch) || ch == '_'))
     {
       obstack_1grow (&token_stack, ch);
-      while ((ch = peek_input ()) < CHAR_EOF && (isalnum (ch) || ch == '_'))
+      while ((ch = peek_input (false)) < CHAR_EOF
+            && (isalnum (ch) || ch == '_'))
        {
          obstack_1grow (&token_stack, ch);
          next_char (false);
@@ -1424,7 +1513,7 @@ next_token (token_data *td, int *line, struct obstack 
*obs, const char *caller)
       obstack_1grow (&token_stack, ch);
       while (1)
        {
-         ch = peek_input ();
+         ch = peek_input (false);
          if (ch >= CHAR_EOF)
            break;
          obstack_1grow (&token_stack, ch);
@@ -1547,9 +1636,19 @@ next_token (token_data *td, int *line, struct obstack 
*obs, const char *caller)
                  token_type_string (type));
        while (chain)
          {
-           assert (chain->type == CHAIN_STR);
-           xfprintf (stderr, "%s", chain->u.u_s.str);
-           len += chain->u.u_s.len;
+           switch (chain->type)
+             {
+             case CHAIN_STR:
+               xfprintf (stderr, "%s", chain->u.u_s.str);
+               len += chain->u.u_s.len;
+               break;
+             case CHAIN_ARGV:
+               xfprintf (stderr, "address@hidden");
+               break;
+             default:
+               assert (!"next_token");
+               abort ();
+             }
            links++;
            chain = chain->next;
          }
@@ -1569,7 +1668,7 @@ token_type
 peek_token (void)
 {
   token_type result;
-  int ch = peek_input ();
+  int ch = peek_input (false);
 
   if (ch == CHAR_EOF)
     {
@@ -1684,7 +1783,7 @@ lex_debug (void)
   token_type t;
   token_data td;
 
-  while ((t = next_token (&td, NULL, NULL, "<debug>")) != TOKEN_EOF)
+  while ((t = next_token (&td, NULL, NULL, false, "<debug>")) != TOKEN_EOF)
     print_token ("lex", t, &td);
 }
 #endif /* DEBUG_INPUT */
diff --git a/src/m4.h b/src/m4.h
index 0f11366..7df29b8 100644
--- a/src/m4.h
+++ b/src/m4.h
@@ -266,7 +266,8 @@ enum token_type
   TOKEN_COMMA, /* Active character `,', TOKEN_TEXT.  */
   TOKEN_CLOSE, /* Active character `)', TOKEN_TEXT.  */
   TOKEN_SIMPLE,        /* Any other single character, TOKEN_TEXT.  */
-  TOKEN_MACDEF /* A macro's definition (see "defn"), TOKEN_FUNC.  */
+  TOKEN_MACDEF,        /* A macro's definition (see "defn"), TOKEN_FUNC.  */
+  TOKEN_ARGV   /* A series of parameters, TOKEN_COMP.  */
 };
 
 /* The data for a token, a macro argument, and a macro definition.  */
@@ -309,6 +310,7 @@ struct token_chain
          unsigned int 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 string_pair *quotes;    /* NULL for $*, quotes for 
address@hidden  */
        }
       u_a;
@@ -373,7 +375,8 @@ typedef enum token_data_type token_data_type;
 
 void input_init (void);
 token_type peek_token (void);
-token_type next_token (token_data *, int *, struct obstack *, const char *);
+token_type next_token (token_data *, int *, struct obstack *, bool,
+                      const char *);
 void skip_line (const char *);
 
 /* push back input */
diff --git a/src/macro.c b/src/macro.c
index d686b73..8b85cf6 100644
--- a/src/macro.c
+++ b/src/macro.c
@@ -216,7 +216,7 @@ expand_input (void)
   TOKEN_DATA_ORIG_TEXT (&empty_token) = "";
 #endif
 
-  while ((t = next_token (&td, &line, NULL, NULL)) != TOKEN_EOF)
+  while ((t = next_token (&td, &line, NULL, false, NULL)) != TOKEN_EOF)
     expand_token (NULL, t, &td, line, true);
 
   for (i = 0; i < stacks_count; i++)
@@ -364,7 +364,7 @@ expand_argument (struct obstack *obs, token_data *argp, 
const char *caller)
   /* Skip leading white space.  */
   do
     {
-      t = next_token (&td, NULL, obs, caller);
+      t = next_token (&td, NULL, obs, true, caller);
     }
   while (t == TOKEN_SIMPLE && isspace (to_uchar (*TOKEN_DATA_TEXT (&td))));
 
@@ -455,6 +455,20 @@ expand_argument (struct obstack *obs, token_data *argp, 
const char *caller)
            }
          break;
 
+       case TOKEN_ARGV:
+         assert (paren_level == 0 && TOKEN_DATA_TYPE (argp) == TOKEN_VOID
+                 && obstack_object_size (obs) == 0
+                 && td.u.u_c.chain == td.u.u_c.end
+                 && td.u.u_c.chain->type == CHAIN_ARGV);
+         TOKEN_DATA_TYPE (argp) = TOKEN_COMP;
+         argp->u.u_c.chain = argp->u.u_c.end = td.u.u_c.chain;
+         t = next_token (&td, NULL, NULL, false, caller);
+         if (argp->u.u_c.chain->u.u_a.skip_last)
+           assert (t == TOKEN_COMMA);
+         else
+           assert (t == TOKEN_COMMA || t == TOKEN_CLOSE);
+         return t == TOKEN_COMMA;
+
        default:
          assert (!"expand_argument");
          abort ();
@@ -462,7 +476,7 @@ expand_argument (struct obstack *obs, token_data *argp, 
const char *caller)
 
       if (TOKEN_DATA_TYPE (argp) != TOKEN_VOID || obstack_object_size (obs))
        first = false;
-      t = next_token (&td, NULL, obs, caller);
+      t = next_token (&td, NULL, obs, first, caller);
     }
 }
 
@@ -496,7 +510,8 @@ collect_arguments (symbol *sym, struct obstack *arguments,
 
   if (peek_token () == TOKEN_OPEN)
     {
-      next_token (&td, NULL, NULL, SYMBOL_NAME (sym)); /* gobble parenthesis */
+      /* gobble parenthesis */
+      next_token (&td, NULL, NULL, false, SYMBOL_NAME (sym));
       do
        {
          tdp = (token_data *) obstack_alloc (arguments, sizeof *tdp);
@@ -519,12 +534,22 @@ collect_arguments (symbol *sym, struct obstack *arguments,
              && TOKEN_DATA_QUOTE_AGE (tdp) != args.quote_age)
            args.quote_age = 0;
          else if (TOKEN_DATA_TYPE (tdp) == TOKEN_COMP)
-           args.has_ref = true;
+           {
+             args.has_ref = true;
+             if (tdp->u.u_c.chain->type == CHAIN_ARGV)
+               {
+                 args.argc += (tdp->u.u_c.chain->u.u_a.argv->argc
+                               - tdp->u.u_c.chain->u.u_a.index
+                               - tdp->u.u_c.chain->u.u_a.skip_last - 1);
+                 args.wrapper = true;
+               }
+           }
        }
       while (more_args);
     }
   argv = (macro_arguments *) obstack_finish (argv_stack);
   argv->argc = args.argc;
+  argv->wrapper = args.wrapper;
   argv->has_ref = args.has_ref;
   if (args.quote_age != quote_age ())
     argv->quote_age = 0;
@@ -734,9 +759,20 @@ arg_adjust_refcount (macro_arguments *argv, bool increase)
          chain = argv->array[i]->u.u_c.chain;
          while (chain)
            {
-             assert (chain->type == CHAIN_STR);
-             if (chain->u.u_s.level >= 0)
-               adjust_refcount (chain->u.u_s.level, increase);
+             switch (chain->type)
+               {
+               case CHAIN_STR:
+                 if (chain->u.u_s.level >= 0)
+                   adjust_refcount (chain->u.u_s.level, increase);
+                 break;
+               case CHAIN_ARGV:
+                 assert (chain->u.u_a.argv->inuse);
+                 arg_adjust_refcount (chain->u.u_a.argv, increase);
+                 break;
+               default:
+                 assert (!"arg_adjust_refcount");
+                 abort ();
+               }
              chain = chain->next;
            }
        }
@@ -766,12 +802,14 @@ arg_token (macro_arguments *argv, unsigned int index, int 
*level)
   for (i = 0; i < argv->arraylen; i++)
     {
       token = argv->array[i];
-      if (TOKEN_DATA_TYPE (token) == TOKEN_COMP)
+      if (TOKEN_DATA_TYPE (token) == TOKEN_COMP
+         && token->u.u_c.chain->type == CHAIN_ARGV)
        {
          token_chain *chain = token->u.u_c.chain;
          /* TODO - for now we support only a single-length $@ chain.  */
-         assert (!chain->next && chain->type == 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))
            {
              token = arg_token (chain->u.u_a.argv,
                                 chain->u.u_a.index - 1 + index, level);
@@ -780,7 +818,8 @@ arg_token (macro_arguments *argv, unsigned int index, int 
*level)
                token = &empty_token;
              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;
@@ -793,18 +832,24 @@ arg_token (macro_arguments *argv, unsigned int index, int 
*level)
 static void
 arg_mark (macro_arguments *argv)
 {
+  unsigned int i;
+  token_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
-             && TOKEN_DATA_TYPE (argv->array[0]) == TOKEN_COMP
-             && !argv->array[0]->u.u_c.chain->next
-             && argv->array[0]->u.u_c.chain->type == CHAIN_ARGV);
-      argv->array[0]->u.u_c.chain->u.u_a.argv->inuse = true;
-    }
+    for (i = 0; i < argv->arraylen; i++)
+      if (TOKEN_DATA_TYPE (argv->array[i]) == TOKEN_COMP)
+       {
+         chain = argv->array[i]->u.u_c.chain;
+         while (chain)
+           {
+             if (chain->type == CHAIN_ARGV && !chain->u.u_a.argv->inuse)
+               arg_mark (chain->u.u_a.argv);
+             chain = chain->next;
+           }
+       }
 }
 
 /* Given ARGV, return how many arguments it refers to.  */
@@ -854,14 +899,24 @@ arg_text (macro_arguments *argv, unsigned int index)
     case TOKEN_TEXT:
       return TOKEN_DATA_TEXT (token);
     case TOKEN_COMP:
-      /* TODO - concatenate multiple arguments?  For now, we assume
-        all elements are text.  */
+      /* TODO - concatenate functions.  */
       chain = token->u.u_c.chain;
       obs = arg_scratch ();
       while (chain)
        {
-         assert (chain->type == CHAIN_STR);
-         obstack_grow (obs, chain->u.u_s.str, chain->u.u_s.len);
+         switch (chain->type)
+           {
+           case CHAIN_STR:
+             obstack_grow (obs, chain->u.u_s.str, chain->u.u_s.len);
+             break;
+           case CHAIN_ARGV:
+             arg_print (obs, chain->u.u_a.argv, chain->u.u_a.index,
+                        chain->u.u_a.quotes, NULL);
+             break;
+           default:
+             assert (!"arg_text");
+             abort ();
+           }
          chain = chain->next;
        }
       obstack_1grow (obs, '\0');
@@ -1122,13 +1177,13 @@ make_argv_ref_token (token_data *token, struct obstack 
*obs, int level,
   token_chain *chain;
 
   assert (obstack_object_size (obs) == 0);
-  if (argv->wrapper)
+  if (argv->wrapper && argv->arraylen == 1)
     {
       /* TODO for now we support only a single-length $@ chain.  */
-      assert (argv->arraylen == 1
-             && TOKEN_DATA_TYPE (argv->array[0]) == TOKEN_COMP);
+      assert (TOKEN_DATA_TYPE (argv->array[0]) == TOKEN_COMP);
       chain = argv->array[0]->u.u_c.chain;
-      assert (!chain->next && chain->type == CHAIN_ARGV);
+      assert (!chain->next && chain->type == CHAIN_ARGV
+             && !chain->u.u_a.skip_last);
       argv = chain->u.u_a.argv;
       index += chain->u.u_a.index - 1;
     }
@@ -1145,6 +1200,7 @@ make_argv_ref_token (token_data *token, struct obstack 
*obs, int 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 a subsequent
diff --git a/src/symtab.c b/src/symtab.c
index 277a79f..dac49d7 100644
--- a/src/symtab.c
+++ b/src/symtab.c
@@ -350,7 +350,7 @@ symtab_debug (void)
   int delete;
   static int i;
 
-  while (next_token (&td, NULL, NULL, "<debug>") == TOKEN_WORD)
+  while (next_token (&td, NULL, NULL, false, "<debug>") == TOKEN_WORD)
     {
       text = TOKEN_DATA_TEXT (&td);
       if (*text == '_')


hooks/post-receive
--
GNU M4 source repository




reply via email to

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