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-46-


From: Eric Blake
Subject: [SCM] GNU M4 source repository branch, master, updated. cvs-readonly-46-g88382ff
Date: Sat, 26 Jan 2008 07:26:17 +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=88382ff9ef2efddf6279fb8af908ddd07210e70c

The branch, master has been updated
       via  88382ff9ef2efddf6279fb8af908ddd07210e70c (commit)
       via  726430fec6c0f3807f8f9e4d2c681f5300dc7694 (commit)
       via  29a7a47303ce73626300a1e3fd09f623bbd57e60 (commit)
      from  12bef65fbdfe4bca86718273e61a70e4828c620f (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 88382ff9ef2efddf6279fb8af908ddd07210e70c
Author: Eric Blake <address@hidden>
Date:   Sat Jan 26 00:08:48 2008 -0700

    Stage 12c: add macro for m4_arg_len.
    
    * m4/m4module.h (M4ARGLEN): New macro.
    * m4/macro.c (process_macro): Adjust all callers.
    * m4/utility.c (m4_dump_args): Likewise.
    * modules/m4.c (divert, maketemp, mkstemp, m4wrap, len, index)
    (substr): Likewise.
    * modules/gnu.c (builtin, indir, mkdtemp, patsubst, regexp)
    (renamesyms): Likewise.
    * modules/stdlib.c (setenv): Likewise.
    
    Signed-off-by: Eric Blake <address@hidden>

commit 726430fec6c0f3807f8f9e4d2c681f5300dc7694
Author: Eric Blake <address@hidden>
Date:   Fri Jan 25 23:49:38 2008 -0700

    Stage 12b: add m4_string_pair.
    
    * m4/m4module.h (m4_string_pair): New type.
    (m4_get_syntax_quotes, m4_get_syntax_comments): New prototypes.
    (m4_symbol_value_print, m4_symbol_print, m4_shipout_string_trunc):
    Alter signature.
    * m4/m4private.h (struct m4_string): Delete.
    (struct m4_syntax_table): Combine quote and comment members.
    (m4_get_syntax_lquote, m4_get_syntax_rquote, m4_get_syntax_bcomm)
    (m4_get_syntax_ecomm): Adjust accessors.
    (m4_get_syntax_quotes, m4_get_syntax_comments): New fast
    accessors.
    * m4/symtab.c (m4_symbol_value_print, m4_symbol_print):
    Alter signatures.
    * m4/input.c (string_print, composite_print, m4_input_print):
    All callers updated.
    * m4/syntax.c (m4_syntax_delete, m4_set_syntax)
    (check_is_single_quotes, m4_set_quotes, set_quote_age)
    (m4_get_syntax_lquote, m4_get_syntax_rquote)
    (m4_get_syntax_quotes, check_is_single_comments, m4_set_comment)
    (m4_get_syntax_bcomm, m4_get_syntax_ecomm)
    (m4_get_syntax_comments): Likewise.
    * m4/macro.c (trace_prepre, trace_pre, m4_push_args): Likewise.
    * m4/output.c (m4_shipout_string, m4_shipout_string_trunc):
    Likewise.
    * modules/m4.c (dumpdef, m4_make_temp): Likewise.
    * src/freeze.c (produce_frozen_state): Likewise.
    * tests/freeze.at (reloading unknown builtin): Update test.
    
    Signed-off-by: Eric Blake <address@hidden>

commit 29a7a47303ce73626300a1e3fd09f623bbd57e60
Author: Eric Blake <address@hidden>
Date:   Fri Jan 25 22:45:17 2008 -0700

    Stage 12a: make m4_symbol_chain a union.
    
    * m4/m4private.h (enum m4__symbol_chain_type): New enum.
    (struct m4_symbol_chain): Rename...
    (struct m4__symbol_chain): ...to this, since it is internal.
    * m4/symtab.c (m4_symbol_value_copy, m4_symbol_value_print): All
    callers updated.
    * m4/input.c (struct m4_input_block, m4__push_symbol)
    (composite_peek, composite_read, composite_unget)
    (composite_clean, m4__make_text_link, append_quote_token): Likewise.
    * m4/macro.c (expand_macro, arg_mark, m4_arg_symbol, m4_arg_text)
    (m4_arg_equal, m4_arg_len, m4_make_argv_ref, m4_push_arg)
    (m4_push_args): Likewise.
    
    Signed-off-by: Eric Blake <address@hidden>

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

Summary of changes:
 ChangeLog        |   63 ++++++++++++++++++
 m4/input.c       |  193 ++++++++++++++++++++++++++++--------------------------
 m4/m4module.h    |   32 +++++++--
 m4/m4private.h   |   67 +++++++++++--------
 m4/macro.c       |  149 +++++++++++++++++++++---------------------
 m4/output.c      |   29 ++++----
 m4/symtab.c      |   80 ++++++++++------------
 m4/syntax.c      |  150 +++++++++++++++++++++++-------------------
 m4/utility.c     |    5 +-
 modules/gnu.c    |   24 +++----
 modules/m4.c     |   44 +++++-------
 modules/stdlib.c |    9 ++-
 src/freeze.c     |   31 ++++-----
 tests/freeze.at  |    4 +-
 14 files changed, 488 insertions(+), 392 deletions(-)

diff --git a/ChangeLog b/ChangeLog
index 81643e7..25c408e 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,66 @@
+2008-01-26  Eric Blake  <address@hidden>
+
+       Stage 12c: add macro for m4_arg_len.
+       Make a common action easier to type.
+       Memory impact: none.
+       Speed impact: none.
+       * m4/m4module.h (M4ARGLEN): New macro.
+       * m4/macro.c (process_macro): Adjust all callers.
+       * m4/utility.c (m4_dump_args): Likewise.
+       * modules/m4.c (divert, maketemp, mkstemp, m4wrap, len, index)
+       (substr): Likewise.
+       * modules/gnu.c (builtin, indir, mkdtemp, patsubst, regexp)
+       (renamesyms): Likewise.
+       * modules/stdlib.c (setenv): Likewise.
+
+        Stage 12b: add m4_string_pair.
+        Make passing quote delimiters around more efficient.
+        Memory impact: none.
+        Speed impact: slight penalty, due to more bookkeeping.
+        * m4/m4module.h (m4_string_pair): New type.
+        (m4_get_syntax_quotes, m4_get_syntax_comments): New prototypes.
+        (m4_symbol_value_print, m4_symbol_print, m4_shipout_string_trunc):
+        Alter signature.
+        * m4/m4private.h (struct m4_string): Delete.
+        (struct m4_syntax_table): Combine quote and comment members.
+        (m4_get_syntax_lquote, m4_get_syntax_rquote, m4_get_syntax_bcomm)
+        (m4_get_syntax_ecomm): Adjust accessors.
+        (m4_get_syntax_quotes, m4_get_syntax_comments): New fast
+        accessors.
+        * m4/symtab.c (m4_symbol_value_print, m4_symbol_print):
+        Alter signatures.
+        * m4/input.c (string_print, composite_print, m4_input_print):
+        All callers updated.
+        * m4/syntax.c (m4_syntax_delete, m4_set_syntax)
+        (check_is_single_quotes, m4_set_quotes, set_quote_age)
+        (m4_get_syntax_lquote, m4_get_syntax_rquote)
+        (m4_get_syntax_quotes, check_is_single_comments, m4_set_comment)
+        (m4_get_syntax_bcomm, m4_get_syntax_ecomm)
+        (m4_get_syntax_comments): Likewise.
+        * m4/macro.c (trace_prepre, trace_pre, m4_push_args): Likewise.
+        * m4/output.c (m4_shipout_string, m4_shipout_string_trunc):
+        Likewise.
+        * modules/m4.c (dumpdef, m4_make_temp): Likewise.
+        * src/freeze.c (produce_frozen_state): Likewise.
+        * tests/freeze.at (reloading unknown builtin): Update test.
+
+        Stage 12a: make m4_symbol_chain a union.
+        Shrink size of symbol chains by using a union.
+        Memory impact: slight improvement, due to smaller struct.
+        Speed impact: slight improvement, due to less bookkeeping.
+        * m4/m4private.h (enum m4__symbol_chain_type): New enum.
+        (struct m4_symbol_chain): Rename...
+        (struct m4__symbol_chain): ...to this, since it is internal.
+        * m4/symtab.c (m4_symbol_value_copy, m4_symbol_value_print): All
+        callers updated.
+        * m4/input.c (struct m4_input_block, m4__push_symbol)
+        (composite_peek, composite_read, composite_unget)
+        (composite_clean, composite_print, m4__make_text_link)
+        (append_quote_token): Likewise.
+        * m4/macro.c (expand_macro, arg_mark, m4_arg_symbol, m4_arg_text)
+        (m4_arg_equal, m4_arg_len, m4_make_argv_ref, m4_push_arg)
+        (m4_push_args): Likewise.
+
 2008-01-23  Eric Blake  <address@hidden>
 
        Adjust to recent libtool interface change.
diff --git a/m4/input.c b/m4/input.c
index 0dcb0ae..4adce9d 100644
--- a/m4/input.c
+++ b/m4/input.c
@@ -186,8 +186,8 @@ struct m4_input_block
       u_b;     /* See builtin_funcs.  */
       struct
        {
-         m4_symbol_chain *chain;       /* Current link in chain.  */
-         m4_symbol_chain *end;         /* Last link in chain.  */
+         m4__symbol_chain *chain;      /* Current link in chain.  */
+         m4__symbol_chain *end;        /* Last link in chain.  */
        }
       u_c;     /* See composite_funcs.  */
     }
@@ -502,8 +502,9 @@ string_print (m4_input_block *me, m4 *context, m4_obstack 
*obs)
   bool quote = m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE);
   size_t arg_length = m4_get_max_debug_arg_length_opt (context);
 
-  m4_shipout_string_trunc (context, obs, me->u.u_s.str, me->u.u_s.len,
-                          quote, &arg_length);
+  m4_shipout_string_trunc (obs, me->u.u_s.str, me->u.u_s.len,
+                          quote ? m4_get_syntax_quotes (M4SYNTAX) : NULL,
+                          &arg_length);
 }
 
 /* First half of m4_push_string ().  The pointer next points to the
@@ -539,7 +540,7 @@ m4_push_string_init (m4 *context)
 bool
 m4__push_symbol (m4 *context, m4_symbol_value *value, size_t level)
 {
-  m4_symbol_chain *chain;
+  m4__symbol_chain *chain;
   bool result = false;
 
   assert (next);
@@ -562,20 +563,18 @@ m4__push_symbol (m4 *context, m4_symbol_value *value, 
size_t level)
       next->u.u_c.chain = next->u.u_c.end = NULL;
     }
   m4__make_text_link (current_input, &next->u.u_c.chain, &next->u.u_c.end);
-  chain = (m4_symbol_chain *) obstack_alloc (current_input, sizeof *chain);
+  chain = (m4__symbol_chain *) obstack_alloc (current_input, sizeof *chain);
   if (next->u.u_c.end)
     next->u.u_c.end->next = chain;
   else
     next->u.u_c.chain = chain;
   next->u.u_c.end = chain;
   chain->next = NULL;
+  chain->type = M4__CHAIN_STR;
   chain->quote_age = m4_get_symbol_value_quote_age (value);
-  chain->str = m4_get_symbol_value_text (value);
-  chain->len = m4_get_symbol_value_len (value);
-  chain->level = level;
-  chain->argv = NULL;
-  chain->index = 0;
-  chain->flatten = false;
+  chain->u.u_s.str = m4_get_symbol_value_text (value);
+  chain->u.u_s.len = m4_get_symbol_value_len (value);
+  chain->u.u_s.level = level;
   if (level < SIZE_MAX)
     {
       m4__adjust_refcount (context, level, true);
@@ -632,18 +631,19 @@ m4_push_string_finish (void)
 static int
 composite_peek (m4_input_block *me)
 {
-  m4_symbol_chain *chain = me->u.u_c.chain;
+  m4__symbol_chain *chain = me->u.u_c.chain;
   while (chain)
     {
-      if (chain->str)
-       {
-         if (chain->len)
-           return to_uchar (chain->str[0]);
-       }
-      else
+      switch (chain->type)
        {
+       case M4__CHAIN_STR:
+         if (chain->u.u_s.len)
+           return to_uchar (chain->u.u_s.str[0]);
+         break;
+       case M4__CHAIN_ARGV:
          /* TODO - peek into argv.  */
-         assert (!"implemented yet");
+       default:
+         assert (!"composite_peek");
          abort ();
        }
       chain = chain->next;
@@ -654,29 +654,30 @@ composite_peek (m4_input_block *me)
 static int
 composite_read (m4_input_block *me, m4 *context, bool allow_quote, bool safe)
 {
-  m4_symbol_chain *chain = me->u.u_c.chain;
+  m4__symbol_chain *chain = me->u.u_c.chain;
   while (chain)
     {
       if (allow_quote && chain->quote_age == m4__quote_age (M4SYNTAX))
        return CHAR_QUOTE;
-      if (chain->str)
+      switch (chain->type)
        {
-         if (chain->len)
+       case M4__CHAIN_STR:
+         if (chain->u.u_s.len)
            {
              /* Partial consumption invalidates quote age.  */
              chain->quote_age = 0;
-             chain->len--;
-             return to_uchar (*chain->str++);
+             chain->u.u_s.len--;
+             return to_uchar (*chain->u.u_s.str++);
            }
-       }
-      else
-       {
+         if (chain->u.u_s.level < SIZE_MAX)
+           m4__adjust_refcount (context, chain->u.u_s.level, false);
+         break;
+       case M4__CHAIN_ARGV:
          /* TODO - peek into argv.  */
-         assert (!"implemented yet");
+       default:
+         assert (!"composite_read");
          abort ();
        }
-      if (chain->level < SIZE_MAX)
-       m4__adjust_refcount (context, chain->level, false);
       me->u.u_c.chain = chain = chain->next;
     }
   return CHAR_RETRY;
@@ -685,17 +686,18 @@ composite_read (m4_input_block *me, m4 *context, bool 
allow_quote, bool safe)
 static void
 composite_unget (m4_input_block *me, int ch)
 {
-  m4_symbol_chain *chain = me->u.u_c.chain;
-  if (chain->str)
-    {
-      assert (ch < CHAR_EOF && to_uchar (chain->str[-1]) == ch);
-      chain->str--;
-      chain->len++;
-    }
-  else
+  m4__symbol_chain *chain = me->u.u_c.chain;
+  switch (chain->type)
     {
+    case M4__CHAIN_STR:
+      assert (ch < CHAR_EOF && to_uchar (chain->u.u_s.str[-1]) == ch);
+      chain->u.u_s.str--;
+      chain->u.u_s.len++;
+      break;
+    case M4__CHAIN_ARGV:
       /* TODO support argv ref.  */
-      assert (!"implemented yet");
+    default:
+      assert (!"composite_unget");
       abort ();
     }
 }
@@ -703,20 +705,23 @@ composite_unget (m4_input_block *me, int ch)
 static bool
 composite_clean (m4_input_block *me, m4 *context, bool cleanup)
 {
-  m4_symbol_chain *chain = me->u.u_c.chain;
+  m4__symbol_chain *chain = me->u.u_c.chain;
   assert (!chain || !cleanup);
   while (chain)
     {
-      if (chain->str)
-       assert (!chain->len);
-      else
+      switch (chain->type)
        {
+       case M4__CHAIN_STR:
+         assert (!chain->u.u_s.len);
+         if (chain->u.u_s.level < SIZE_MAX)
+           m4__adjust_refcount (context, chain->u.u_s.level, false);
+         break;
+       case M4__CHAIN_ARGV:
          /* TODO - peek into argv.  */
-         assert (!"implemented yet");
+       default:
+         assert (!"composite_clean");
          abort ();
        }
-      if (chain->level < SIZE_MAX)
-       m4__adjust_refcount (context, chain->level, false);
       me->u.u_c.chain = chain = chain->next;
     }
   return true;
@@ -727,53 +732,59 @@ composite_print (m4_input_block *me, m4 *context, 
m4_obstack *obs)
 {
   bool quote = m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE);
   size_t maxlen = m4_get_max_debug_arg_length_opt (context);
-  m4_symbol_chain *chain = me->u.u_c.chain;
-  const char *lquote = m4_get_syntax_lquote (M4SYNTAX);
-  const char *rquote = m4_get_syntax_rquote (M4SYNTAX);
+  m4__symbol_chain *chain = me->u.u_c.chain;
+  const m4_string_pair *quotes = m4_get_syntax_quotes (M4SYNTAX);
+  bool done = false;
 
   if (quote)
-    m4_shipout_string (context, obs, lquote, SIZE_MAX, false);
-  while (chain)
+    m4_shipout_string (context, obs, quotes->str1, quotes->len1, false);
+  while (chain && !done)
     {
-      /* TODO support argv refs as well.  */
-      assert (chain->str);
-      if (m4_shipout_string_trunc (context, obs, chain->str, chain->len, false,
-                                  &maxlen))
-       break;
+      switch (chain->type)
+       {
+       case M4__CHAIN_STR:
+         if (m4_shipout_string_trunc (obs, chain->u.u_s.str,
+                                      chain->u.u_s.len, NULL, &maxlen))
+           done = true;
+         break;
+       case M4__CHAIN_ARGV:
+         /* TODO support argv refs as well.  */
+       default:
+         assert (!"composite_print");
+         abort ();
+       }
       chain = chain->next;
     }
   if (quote)
-    m4_shipout_string (context, obs, rquote, SIZE_MAX, false);
+    m4_shipout_string (context, obs, quotes->str2, quotes->len2, false);
 }
 
 /* Given an obstack OBS, capture any unfinished text as a link in the
    chain that starts at *START and ends at *END.  START may be NULL if
    *END is non-NULL.  */
 void
-m4__make_text_link (m4_obstack *obs, m4_symbol_chain **start,
-                   m4_symbol_chain **end)
+m4__make_text_link (m4_obstack *obs, m4__symbol_chain **start,
+                   m4__symbol_chain **end)
 {
-  m4_symbol_chain *chain;
+  m4__symbol_chain *chain;
   size_t len = obstack_object_size (obs);
 
   assert (end && (start || *end));
   if (len)
     {
       char *str = (char *) obstack_finish (obs);
-      chain = (m4_symbol_chain *) obstack_alloc (obs, sizeof *chain);
+      chain = (m4__symbol_chain *) obstack_alloc (obs, sizeof *chain);
       if (*end)
        (*end)->next = chain;
       else
        *start = chain;
       *end = chain;
       chain->next = NULL;
+      chain->type = M4__CHAIN_STR;
       chain->quote_age = 0;
-      chain->str = str;
-      chain->len = len;
-      chain->level = SIZE_MAX;
-      chain->argv = NULL;
-      chain->index = 0;
-      chain->flatten = false;
+      chain->u.u_s.str = str;
+      chain->u.u_s.len = len;
+      chain->u.u_s.level = SIZE_MAX;
     }
 }
 
@@ -787,13 +798,11 @@ m4_input_print (m4 *context, m4_obstack *obs, 
m4_input_block *input)
   assert (context && obs);
   if (input == NULL)
     {
-      bool quote = m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE);
-      if (quote)
+      if (m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE))
        {
-         const char *lquote = m4_get_syntax_lquote (M4SYNTAX);
-         const char *rquote = m4_get_syntax_rquote (M4SYNTAX);
-         obstack_grow (obs, lquote, strlen (lquote));
-         obstack_grow (obs, rquote, strlen (rquote));
+         const m4_string_pair *quotes = m4_get_syntax_quotes (M4SYNTAX);
+         obstack_grow (obs, quotes->str1, quotes->len1);
+         obstack_grow (obs, quotes->str2, quotes->len2);
        }
     }
   else
@@ -918,8 +927,8 @@ init_builtin_token (m4 *context, m4_symbol_value *token)
 static void
 append_quote_token (m4_obstack *obs, m4_symbol_value *value)
 {
-  m4_symbol_chain *src_chain = isp->u.u_c.chain;
-  m4_symbol_chain *chain;
+  m4__symbol_chain *src_chain = isp->u.u_c.chain;
+  m4__symbol_chain *chain;
   assert (isp->funcs == &composite_funcs && obs);
 
   if (value->type == M4_SYMBOL_VOID)
@@ -929,7 +938,7 @@ append_quote_token (m4_obstack *obs, m4_symbol_value *value)
     }
   assert (value->type == M4_SYMBOL_COMP);
   m4__make_text_link (obs, &value->u.u_c.chain, &value->u.u_c.end);
-  chain = (m4_symbol_chain *) obstack_copy (obs, src_chain, sizeof *chain);
+  chain = (m4__symbol_chain *) obstack_copy (obs, src_chain, sizeof *chain);
   if (value->u.u_c.end)
     value->u.u_c.end->next = chain;
   else
@@ -1302,7 +1311,7 @@ m4__next_token (m4 *context, m4_symbol_value *token, int 
*line,
        type = M4_TOKEN_STRING;
       }
     else if (!m4_is_syntax_single_quotes (M4SYNTAX)
-            && MATCH (context, ch, context->syntax->lquote.string, true))
+            && MATCH (context, ch, context->syntax->quote.str1, true))
       {                                        /* QUOTED STRING, LONGER QUOTES 
*/
        if (obs)
          obs_safe = obs;
@@ -1314,18 +1323,18 @@ m4__next_token (m4 *context, m4_symbol_value *token, 
int *line,
            if (ch == CHAR_EOF)
              m4_error_at_line (context, EXIT_FAILURE, 0, file, *line, caller,
                                _("end of file in string"));
-           if (MATCH (context, ch, context->syntax->rquote.string, true))
+           if (MATCH (context, ch, context->syntax->quote.str2, true))
              {
                if (--quote_level == 0)
                  break;
-               obstack_grow (obs_safe, context->syntax->rquote.string,
-                             context->syntax->rquote.length);
+               obstack_grow (obs_safe, context->syntax->quote.str2,
+                             context->syntax->quote.len2);
              }
-           else if (MATCH (context, ch, context->syntax->lquote.string, true))
+           else if (MATCH (context, ch, context->syntax->quote.str1, true))
              {
                quote_level++;
-               obstack_grow (obs_safe, context->syntax->lquote.string,
-                             context->syntax->lquote.length);
+               obstack_grow (obs_safe, context->syntax->quote.str1,
+                             context->syntax->quote.len2);
              }
            else
              obstack_1grow (obs_safe, ch);
@@ -1352,20 +1361,20 @@ m4__next_token (m4 *context, m4_symbol_value *token, 
int *line,
                ? M4_TOKEN_NONE : M4_TOKEN_STRING);
       }
     else if (!m4_is_syntax_single_comments (M4SYNTAX)
-            && MATCH (context, ch, context->syntax->bcomm.string, true))
+            && MATCH (context, ch, context->syntax->comm.str1, true))
       {                                        /* COMMENT, LONGER DELIM */
        if (obs && !m4_get_discard_comments_opt (context))
          obs_safe = obs;
-       obstack_grow (obs_safe, context->syntax->bcomm.string,
-                     context->syntax->bcomm.length);
+       obstack_grow (obs_safe, context->syntax->comm.str1,
+                     context->syntax->comm.len1);
        while ((ch = next_char (context, false, true)) < CHAR_EOF
-              && !MATCH (context, ch, context->syntax->ecomm.string, true))
+              && !MATCH (context, ch, context->syntax->comm.str2, true))
          obstack_1grow (obs_safe, ch);
        if (ch != CHAR_EOF)
          {
            assert (ch < CHAR_EOF);
-           obstack_grow (obs_safe, context->syntax->ecomm.string,
-                         context->syntax->ecomm.length);
+           obstack_grow (obs_safe, context->syntax->comm.str2,
+                         context->syntax->comm.len2);
          }
        else
          m4_error_at_line (context, EXIT_FAILURE, 0, file, *line, caller,
@@ -1487,9 +1496,9 @@ m4__next_token_is_open (m4 *context)
                                       | M4_SYNTAX_ALPHA | M4_SYNTAX_LQUOTE
                                       | M4_SYNTAX_ACTIVE))
       || (!m4_is_syntax_single_comments (M4SYNTAX)
-         && MATCH (context, ch, context->syntax->bcomm.string, false))
+         && MATCH (context, ch, context->syntax->comm.str1, false))
       || (!m4_is_syntax_single_quotes (M4SYNTAX)
-         && MATCH (context, ch, context->syntax->lquote.string, false)))
+         && MATCH (context, ch, context->syntax->quote.str1, false)))
     return false;
   return m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_OPEN);
 }
diff --git a/m4/m4module.h b/m4/m4module.h
index 330a90e..24d6a45 100644
--- a/m4/m4module.h
+++ b/m4/m4module.h
@@ -38,6 +38,7 @@ typedef struct m4_symbol_value        m4_symbol_value;
 typedef struct m4_input_block  m4_input_block;
 typedef struct m4_module       m4_module;
 typedef struct m4_macro_args   m4_macro_args;
+typedef struct m4_string_pair  m4_string_pair;
 
 typedef struct obstack         m4_obstack;
 
@@ -77,6 +78,15 @@ struct m4_macro
   const char *value;
 };
 
+/* Describe a pair of strings, such as begin and end quotes.  */
+struct m4_string_pair
+{
+  char *str1;          /* First string.  */
+  size_t len1;         /* First length.  */
+  char *str2;          /* Second string.  */
+  size_t len2;         /* Second length.  */
+};
+
 #define M4BUILTIN(name)                                                        
\
   static void CONC (builtin_, name)                                    \
    (m4 *context, m4_obstack *obs, unsigned int argc, m4_macro_args *argv);
@@ -106,6 +116,11 @@ struct m4_macro
    in scope.  */
 #define M4ARG(i) m4_arg_text (context, argv, i)
 
+/* Grab the length of the text contents of argument I, or abort if the
+   argument is not text.  Assumes that `m4_macro_args *argv' is in
+   scope.  */
+#define M4ARGLEN(i) m4_arg_len (argv, i)
+
 extern bool    m4_bad_argc        (m4 *, int, const char *,
                                    unsigned int, unsigned int, bool);
 extern bool    m4_numeric_arg     (m4 *, const char *, const char *, int *);
@@ -231,12 +246,11 @@ extern m4_symbol_value *m4_get_symbol_value         
(m4_symbol*);
 extern bool            m4_get_symbol_traced      (m4_symbol*);
 extern bool            m4_set_symbol_name_traced (m4_symbol_table*,
                                                   const char *, bool);
-extern void    m4_symbol_value_print   (m4_symbol_value *, m4_obstack *, bool,
-                                        const char *, const char *, size_t,
+extern void    m4_symbol_value_print   (m4_symbol_value *, m4_obstack *,
+                                        const m4_string_pair *, size_t, bool);
+extern void    m4_symbol_print         (m4_symbol *, m4_obstack *,
+                                        const m4_string_pair *, bool, size_t,
                                         bool);
-extern void    m4_symbol_print         (m4_symbol *, m4_obstack *, bool,
-                                        const char *, const char *, bool,
-                                        size_t, bool);
 extern bool    m4_symbol_value_groks_macro     (m4_symbol_value *);
 
 #define m4_is_symbol_void(symbol)                                      \
@@ -313,7 +327,7 @@ extern size_t       m4_arg_len              (m4_macro_args 
*, unsigned int);
 extern m4_builtin_func *m4_arg_func    (m4_macro_args *, unsigned int);
 extern m4_obstack *m4_arg_scratch      (m4 *);
 extern m4_macro_args *m4_make_argv_ref (m4 *, m4_macro_args *, const char *,
-                                         size_t, bool, bool);
+                                        size_t, bool, bool);
 extern void    m4_push_arg             (m4 *, m4_obstack *, m4_macro_args *,
                                         unsigned int);
 extern void    m4_push_args            (m4 *, m4_obstack *, m4_macro_args *,
@@ -384,6 +398,8 @@ extern      const char *     m4_get_syntax_lquote   
(m4_syntax_table *syntax);
 extern const char *     m4_get_syntax_rquote   (m4_syntax_table *syntax);
 extern const char *     m4_get_syntax_bcomm    (m4_syntax_table *syntax);
 extern const char *     m4_get_syntax_ecomm    (m4_syntax_table *syntax);
+extern const m4_string_pair *m4_get_syntax_quotes      (m4_syntax_table *);
+extern const m4_string_pair *m4_get_syntax_comments    (m4_syntax_table *);
 
 extern bool             m4_is_syntax_single_quotes     (m4_syntax_table *);
 extern bool             m4_is_syntax_single_comments   (m4_syntax_table *);
@@ -462,8 +478,8 @@ extern void m4_divert_text          (m4 *, m4_obstack *, 
const char *,
 extern void    m4_shipout_int          (m4_obstack *, int);
 extern void    m4_shipout_string       (m4 *, m4_obstack *, const char *,
                                         size_t, bool);
-extern bool    m4_shipout_string_trunc (m4 *, m4_obstack *, const char *,
-                                        size_t, bool, size_t *);
+extern bool    m4_shipout_string_trunc (m4_obstack *, const char *, size_t,
+                                        const m4_string_pair *, size_t *);
 
 extern void    m4_make_diversion    (m4 *, int);
 extern void    m4_insert_diversion  (m4 *, int);
diff --git a/m4/m4private.h b/m4/m4private.h
index 6a08455..4261c4c 100644
--- a/m4/m4private.h
+++ b/m4/m4private.h
@@ -185,7 +185,7 @@ extern m4_module *  m4__module_find (const char *name);
 
 /* --- SYMBOL TABLE MANAGEMENT --- */
 
-typedef struct m4_symbol_chain m4_symbol_chain;
+typedef struct m4__symbol_chain m4__symbol_chain;
 
 struct m4_symbol
 {
@@ -193,17 +193,35 @@ struct m4_symbol
   m4_symbol_value *value;      /* Linked list of pushdef'd values.  */
 };
 
+/* Type of a link in a symbol chain.  */
+enum m4__symbol_chain_type
+{
+  M4__CHAIN_STR,       /* Link contains a string, u.u_s is valid.  */
+  /* TODO Add M4__CHAIN_FUNC.  */
+  M4__CHAIN_ARGV       /* Link contains a $@ reference, u.u_a is valid.  */
+};
+
 /* Composite symbols are built of a linked list of chain objects.  */
-struct m4_symbol_chain
+struct m4__symbol_chain
 {
-  m4_symbol_chain *next;/* Pointer to next link of chain.  */
-  unsigned int quote_age; /* Quote_age of this link of chain, or 0.  */
-  const char *str;     /* NUL-terminated string if text, or NULL.  */
-  size_t len;          /* Length of str, or 0.  */
-  size_t level;                /* Expansion level of content, or SIZE_MAX.  */
-  m4_macro_args *argv; /* Reference to earlier address@hidden  */
-  unsigned int index;  /* Argument index within argv.  */
-  bool flatten;                /* True to treat builtins as text.  */
+  m4__symbol_chain *next;              /* Pointer to next link of chain.  */
+  enum m4__symbol_chain_type type;     /* Type of this link.  */
+  unsigned int quote_age;              /* Quote_age of this link, or 0.  */
+  union
+  {
+    struct
+    {
+      const char *str;         /* Pointer to text.  */
+      size_t len;              /* Remaining length of str.  */
+      size_t level;            /* Expansion level of content, or SIZE_MAX.  */
+    } u_s;                     /* M4__CHAIN_STR.  */
+    struct
+    {
+      m4_macro_args *argv;     /* Reference to earlier address@hidden  */
+      unsigned int index;      /* Argument index within argv.  */
+      bool flatten;            /* True to treat builtins as text.  */
+    } u_a;                     /* M4__CHAIN_ARGV.  */
+  } u;
 };
 
 /* A symbol value is used both for values associated with a macro
@@ -233,8 +251,8 @@ struct m4_symbol_value
     const m4_builtin * builtin;/* Valid when type is FUNC.  */
     struct
     {
-      m4_symbol_chain *        chain;  /* First link of the chain.  */
-      m4_symbol_chain *        end;    /* Last link of the chain.  */
+      m4__symbol_chain *chain; /* First link of the chain.  */
+      m4__symbol_chain *end;   /* Last link of the chain.  */
     } u_c;                     /* Valid when type is COMP.  */
   } u;
 };
@@ -381,21 +399,14 @@ extern void m4__symtab_remove_module_references 
(m4_symbol_table*,
 #define DEF_BCOMM      "#"     /* Default begin comment delimiter.  */
 #define DEF_ECOMM      "\n"    /* Default end comment delimiter.  */
 
-typedef struct {
-  char *string;                /* characters of the string */
-  size_t length;       /* length of the string */
-} m4_string;
-
 struct m4_syntax_table {
   /* Please read the comment at the top of input.c for details.  table
      holds the current syntax, and orig holds the default syntax.  */
   unsigned short table[CHAR_RETRY];
   unsigned short orig[CHAR_RETRY];
 
-  m4_string lquote;
-  m4_string rquote;
-  m4_string bcomm;
-  m4_string ecomm;
+  m4_string_pair quote;        /* Quote delimiters.  */
+  m4_string_pair comm; /* Comment delimiters.  */
 
   /* True iff strlen(lquote) == strlen(rquote) == 1 and lquote is not
      interfering with macro names.  */
@@ -424,10 +435,12 @@ struct m4_syntax_table {
 /* Fast macro versions of syntax table accessor functions,
    that also have an identically named function exported in m4module.h.  */
 #ifdef NDEBUG
-#  define m4_get_syntax_lquote(S)              ((S)->lquote.string)
-#  define m4_get_syntax_rquote(S)              ((S)->rquote.string)
-#  define m4_get_syntax_bcomm(S)               ((S)->bcomm.string)
-#  define m4_get_syntax_ecomm(S)               ((S)->ecomm.string)
+#  define m4_get_syntax_lquote(S)              ((S)->quote.str1)
+#  define m4_get_syntax_rquote(S)              ((S)->quote.str2)
+#  define m4_get_syntax_bcomm(S)               ((S)->comm.str1)
+#  define m4_get_syntax_ecomm(S)               ((S)->comm.str2)
+#  define m4_get_syntax_quotes(S)              (&(S)->quote)
+#  define m4_get_syntax_comments(S)            (&(S)->comm)
 
 #  define m4_is_syntax_single_quotes(S)                ((S)->is_single_quotes)
 #  define m4_is_syntax_single_comments(S)      ((S)->is_single_comments)
@@ -460,8 +473,8 @@ typedef enum {
   M4_TOKEN_MACDEF      /* Macro's definition (see "defn"), M4_SYMBOL_FUNC.  */
 } m4__token_type;
 
-extern void            m4__make_text_link (m4_obstack *, m4_symbol_chain **,
-                                           m4_symbol_chain **);
+extern void            m4__make_text_link (m4_obstack *, m4__symbol_chain **,
+                                           m4__symbol_chain **);
 extern bool            m4__push_symbol (m4 *, m4_symbol_value *, size_t);
 extern m4__token_type  m4__next_token (m4 *, m4_symbol_value *, int *,
                                        m4_obstack *, const char *);
diff --git a/m4/macro.c b/m4/macro.c
index 683dd26..88ee391 100644
--- a/m4/macro.c
+++ b/m4/macro.c
@@ -525,7 +525,7 @@ recursion limit of %zu exceeded, use -L<N> to change it"),
   /* If argv contains references, those refcounts must be reduced now.  */
   if (argv->has_ref)
     {
-      m4_symbol_chain *chain;
+      m4__symbol_chain *chain;
       size_t i;
       for (i = 0; i < argv->arraylen; i++)
        if (argv->array[i]->type == M4_SYMBOL_COMP)
@@ -533,8 +533,9 @@ recursion limit of %zu exceeded, use -L<N> to change it"),
            chain = argv->array[i]->u.u_c.chain;
            while (chain)
              {
-               if (chain->level < SIZE_MAX)
-                 m4__adjust_refcount (context, chain->level, false);
+               assert (chain->type == M4__CHAIN_STR);
+               if (chain->u.u_s.level < SIZE_MAX)
+                 m4__adjust_refcount (context, chain->u.u_s.level, false);
                chain = chain->next;
              }
          }
@@ -762,8 +763,8 @@ process_macro (m4 *context, m4_symbol_value *value, 
m4_obstack *obs,
                    {
                      i = SYMBOL_ARG_INDEX (*arg);
                      assert (i < argc);
-                     m4_shipout_string (context, obs, M4ARG (i),
-                                        m4_arg_len (argv, i), false);
+                     m4_shipout_string (context, obs, M4ARG (i), M4ARGLEN (i),
+                                        false);
                    }
                }
              else
@@ -887,16 +888,16 @@ trace_flush (m4 *context)
 static void
 trace_prepre (m4 *context, const char *name, size_t id, m4_symbol_value *value)
 {
-  bool quote = m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE);
-  const char *lquote = m4_get_syntax_lquote (M4SYNTAX);
-  const char *rquote = m4_get_syntax_rquote (M4SYNTAX);
+  const m4_string_pair *quotes = NULL;
   size_t arg_length = m4_get_max_debug_arg_length_opt (context);
   bool module = m4_is_debug_bit (context, M4_DEBUG_TRACE_MODULE);
 
+  if (m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE))
+    quotes = m4_get_syntax_quotes (M4SYNTAX);
   trace_header (context, id);
   trace_format (context, "%s ... = ", name);
-  m4_symbol_value_print (value, &context->trace_messages,
-                        quote, lquote, rquote, arg_length, module);
+  m4_symbol_value_print (value, &context->trace_messages, quotes, arg_length,
+                        module);
   trace_flush (context);
 }
 
@@ -913,12 +914,12 @@ trace_pre (m4 *context, size_t id, m4_macro_args *argv)
 
   if (1 < argc && m4_is_debug_bit (context, M4_DEBUG_TRACE_ARGS))
     {
-      bool quote = m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE);
-      const char *lquote = m4_get_syntax_lquote (M4SYNTAX);
-      const char *rquote = m4_get_syntax_rquote (M4SYNTAX);
+      const m4_string_pair *quotes = NULL;
       size_t arg_length = m4_get_max_debug_arg_length_opt (context);
       bool module = m4_is_debug_bit (context, M4_DEBUG_TRACE_MODULE);
 
+      if (m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE))
+       quotes = m4_get_syntax_quotes (M4SYNTAX);
       trace_format (context, "(");
       for (i = 1; i < argc; i++)
        {
@@ -926,8 +927,8 @@ trace_pre (m4 *context, size_t id, m4_macro_args *argv)
            trace_format (context, ", ");
 
          m4_symbol_value_print (m4_arg_symbol (argv, i),
-                                &context->trace_messages, quote, lquote,
-                                rquote, arg_length, module);
+                                &context->trace_messages, quotes, arg_length,
+                                module);
        }
       trace_format (context, ")");
     }
@@ -991,8 +992,8 @@ arg_mark (m4_macro_args *argv)
       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->str);
-      argv->array[0]->u.u_c.chain->argv->inuse = true;
+             && argv->array[0]->u.u_c.chain->type == M4__CHAIN_ARGV);
+      argv->array[0]->u.u_c.chain->u.u_a.argv->inuse = true;
     }
 }
 
@@ -1017,17 +1018,18 @@ m4_arg_symbol (m4_macro_args *argv, unsigned int index)
       value = argv->array[i];
       if (value->type == M4_SYMBOL_COMP)
        {
-         m4_symbol_chain *chain = value->u.u_c.chain;
+         m4__symbol_chain *chain = value->u.u_c.chain;
          /* TODO - for now we support only a single $@ chain.  */
-         assert (!chain->next && !chain->str);
-         if (index < chain->argv->argc - (chain->index - 1))
+         assert (!chain->next && chain->type == M4__CHAIN_ARGV);
+         if (index < chain->u.u_a.argv->argc - (chain->u.u_a.index - 1))
            {
-             value = m4_arg_symbol (chain->argv, chain->index - 1 + index);
-             if (chain->flatten && m4_is_symbol_value_func (value))
+             value = m4_arg_symbol (chain->u.u_a.argv,
+                                    chain->u.u_a.index - 1 + index);
+             if (chain->u.u_a.flatten && m4_is_symbol_value_func (value))
                value = &empty_symbol;
              break;
            }
-         index -= chain->argv->argc - chain->index;
+         index -= chain->u.u_a.argv->argc - chain->u.u_a.index;
        }
       else if (--index == 0)
        break;
@@ -1068,7 +1070,7 @@ const char *
 m4_arg_text (m4 *context, m4_macro_args *argv, unsigned int index)
 {
   m4_symbol_value *value;
-  m4_symbol_chain *chain;
+  m4__symbol_chain *chain;
   m4_obstack *obs;
 
   if (index == 0)
@@ -1085,8 +1087,8 @@ m4_arg_text (m4 *context, m4_macro_args *argv, unsigned 
int index)
   obs = m4_arg_scratch (context);
   while (chain)
     {
-      assert (chain->str);
-      obstack_grow (obs, chain->str, chain->len);
+      assert (chain->type == M4__CHAIN_STR);
+      obstack_grow (obs, chain->u.u_s.str, chain->u.u_s.len);
       chain = chain->next;
     }
   obstack_1grow (obs, '\0');
@@ -1103,10 +1105,10 @@ m4_arg_equal (m4_macro_args *argv, unsigned int indexa, 
unsigned int indexb)
 {
   m4_symbol_value *sa = m4_arg_symbol (argv, indexa);
   m4_symbol_value *sb = m4_arg_symbol (argv, indexb);
-  m4_symbol_chain tmpa;
-  m4_symbol_chain tmpb;
-  m4_symbol_chain *ca = &tmpa;
-  m4_symbol_chain *cb = &tmpb;
+  m4__symbol_chain tmpa;
+  m4__symbol_chain tmpb;
+  m4__symbol_chain *ca = &tmpa;
+  m4__symbol_chain *cb = &tmpb;
 
   /* Quick tests.  */
   if (sa == &empty_symbol || sb == &empty_symbol)
@@ -1122,8 +1124,9 @@ m4_arg_equal (m4_macro_args *argv, unsigned int indexa, 
unsigned int indexb)
   if (m4_is_symbol_value_text (sa))
     {
       tmpa.next = NULL;
-      tmpa.str = m4_get_symbol_value_text (sa);
-      tmpa.len = m4_get_symbol_value_len (sa);
+      tmpa.type = M4__CHAIN_STR;
+      tmpa.u.u_s.str = m4_get_symbol_value_text (sa);
+      tmpa.u.u_s.len = m4_get_symbol_value_len (sa);
     }
   else
     {
@@ -1133,8 +1136,9 @@ m4_arg_equal (m4_macro_args *argv, unsigned int indexa, 
unsigned int indexb)
   if (m4_is_symbol_value_text (sb))
     {
       tmpb.next = NULL;
-      tmpb.str = m4_get_symbol_value_text (sb);
-      tmpb.len = m4_get_symbol_value_len (sb);
+      tmpb.type = M4__CHAIN_STR;
+      tmpb.u.u_s.str = m4_get_symbol_value_text (sb);
+      tmpb.u.u_s.len = m4_get_symbol_value_len (sb);
     }
   else
     {
@@ -1146,32 +1150,32 @@ m4_arg_equal (m4_macro_args *argv, unsigned int indexa, 
unsigned int indexb)
   while (ca && cb)
     {
       /* TODO support comparison against $@ refs.  */
-      assert (ca->str && cb->str);
-      if (ca->len == cb->len)
+      assert (ca->type == M4__CHAIN_STR && cb->type == M4__CHAIN_STR);
+      if (ca->u.u_s.len == cb->u.u_s.len)
        {
-         if (memcmp (ca->str, cb->str, ca->len) != 0)
+         if (memcmp (ca->u.u_s.str, cb->u.u_s.str, ca->u.u_s.len) != 0)
            return false;
          ca = ca->next;
          cb = cb->next;
        }
-      else if (ca->len < cb->len)
+      else if (ca->u.u_s.len < cb->u.u_s.len)
        {
-         if (memcmp (ca->str, cb->str, ca->len) != 0)
+         if (memcmp (ca->u.u_s.str, cb->u.u_s.str, ca->u.u_s.len) != 0)
            return false;
          tmpb.next = cb->next;
-         tmpb.str = cb->str + ca->len;
-         tmpb.len = cb->len - ca->len;
+         tmpb.u.u_s.str = cb->u.u_s.str + ca->u.u_s.len;
+         tmpb.u.u_s.len = cb->u.u_s.len - ca->u.u_s.len;
          ca = ca->next;
          cb = &tmpb;
        }
       else
        {
-         assert (cb->len < ca->len);
-         if (memcmp (ca->str, cb->str, cb->len) != 0)
+         assert (cb->u.u_s.len < ca->u.u_s.len);
+         if (memcmp (ca->u.u_s.str, cb->u.u_s.str, cb->u.u_s.len) != 0)
            return false;
          tmpa.next = ca->next;
-         tmpa.str = ca->str + cb->len;
-         tmpa.len = ca->len - cb->len;
+         tmpa.u.u_s.str = ca->u.u_s.str + cb->u.u_s.len;
+         tmpa.u.u_s.len = ca->u.u_s.len - cb->u.u_s.len;
          ca = &tmpa;
          cb = cb->next;
        }
@@ -1199,7 +1203,7 @@ size_t
 m4_arg_len (m4_macro_args *argv, unsigned int index)
 {
   m4_symbol_value *value;
-  m4_symbol_chain *chain;
+  m4__symbol_chain *chain;
   size_t len;
 
   if (index == 0)
@@ -1215,8 +1219,8 @@ m4_arg_len (m4_macro_args *argv, unsigned int index)
   len = 0;
   while (chain)
     {
-      assert (chain->str);
-      len += chain->len;
+      assert (chain->type == M4__CHAIN_STR);
+      len += chain->u.u_s.len;
       chain = chain->next;
     }
   assert (len);
@@ -1244,7 +1248,7 @@ m4_make_argv_ref (m4 *context, m4_macro_args *argv, const 
char *argv0,
 {
   m4_macro_args *new_argv;
   m4_symbol_value *value;
-  m4_symbol_chain *chain;
+  m4__symbol_chain *chain;
   unsigned int index = skip ? 2 : 1;
   m4_obstack *obs = m4_arg_scratch (context);
 
@@ -1255,9 +1259,9 @@ m4_make_argv_ref (m4 *context, m4_macro_args *argv, const 
char *argv0,
       /* TODO for now we support only a single-length $@ chain.  */
       assert (argv->arraylen == 1 && argv->array[0]->type == M4_SYMBOL_COMP);
       chain = argv->array[0]->u.u_c.chain;
-      assert (!chain->next && !chain->str);
-      argv = chain->argv;
-      index += chain->index - 1;
+      assert (!chain->next && chain->type == M4__CHAIN_ARGV);
+      argv = chain->u.u_a.argv;
+      index += chain->u.u_a.index - 1;
     }
   if (argv->argc <= index)
     {
@@ -1272,7 +1276,7 @@ m4_make_argv_ref (m4 *context, m4_macro_args *argv, const 
char *argv0,
                                                                  array)
                                                        + sizeof value));
       value = (m4_symbol_value *) obstack_alloc (obs, sizeof *value);
-      chain = (m4_symbol_chain *) obstack_alloc (obs, sizeof *chain);
+      chain = (m4__symbol_chain *) obstack_alloc (obs, sizeof *chain);
       new_argv->arraylen = 1;
       new_argv->array[0] = value;
       new_argv->wrapper = true;
@@ -1280,13 +1284,11 @@ m4_make_argv_ref (m4 *context, m4_macro_args *argv, 
const char *argv0,
       value->type = M4_SYMBOL_COMP;
       value->u.u_c.chain = value->u.u_c.end = chain;
       chain->next = NULL;
+      chain->type = M4__CHAIN_ARGV;
       chain->quote_age = argv->quote_age;
-      chain->str = NULL;
-      chain->len = 0;
-      chain->level = context->expansion_level - 1;
-      chain->argv = argv;
-      chain->index = index;
-      chain->flatten = flatten;
+      chain->u.u_a.argv = argv;
+      chain->u.u_a.index = index;
+      chain->u.u_a.flatten = flatten;
     }
   new_argv->argc = argv->argc - (index - 1);
   new_argv->inuse = false;
@@ -1326,11 +1328,11 @@ m4_push_arg (m4 *context, m4_obstack *obs, 
m4_macro_args *argv,
     {
       /* TODO - really handle composites; for now, just flatten the
         composite and push its text.  */
-      m4_symbol_chain *chain = value->u.u_c.chain;
+      m4__symbol_chain *chain = value->u.u_c.chain;
       while (chain)
        {
-         assert (chain->str);
-         obstack_grow (obs, chain->str, chain->len);
+         assert (chain->type == M4__CHAIN_STR);
+         obstack_grow (obs, chain->u.u_s.str, chain->u.u_s.len);
          chain = chain->next;
        }
     }
@@ -1345,14 +1347,13 @@ m4_push_args (m4 *context, m4_obstack *obs, 
m4_macro_args *argv, bool skip,
              bool quote)
 {
   m4_symbol_value *value;
-  m4_symbol_chain *chain;
+  m4__symbol_chain *chain;
   unsigned int i = skip ? 2 : 1;
   const char *sep = ",";
   size_t sep_len = 1;
   bool use_sep = false;
   bool inuse = false;
-  const char *lquote = m4_get_syntax_lquote (M4SYNTAX);
-  const char *rquote = m4_get_syntax_rquote (M4SYNTAX);
+  const m4_string_pair *quotes = m4_get_syntax_quotes (M4SYNTAX);
   m4_obstack *scratch = m4_arg_scratch (context);
 
   if (argv->argc <= i)
@@ -1361,22 +1362,22 @@ m4_push_args (m4 *context, m4_obstack *obs, 
m4_macro_args *argv, bool skip,
   if (argv->argc == i + 1)
     {
       if (quote)
-       obstack_grow (obs, lquote, strlen (lquote));
+       obstack_grow (obs, quotes->str1, quotes->len1);
       m4_push_arg (context, obs, argv, i);
       if (quote)
-       obstack_grow (obs, rquote, strlen (rquote));
+       obstack_grow (obs, quotes->str2, quotes->len2);
       return;
     }
 
   /* Compute the separator in the scratch space.  */
   if (quote)
     {
-      obstack_grow (obs, lquote, strlen (lquote));
-      obstack_grow (scratch, rquote, strlen (rquote));
+      obstack_grow (obs, quotes->str1, quotes->len1);
+      obstack_grow (scratch, quotes->str2, quotes->len2);
       obstack_1grow (scratch, ',');
-      obstack_grow0 (scratch, lquote, strlen (lquote));
+      obstack_grow0 (scratch, quotes->str1, quotes->len1);
       sep = (char *) obstack_finish (scratch);
-      sep_len += strlen (lquote) + strlen (rquote);
+      sep_len += quotes->len1 + quotes->len2;
     }
 
   /* TODO push entire $@ ref, rather than each arg.  */
@@ -1398,14 +1399,14 @@ m4_push_args (m4 *context, m4_obstack *obs, 
m4_macro_args *argv, bool skip,
          chain = value->u.u_c.chain;
          while (chain)
            {
-             assert (chain->str);
-             obstack_grow (obs, chain->str, chain->len);
+             assert (chain->type == M4__CHAIN_STR);
+             obstack_grow (obs, chain->u.u_s.str, chain->u.u_s.len);
              chain = chain->next;
            }
        }
     }
   if (quote)
-    obstack_grow (obs, rquote, strlen (rquote));
+    obstack_grow (obs, quotes->str2, quotes->len2);
   if (inuse)
     arg_mark (argv);
 }
diff --git a/m4/output.c b/m4/output.c
index dc2194f..21a28f7 100644
--- a/m4/output.c
+++ b/m4/output.c
@@ -595,27 +595,27 @@ void
 m4_shipout_string (m4 *context, m4_obstack *obs, const char *s, size_t len,
                   bool quoted)
 {
-  m4_shipout_string_trunc (context, obs, s, len, quoted, NULL);
+  m4_shipout_string_trunc (obs, s, len,
+                          quoted ? m4_get_syntax_quotes (M4SYNTAX) : NULL,
+                          NULL);
 }
 
-/* Output the text S, of length LEN, to OBS.  If QUOTED, also output
-   current quote characters around S.  If LEN is SIZE_MAX, use the
-   string length of S instead.  If MAX_LEN, reduce *MAX_LEN by LEN.
-   If LEN is larger than *MAX_LEN, then truncate output and return
-   true; otherwise return false.  CONTEXT may be NULL if QUOTED is
-   false.  */
+/* Output the text S, of length LEN, to OBS.  If QUOTES, also output
+   quote characters around S.  If LEN is SIZE_MAX, use the string
+   length of S instead.  If MAX_LEN, reduce *MAX_LEN by LEN.  If LEN
+   is larger than *MAX_LEN, then truncate output and return true;
+   otherwise return false.  */
 bool
-m4_shipout_string_trunc (m4 *context, m4_obstack *obs, const char *s,
-                        size_t len, bool quoted, size_t *max_len)
+m4_shipout_string_trunc (m4_obstack *obs, const char *s, size_t len,
+                        const m4_string_pair *quotes, size_t *max_len)
 {
   size_t max = max_len ? *max_len : SIZE_MAX;
 
   assert (obs && s);
   if (len == SIZE_MAX)
     len = strlen (s);
-  if (quoted)
-    obstack_grow (obs, context->syntax->lquote.string,
-                 context->syntax->lquote.length);
+  if (quotes)
+    obstack_grow (obs, quotes->str1, quotes->len1);
   if (len < max)
     {
       obstack_grow (obs, s, len);
@@ -627,9 +627,8 @@ m4_shipout_string_trunc (m4 *context, m4_obstack *obs, 
const char *s,
       obstack_grow (obs, "...", 3);
       max = 0;
     }
-  if (quoted)
-    obstack_grow (obs, context->syntax->rquote.string,
-                 context->syntax->rquote.length);
+  if (quotes)
+    obstack_grow (obs, quotes->str2, quotes->len2);
   if (max_len)
     *max_len = max;
   return max == 0;
diff --git a/m4/symtab.c b/m4/symtab.c
index 3ff6f0d..60afe63 100644
--- a/m4/symtab.c
+++ b/m4/symtab.c
@@ -454,23 +454,23 @@ m4_symbol_value_copy (m4_symbol_value *dest, 
m4_symbol_value *src)
       break;
     case M4_SYMBOL_COMP:
       {
-       m4_symbol_chain *chain = src->u.u_c.chain;
+       m4__symbol_chain *chain = src->u.u_c.chain;
        size_t len = 0;
        char *str;
        char *p;
        while (chain)
          {
            /* TODO for now, only text links are supported.  */
-           assert (chain->str);
-           len += chain->len;
+           assert (chain->type == M4__CHAIN_STR);
+           len += chain->u.u_s.len;
            chain = chain->next;
          }
        p = str = xcharalloc (len + 1);
        chain = src->u.u_c.chain;
        while (chain)
          {
-           memcpy (p, chain->str, chain->len);
-           p += chain->len;
+           memcpy (p, chain->u.u_s.str, chain->u.u_s.len);
+           p += chain->u.u_s.len;
            chain = chain->next;
          }
        *p = '\0';
@@ -532,13 +532,13 @@ m4_set_symbol_name_traced (m4_symbol_table *symtab, const 
char *name,
   return result;
 }
 
-/* Grow OBS with a text representation of VALUE.  If QUOTE, then
-   surround a text definition by LQUOTE and RQUOTE.  If MAXLEN is less
-   than SIZE_MAX, then truncate text definitions to that length.  If
-   MODULE, then include which module defined a builtin.  */
+/* Grow OBS with a text representation of VALUE.  If QUOTES, then use
+   it to surround a text definition.  If MAXLEN is less than SIZE_MAX,
+   then truncate text definitions to that length.  If MODULE, then
+   include which module defined a builtin.  */
 void
-m4_symbol_value_print (m4_symbol_value *value, m4_obstack *obs, bool quote,
-                      const char *lquote, const char *rquote, size_t maxlen,
+m4_symbol_value_print (m4_symbol_value *value, m4_obstack *obs,
+                      const m4_string_pair *quotes, size_t maxlen,
                       bool module)
 {
   const char *text;
@@ -559,37 +559,34 @@ m4_symbol_value_print (m4_symbol_value *value, m4_obstack 
*obs, bool quote,
     case M4_SYMBOL_FUNC:
       {
        const m4_builtin *bp = m4_get_symbol_value_builtin (value);
+       static const m4_string_pair q1 = { "<", 1, ">", 1 };
        text = bp->name;
        len = strlen (text);
-       lquote = "<";
-       rquote = ">";
-       quote = true;
+       quotes = &q1;
       }
       break;
     case M4_SYMBOL_PLACEHOLDER:
       text = m4_get_symbol_value_placeholder (value);
-      /* FIXME - is it worth translating "placeholder for "?  */
+      static const m4_string_pair q2 = { "<<", 2, ">>", 2 };
       len = strlen (text);
-      lquote = "<placeholder for ";
-      rquote = ">";
-      quote = true;
+      quotes = &q2;
       break;
     case M4_SYMBOL_COMP:
       {
-       m4_symbol_chain *chain = value->u.u_c.chain;
-       if (quote)
-         obstack_grow (obs, lquote, strlen (lquote));
+       m4__symbol_chain *chain = value->u.u_c.chain;
+       if (quotes)
+         obstack_grow (obs, quotes->str1, quotes->len1);
        while (chain)
          {
            /* TODO for now, assume all links are text.  */
-           assert (chain->str);
-           if (m4_shipout_string_trunc (NULL, obs, chain->str, chain->len,
-                                        false, &maxlen))
+           assert (chain->type == M4__CHAIN_STR);
+           if (m4_shipout_string_trunc (obs, chain->u.u_s.str,
+                                        chain->u.u_s.len, NULL, &maxlen))
              break;
            chain = chain->next;
          }
-       if (quote)
-         obstack_grow (obs, rquote, strlen (rquote));
+       if (quotes)
+         obstack_grow (obs, quotes->str2, quotes->len2);
        assert (!module);
        return;
       }
@@ -598,13 +595,13 @@ m4_symbol_value_print (m4_symbol_value *value, m4_obstack 
*obs, bool quote,
       abort ();
     }
 
-  if (quote)
-    obstack_grow (obs, lquote, strlen (lquote));
+  if (quotes)
+    obstack_grow (obs, quotes->str1, quotes->len1);
   obstack_grow (obs, text, len);
   if (truncated)
     obstack_grow (obs, "...", 3);
-  if (quote)
-    obstack_grow (obs, rquote, strlen (rquote));
+  if (quotes)
+    obstack_grow (obs, quotes->str2, quotes->len2);
   if (module && VALUE_MODULE (value))
     {
       obstack_1grow (obs, '{');
@@ -614,16 +611,15 @@ m4_symbol_value_print (m4_symbol_value *value, m4_obstack 
*obs, bool quote,
     }
 }
 
-/* Grow OBS with a text representation of SYMBOL.  If QUOTE, then
-   surround each text definition by LQUOTE and RQUOTE.  If STACK, then
-   append all pushdef'd values, rather than just the top.  If
-   ARG_LENGTH is less than SIZE_MAX, then truncate text definitions to
-   that length.  If MODULE, then include which module defined a
-   builtin.  */
+/* Grow OBS with a text representation of SYMBOL.  If QUOTES, then use
+   it to surround each text definition.  If STACK, then append all
+   pushdef'd values, rather than just the top.  If ARG_LENGTH is less
+   than SIZE_MAX, then truncate text definitions to that length.  If
+   MODULE, then include which module defined a builtin.  */
 void
-m4_symbol_print (m4_symbol *symbol, m4_obstack *obs, bool quote,
-                const char *lquote, const char *rquote, bool stack,
-                size_t arg_length, bool module)
+m4_symbol_print (m4_symbol *symbol, m4_obstack *obs,
+                const m4_string_pair *quotes, bool stack, size_t arg_length,
+                bool module)
 {
   m4_symbol_value *value;
 
@@ -631,8 +627,7 @@ m4_symbol_print (m4_symbol *symbol, m4_obstack *obs, bool 
quote,
   assert (obs);
 
   value = m4_get_symbol_value (symbol);
-  m4_symbol_value_print (value, obs, quote, lquote, rquote, arg_length,
-                        module);
+  m4_symbol_value_print (value, obs, quotes, arg_length, module);
   if (stack)
     {
       value = VALUE_NEXT (value);
@@ -640,8 +635,7 @@ m4_symbol_print (m4_symbol *symbol, m4_obstack *obs, bool 
quote,
        {
          obstack_1grow (obs, ',');
          obstack_1grow (obs, ' ');
-         m4_symbol_value_print (value, obs, quote, lquote, rquote,
-                                arg_length, module);
+         m4_symbol_value_print (value, obs, quotes, arg_length, module);
          value = VALUE_NEXT (value);
        }
     }
diff --git a/m4/syntax.c b/m4/syntax.c
index 0bce3c0..c39a9be 100644
--- a/m4/syntax.c
+++ b/m4/syntax.c
@@ -1,6 +1,6 @@
 /* GNU m4 -- A simple macro processor
-   Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2002, 2004, 2006, 2007
-   Free Software Foundation, Inc.
+   Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2002, 2004, 2006,
+   2007, 2008 Free Software Foundation, Inc.
 
    This file is part of GNU M4.
 
@@ -168,10 +168,10 @@ m4_syntax_delete (m4_syntax_table *syntax)
 {
   assert (syntax);
 
-  free (syntax->lquote.string);
-  free (syntax->rquote.string);
-  free (syntax->bcomm.string);
-  free (syntax->ecomm.string);
+  free (syntax->quote.str1);
+  free (syntax->quote.str2);
+  free (syntax->comm.str1);
+  free (syntax->comm.str2);
   free (syntax);
 }
 
@@ -371,23 +371,23 @@ m4_set_syntax (m4_syntax_table *syntax, char key, char 
action,
         properties.  */
       memcpy (syntax->table, syntax->orig, sizeof syntax->orig);
 
-      free (syntax->lquote.string);
-      free (syntax->rquote.string);
-      free (syntax->bcomm.string);
-      free (syntax->ecomm.string);
-
-      syntax->lquote.string    = xstrdup (DEF_LQUOTE);
-      syntax->lquote.length    = strlen (syntax->lquote.string);
-      syntax->rquote.string    = xstrdup (DEF_RQUOTE);
-      syntax->rquote.length    = strlen (syntax->rquote.string);
-      syntax->bcomm.string     = xstrdup (DEF_BCOMM);
-      syntax->bcomm.length     = strlen (syntax->bcomm.string);
-      syntax->ecomm.string     = xstrdup (DEF_ECOMM);
-      syntax->ecomm.length     = strlen (syntax->ecomm.string);
-
-      add_syntax_attribute (syntax, to_uchar (syntax->rquote.string[0]),
+      free (syntax->quote.str1);
+      free (syntax->quote.str2);
+      free (syntax->comm.str1);
+      free (syntax->comm.str2);
+
+      syntax->quote.str1       = xstrdup (DEF_LQUOTE);
+      syntax->quote.len1       = 1;
+      syntax->quote.str2       = xstrdup (DEF_RQUOTE);
+      syntax->quote.len2       = 1;
+      syntax->comm.str1                = xstrdup (DEF_BCOMM);
+      syntax->comm.len1                = 1;
+      syntax->comm.str2                = xstrdup (DEF_ECOMM);
+      syntax->comm.len2                = 1;
+
+      add_syntax_attribute (syntax, to_uchar (syntax->quote.str2[0]),
                            M4_SYNTAX_RQUOTE);
-      add_syntax_attribute (syntax, to_uchar (syntax->ecomm.string[0]),
+      add_syntax_attribute (syntax, to_uchar (syntax->comm.str2[0]),
                            M4_SYNTAX_ECOMM);
 
       syntax->is_single_quotes         = true;
@@ -432,10 +432,10 @@ check_is_single_quotes (m4_syntax_table *syntax)
 
   if (! syntax->is_single_quotes)
     return false;
-  assert (syntax->lquote.length == 1 && syntax->rquote.length == 1);
+  assert (syntax->quote.len1 == 1 && syntax->quote.len2 == 1);
 
-  if (m4_has_syntax (syntax, *syntax->lquote.string, M4_SYNTAX_LQUOTE)
-      && m4_has_syntax (syntax, *syntax->rquote.string, M4_SYNTAX_RQUOTE))
+  if (m4_has_syntax (syntax, *syntax->quote.str1, M4_SYNTAX_LQUOTE)
+      && m4_has_syntax (syntax, *syntax->quote.str2, M4_SYNTAX_RQUOTE))
     return true;
 
   /* The most recent action invalidated our current lquote/rquote.  If
@@ -470,8 +470,8 @@ check_is_single_quotes (m4_syntax_table *syntax)
     syntax->is_single_quotes = false;
   else if (syntax->is_single_quotes)
     {
-      *syntax->lquote.string = lquote;
-      *syntax->rquote.string = rquote;
+      *syntax->quote.str1 = lquote;
+      *syntax->quote.str2 = rquote;
     }
   return syntax->is_single_quotes;
 }
@@ -485,10 +485,10 @@ check_is_single_comments (m4_syntax_table *syntax)
 
   if (! syntax->is_single_comments)
     return false;
-  assert (syntax->bcomm.length == 1 && syntax->ecomm.length == 1);
+  assert (syntax->comm.len1 == 1 && syntax->comm.len2 == 1);
 
-  if (m4_has_syntax (syntax, *syntax->bcomm.string, M4_SYNTAX_BCOMM)
-      && m4_has_syntax (syntax, *syntax->ecomm.string, M4_SYNTAX_ECOMM))
+  if (m4_has_syntax (syntax, *syntax->comm.str1, M4_SYNTAX_BCOMM)
+      && m4_has_syntax (syntax, *syntax->comm.str2, M4_SYNTAX_ECOMM))
     return true;
 
   /* The most recent action invalidated our current bcomm/ecomm.  If
@@ -523,8 +523,8 @@ check_is_single_comments (m4_syntax_table *syntax)
     syntax->is_single_comments = false;
   else if (syntax->is_single_comments)
     {
-      *syntax->bcomm.string = bcomm;
-      *syntax->ecomm.string = ecomm;
+      *syntax->comm.str1 = bcomm;
+      *syntax->comm.str2 = ecomm;
     }
   return syntax->is_single_comments;
 }
@@ -572,24 +572,24 @@ m4_set_quotes (m4_syntax_table *syntax, const char *lq, 
const char *rq)
   else if (!rq || (*lq && !*rq))
     rq = DEF_RQUOTE;
 
-  if (strcmp (syntax->lquote.string, lq) == 0
-      && strcmp (syntax->rquote.string, rq) == 0)
+  if (strcmp (syntax->quote.str1, lq) == 0
+      && strcmp (syntax->quote.str2, rq) == 0)
     return;
 
-  free (syntax->lquote.string);
-  free (syntax->rquote.string);
-  syntax->lquote.string = xstrdup (lq);
-  syntax->lquote.length = strlen (syntax->lquote.string);
-  syntax->rquote.string = xstrdup (rq);
-  syntax->rquote.length = strlen (syntax->rquote.string);
+  free (syntax->quote.str1);
+  free (syntax->quote.str2);
+  syntax->quote.str1 = xstrdup (lq);
+  syntax->quote.len1 = strlen (lq);
+  syntax->quote.str2 = xstrdup (rq);
+  syntax->quote.len2 = strlen (rq);
 
   /* changequote overrides syntax_table, but be careful when it is
      used to select a start-quote sequence that is effectively
      disabled.  */
 
   syntax->is_single_quotes
-    = (syntax->lquote.length == 1 && syntax->rquote.length == 1
-       && !m4_has_syntax (syntax, *syntax->lquote.string,
+    = (syntax->quote.len1 == 1 && syntax->quote.len2 == 1
+       && !m4_has_syntax (syntax, *syntax->quote.str1,
                          (M4_SYNTAX_IGNORE | M4_SYNTAX_ESCAPE
                           | M4_SYNTAX_ALPHA | M4_SYNTAX_NUM)));
 
@@ -605,9 +605,9 @@ m4_set_quotes (m4_syntax_table *syntax, const char *lq, 
const char *rq)
 
   if (syntax->is_single_quotes)
     {
-      add_syntax_attribute (syntax, to_uchar (syntax->lquote.string[0]),
+      add_syntax_attribute (syntax, to_uchar (syntax->quote.str1[0]),
                            M4_SYNTAX_LQUOTE);
-      add_syntax_attribute (syntax, to_uchar (syntax->rquote.string[0]),
+      add_syntax_attribute (syntax, to_uchar (syntax->quote.str2[0]),
                            M4_SYNTAX_RQUOTE);
     }
   if (syntax->is_macro_escaped)
@@ -634,24 +634,24 @@ m4_set_comment (m4_syntax_table *syntax, const char *bc, 
const char *ec)
   else if (!ec || (*bc && !*ec))
     ec = DEF_ECOMM;
 
-  if (strcmp (syntax->bcomm.string, bc) == 0
-      && strcmp (syntax->ecomm.string, ec) == 0)
+  if (strcmp (syntax->comm.str1, bc) == 0
+      && strcmp (syntax->comm.str2, ec) == 0)
     return;
 
-  free (syntax->bcomm.string);
-  free (syntax->ecomm.string);
-  syntax->bcomm.string = xstrdup (bc);
-  syntax->bcomm.length = strlen (syntax->bcomm.string);
-  syntax->ecomm.string = xstrdup (ec);
-  syntax->ecomm.length = strlen (syntax->ecomm.string);
+  free (syntax->comm.str1);
+  free (syntax->comm.str2);
+  syntax->comm.str1 = xstrdup (bc);
+  syntax->comm.len1 = strlen (bc);
+  syntax->comm.str2 = xstrdup (ec);
+  syntax->comm.len2 = strlen (ec);
 
   /* changecom overrides syntax_table, but be careful when it is used
      to select a start-comment sequence that is effectively
      disabled.  */
 
   syntax->is_single_comments
-    = (syntax->bcomm.length == 1 && syntax->ecomm.length == 1
-       && !m4_has_syntax (syntax, *syntax->bcomm.string,
+    = (syntax->comm.len1 == 1 && syntax->comm.len2 == 1
+       && !m4_has_syntax (syntax, *syntax->comm.str1,
                          (M4_SYNTAX_IGNORE | M4_SYNTAX_ESCAPE
                           | M4_SYNTAX_ALPHA | M4_SYNTAX_NUM
                           | M4_SYNTAX_LQUOTE)));
@@ -667,9 +667,9 @@ m4_set_comment (m4_syntax_table *syntax, const char *bc, 
const char *ec)
     }
   if (syntax->is_single_comments)
     {
-      add_syntax_attribute (syntax, to_uchar (syntax->bcomm.string[0]),
+      add_syntax_attribute (syntax, to_uchar (syntax->comm.str1[0]),
                            M4_SYNTAX_BCOMM);
-      add_syntax_attribute (syntax, to_uchar (syntax->ecomm.string[0]),
+      add_syntax_attribute (syntax, to_uchar (syntax->comm.str2[0]),
                            M4_SYNTAX_ECOMM);
     }
   if (syntax->is_macro_escaped)
@@ -728,22 +728,22 @@ set_quote_age (m4_syntax_table *syntax, bool reset, bool 
change)
   else
     local_syntax_age = syntax->syntax_age;
   if (local_syntax_age < 0xffff && syntax->is_single_quotes
-      && !m4_has_syntax (syntax, *syntax->lquote.string,
+      && !m4_has_syntax (syntax, *syntax->quote.str1,
                         (M4_SYNTAX_ALPHA | M4_SYNTAX_NUM | M4_SYNTAX_OPEN
                          | M4_SYNTAX_COMMA | M4_SYNTAX_CLOSE
                          | M4_SYNTAX_SPACE))
-      && !m4_has_syntax (syntax, *syntax->rquote.string,
+      && !m4_has_syntax (syntax, *syntax->quote.str2,
                         (M4_SYNTAX_ALPHA | M4_SYNTAX_NUM | M4_SYNTAX_OPEN
                          | M4_SYNTAX_COMMA | M4_SYNTAX_CLOSE
                          | M4_SYNTAX_SPACE))
-      && *syntax->lquote.string != *syntax->rquote.string
-      && *syntax->bcomm.string != *syntax->lquote.string
-      && !m4_has_syntax (syntax, *syntax->bcomm.string,
+      && *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->quote_age = ((local_syntax_age << 16)
-                          | ((*syntax->lquote.string & 0xff) << 8)
-                          | (*syntax->rquote.string & 0xff));
+                          | ((*syntax->quote.str1 & 0xff) << 8)
+                          | (*syntax->quote.str2 & 0xff));
     }
   else
     syntax->quote_age = 0;
@@ -757,7 +757,7 @@ const char *
 m4_get_syntax_lquote (m4_syntax_table *syntax)
 {
   assert (syntax);
-  return syntax->lquote.string;
+  return syntax->quote.str1;
 }
 
 #undef m4_get_syntax_rquote
@@ -765,7 +765,15 @@ const char *
 m4_get_syntax_rquote (m4_syntax_table *syntax)
 {
   assert (syntax);
-  return syntax->rquote.string;
+  return syntax->quote.str2;
+}
+
+#undef m4_get_syntax_quotes
+const m4_string_pair *
+m4_get_syntax_quotes (m4_syntax_table *syntax)
+{
+  assert (syntax);
+  return &syntax->quote;
 }
 
 #undef m4_is_syntax_single_quotes
@@ -781,7 +789,7 @@ const char *
 m4_get_syntax_bcomm (m4_syntax_table *syntax)
 {
   assert (syntax);
-  return syntax->bcomm.string;
+  return syntax->comm.str1;
 }
 
 #undef m4_get_syntax_ecomm
@@ -789,7 +797,15 @@ const char *
 m4_get_syntax_ecomm (m4_syntax_table *syntax)
 {
   assert (syntax);
-  return syntax->ecomm.string;
+  return syntax->comm.str2;
+}
+
+#undef m4_get_syntax_comments
+const m4_string_pair *
+m4_get_syntax_comments (m4_syntax_table *syntax)
+{
+  assert (syntax);
+  return &syntax->comm;
 }
 
 #undef m4_is_syntax_single_comments
diff --git a/m4/utility.c b/m4/utility.c
index b367717..d95e44e 100644
--- a/m4/utility.c
+++ b/m4/utility.c
@@ -1,6 +1,6 @@
 /* GNU m4 -- A simple macro processor
    Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 1998, 1999, 2003,
-   2006, 2007 Free Software Foundation, Inc.
+   2006, 2007, 2008 Free Software Foundation, Inc.
 
    This file is part of GNU M4.
 
@@ -114,8 +114,7 @@ m4_dump_args (m4 *context, m4_obstack *obs, unsigned int 
start,
       else
        need_sep = true;
 
-      m4_shipout_string (context, obs, M4ARG (i), m4_arg_len (argv, i),
-                         quoted);
+      m4_shipout_string (context, obs, M4ARG (i), M4ARGLEN (i), quoted);
     }
 }
 
diff --git a/modules/gnu.c b/modules/gnu.c
index 91cfb54..841e660 100644
--- a/modules/gnu.c
+++ b/modules/gnu.c
@@ -1,5 +1,6 @@
 /* GNU m4 -- A simple macro processor
-   Copyright (C) 2000, 2004, 2005, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 2000, 2004, 2005, 2006, 2007, 2008 Free Software
+   Foundation, Inc.
 
    This file is part of GNU M4.
 
@@ -446,8 +447,7 @@ M4BUILTIN_HANDLER (builtin)
            {
              m4_macro_args *new_argv;
              bool flatten = (bp->flags & M4_BUILTIN_GROKS_MACRO) == 0;
-             new_argv = m4_make_argv_ref (context, argv, name,
-                                          m4_arg_len (argv, 1),
+             new_argv = m4_make_argv_ref (context, argv, name, M4ARGLEN (1),
                                           true, flatten);
              bp->func (context, obs, argc - 1, new_argv);
            }
@@ -682,8 +682,8 @@ M4BUILTIN_HANDLER (indir)
        {
          m4_macro_args *new_argv;
          bool flatten = !m4_symbol_groks_macro (symbol);
-         new_argv = m4_make_argv_ref (context, argv, name,
-                                      m4_arg_len (argv, 1), true, flatten);
+         new_argv = m4_make_argv_ref (context, argv, name, M4ARGLEN (1),
+                                      true, flatten);
          m4_macro_call (context, m4_get_symbol_value (symbol), obs,
                         argc - 1, new_argv);
        }
@@ -701,8 +701,7 @@ M4BUILTIN_HANDLER (mkdtemp)
   M4_MODULE_IMPORT (m4, m4_make_temp);
 
   if (m4_make_temp)
-    m4_make_temp (context, obs, M4ARG (0), M4ARG (1), m4_arg_len (argv, 1),
-                 true);
+    m4_make_temp (context, obs, M4ARG (0), M4ARG (1), M4ARGLEN (1), true);
   else
     assert (!"Unable to import from m4 module");
 }
@@ -746,11 +745,11 @@ M4BUILTIN_HANDLER (patsubst)
       return;
     }
 
-  buf = regexp_compile (context, me, pattern, m4_arg_len (argv, 2), resyntax);
+  buf = regexp_compile (context, me, pattern, M4ARGLEN (2), resyntax);
   if (!buf)
     return;
 
-  regexp_substitute (context, obs, me, M4ARG (1), m4_arg_len (argv, 1),
+  regexp_substitute (context, obs, me, M4ARG (1), M4ARGLEN (1),
                     pattern, buf, replace, false);
 }
 
@@ -817,12 +816,12 @@ M4BUILTIN_HANDLER (regexp)
       return;
     }
 
-  buf = regexp_compile (context, me, pattern, m4_arg_len (argv, 2), resyntax);
+  buf = regexp_compile (context, me, pattern, M4ARGLEN (2), resyntax);
   if (!buf)
     return;
 
   victim = M4ARG (1);
-  len = m4_arg_len (argv, 1);
+  len = M4ARGLEN (1);
   startpos = regexp_search (buf, victim, len, 0, len, replace == NULL);
 
   if (startpos == -2)
@@ -873,8 +872,7 @@ M4BUILTIN_HANDLER (renamesyms)
            return;
        }
 
-      buf = regexp_compile (context, me, regexp, m4_arg_len (argv, 1),
-                           resyntax);
+      buf = regexp_compile (context, me, regexp, M4ARGLEN (1), resyntax);
       if (!buf)
        return;
 
diff --git a/modules/m4.c b/modules/m4.c
index 4b1416e..cd4c230 100644
--- a/modules/m4.c
+++ b/modules/m4.c
@@ -341,13 +341,13 @@ m4_dump_symbols (m4 *context, m4_dump_symbol_data *data, 
unsigned int argc,
 M4BUILTIN_HANDLER (dumpdef)
 {
   m4_dump_symbol_data data;
-  bool quote = m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE);
-  const char *lquote = m4_get_syntax_lquote (M4SYNTAX);
-  const char *rquote = m4_get_syntax_rquote (M4SYNTAX);
+  const m4_string_pair *quotes = NULL;
   bool stack = m4_is_debug_bit (context, M4_DEBUG_TRACE_STACK);
   size_t arg_length = m4_get_max_debug_arg_length_opt (context);
   bool module = m4_is_debug_bit (context, M4_DEBUG_TRACE_MODULE);
 
+  if (m4_is_debug_bit (context, M4_DEBUG_TRACE_QUOTE))
+    quotes = m4_get_syntax_quotes (M4SYNTAX);
   data.obs = m4_arg_scratch (context);
   m4_dump_symbols (context, &data, argc, argv, true);
 
@@ -359,8 +359,7 @@ M4BUILTIN_HANDLER (dumpdef)
       obstack_grow (obs, data.base[0], strlen (data.base[0]));
       obstack_1grow (obs, ':');
       obstack_1grow (obs, '\t');
-      m4_symbol_print (symbol, obs, quote, lquote, rquote, stack, arg_length,
-                      module);
+      m4_symbol_print (symbol, obs, quotes, stack, arg_length, module);
       obstack_1grow (obs, '\n');
     }
 
@@ -561,7 +560,7 @@ M4BUILTIN_HANDLER (divert)
   if (argc >= 2 && !m4_numeric_arg (context, M4ARG (0), M4ARG (1), &i))
     return;
   m4_make_diversion (context, i);
-  m4_divert_text (context, NULL, M4ARG (2), m4_arg_len (argv, 2),
+  m4_divert_text (context, NULL, M4ARG (2), M4ARGLEN (2),
                  m4_get_current_line (context));
 }
 
@@ -698,8 +697,7 @@ m4_make_temp (m4 *context, m4_obstack *obs, const char 
*macro,
   int fd;
   int i;
   char *name;
-  const char *tmp;
-  size_t qlen;
+  const m4_string_pair *quotes = m4_get_syntax_quotes (M4SYNTAX);
 
   if (m4_get_safer_opt (context))
     {
@@ -711,15 +709,13 @@ m4_make_temp (m4 *context, m4_obstack *obs, const char 
*macro,
      user forgot to supply them.  Output must be quoted if
      successful.  */
   assert (obstack_object_size (obs) == 0);
-  tmp = m4_get_syntax_lquote (M4SYNTAX);
-  qlen = strlen (tmp);
-  obstack_grow (obs, tmp, qlen);
+  obstack_grow (obs, quotes->str1, quotes->len1);
   obstack_grow (obs, pattern, len);
   for (i = 0; len > 0 && i < 6; i++)
     if (pattern[--len] != 'X')
       break;
   obstack_grow0 (obs, "XXXXXX", 6 - i);
-  name = (char *) obstack_base (obs) + qlen;
+  name = (char *) obstack_base (obs) + quotes->len1;
 
   /* Make the temporary object.  */
   errno = 0;
@@ -741,8 +737,7 @@ m4_make_temp (m4 *context, m4_obstack *obs, const char 
*macro,
        close (fd);
       /* Remove NUL, then finish quote.  */
       obstack_blank (obs, -1);
-      tmp = m4_get_syntax_rquote (M4SYNTAX);
-      obstack_grow (obs, tmp, strlen (tmp));
+      obstack_grow (obs, quotes->str2, quotes->len2);
     }
 }
 
@@ -763,9 +758,9 @@ M4BUILTIN_HANDLER (maketemp)
           maketemp(XXXXXXXX) -> `X00nnnnn', where nnnnn is 16-bit pid
       */
       const char *str = M4ARG (1);
-      size_t len = m4_arg_len (argv, 1);
-      int i;
-      int len2;
+      size_t len = M4ARGLEN (1);
+      size_t i;
+      size_t len2;
 
       for (i = len; i > 1; i--)
        if (str[i - 1] != 'X')
@@ -783,15 +778,13 @@ M4BUILTIN_HANDLER (maketemp)
        }
     }
   else
-    m4_make_temp (context, obs, M4ARG (0), M4ARG (1), m4_arg_len (argv, 1),
-                 false);
+    m4_make_temp (context, obs, M4ARG (0), M4ARG (1), M4ARGLEN (1), false);
 }
 
 /* Use the first argument as a template for a temporary file name.  */
 M4BUILTIN_HANDLER (mkstemp)
 {
-  m4_make_temp (context, obs, M4ARG (0), M4ARG (1), m4_arg_len (argv, 1),
-               false);
+  m4_make_temp (context, obs, M4ARG (0), M4ARG (1), M4ARGLEN (1), false);
 }
 
 /* Print all arguments on standard error.  */
@@ -855,7 +848,7 @@ M4BUILTIN_HANDLER (m4wrap)
 {
   assert (obstack_object_size (obs) == 0);
   if (m4_get_posixly_correct_opt (context))
-    m4_shipout_string (context, obs, M4ARG (1), m4_arg_len (argv, 1), false);
+    m4_shipout_string (context, obs, M4ARG (1), M4ARGLEN (1), false);
   else
     m4_dump_args (context, obs, 1, argv, " ", false);
   obstack_1grow (obs, '\0');
@@ -899,7 +892,7 @@ M4BUILTIN_HANDLER (traceoff)
 /* Expand to the length of the first argument.  */
 M4BUILTIN_HANDLER (len)
 {
-  m4_shipout_int (obs, m4_arg_len (argv, 1));
+  m4_shipout_int (obs, M4ARGLEN (1));
 }
 
 /* The macro expands to the first index of the second argument in the first
@@ -913,8 +906,7 @@ M4BUILTIN_HANDLER (index)
 
   /* Rely on the optimizations guaranteed by gnulib's memmem
      module.  */
-  result = (char *) memmem (haystack, m4_arg_len (argv, 1),
-                           needle, m4_arg_len (argv, 2));
+  result = (char *) memmem (haystack, M4ARGLEN (1), needle, M4ARGLEN (2));
   if (result)
     retval = result - haystack;
 
@@ -939,7 +931,7 @@ M4BUILTIN_HANDLER (substr)
       return;
     }
 
-  length = avail = m4_arg_len (argv, 1);
+  length = avail = M4ARGLEN (1);
   if (!m4_numeric_arg (context, me, M4ARG (2), &start))
     return;
 
diff --git a/modules/stdlib.c b/modules/stdlib.c
index 0063ed8..0849d3d 100644
--- a/modules/stdlib.c
+++ b/modules/stdlib.c
@@ -1,5 +1,6 @@
 /* GNU m4 -- A simple macro processor
-   Copyright (C) 1999, 2000, 2001, 2006, 2007 Free Software Foundation, Inc.
+   Copyright (C) 1999, 2000, 2001, 2006, 2007, 2008 Free Software
+   Foundation, Inc.
 
    This file is part of GNU M4.
 
@@ -122,12 +123,12 @@ M4BUILTIN_HANDLER (setenv)
     return;
 
   assert (obstack_object_size (obs) == 0);
-  obstack_grow (obs, M4ARG (1), m4_arg_len (argv, 1));
+  obstack_grow (obs, M4ARG (1), M4ARGLEN (1));
   obstack_1grow (obs, '=');
-  obstack_grow0 (obs, M4ARG (2), m4_arg_len (argv, 2));
+  obstack_grow0 (obs, M4ARG (2), M4ARGLEN (2));
 
   {
-    char *env = obstack_finish (obs);
+    char *env = (char *) obstack_finish (obs);
     putenv (env);
   }
 #endif /* HAVE_PUTENV */
diff --git a/src/freeze.c b/src/freeze.c
index cdadf60..941b761 100644
--- a/src/freeze.c
+++ b/src/freeze.c
@@ -1,6 +1,6 @@
 /* GNU m4 -- A simple macro processor
-   Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2004, 2005, 2006, 2007
-   Free Software Foundation, Inc.
+   Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2004, 2005, 2006,
+   2007, 2008 Free Software Foundation, Inc.
 
    This file is part of GNU M4.
 
@@ -213,6 +213,7 @@ produce_frozen_state (m4 *context, const char *name)
 {
   FILE *file = fopen (name, O_BINARY ? "wb" : "w");
   const char *str;
+  const m4_string_pair *pair;
 
   if (!file)
     {
@@ -227,28 +228,22 @@ produce_frozen_state (m4 *context, const char *name)
   fputs ("V2\n", file);
 
   /* Dump quote delimiters.  */
-
-  if (strcmp (m4_get_syntax_lquote (M4SYNTAX), DEF_LQUOTE)
-      || strcmp (m4_get_syntax_rquote (M4SYNTAX), DEF_RQUOTE))
+  pair = m4_get_syntax_quotes (M4SYNTAX);
+  if (strcmp (pair->str1, DEF_LQUOTE) || strcmp (pair->str2, DEF_RQUOTE))
     {
-      xfprintf (file, "Q%zu,%zu\n", M4SYNTAX->lquote.length,
-              M4SYNTAX->rquote.length);
-      produce_mem_dump (file, M4SYNTAX->lquote.string,
-                       M4SYNTAX->lquote.length);
-      produce_mem_dump (file, M4SYNTAX->rquote.string,
-                       M4SYNTAX->rquote.length);
+      xfprintf (file, "Q%zu,%zu\n", pair->len1, pair->len2);
+      produce_mem_dump (file, pair->str1, pair->len1);
+      produce_mem_dump (file, pair->str2, pair->len2);
       fputc ('\n', file);
     }
 
   /* Dump comment delimiters.  */
-
-  if (strcmp (m4_get_syntax_bcomm (M4SYNTAX), DEF_BCOMM)
-      || strcmp (m4_get_syntax_ecomm (M4SYNTAX), DEF_ECOMM))
+  pair = m4_get_syntax_comments (M4SYNTAX);
+  if (strcmp (pair->str1, DEF_BCOMM) || strcmp (pair->str2, DEF_ECOMM))
     {
-      xfprintf (file, "C%zu,%zu\n", M4SYNTAX->bcomm.length,
-               M4SYNTAX->ecomm.length);
-      produce_mem_dump (file, M4SYNTAX->bcomm.string, M4SYNTAX->bcomm.length);
-      produce_mem_dump (file, M4SYNTAX->ecomm.string, M4SYNTAX->ecomm.length);
+      xfprintf (file, "C%zu,%zu\n", pair->len1, pair->len2);
+      produce_mem_dump (file, pair->str1, pair->len1);
+      produce_mem_dump (file, pair->str2, pair->len2);
       fputc ('\n', file);
     }
 
diff --git a/tests/freeze.at b/tests/freeze.at
index 530553a..2a84843 100644
--- a/tests/freeze.at
+++ b/tests/freeze.at
@@ -1,5 +1,5 @@
 # Hand crafted tests for GNU M4.                               -*- Autotest -*-
-# Copyright (C) 2006, 2007 Free Software Foundation, Inc.
+# Copyright (C) 2006, 2007, 2008 Free Software Foundation, Inc.
 
 # This file is part of GNU M4.
 #
@@ -360,7 +360,7 @@ a
 [[m4:input.m4:4: Warning: a: builtin `b' requested by frozen file not found
 m4:input.m4:6: Warning: a: builtin `b' requested by frozen file not found
 m4:input.m4:8: Warning: a: builtin `b' requested by frozen file not found
-a:     <placeholder for b>
+a:     <<b>>
 c:     `'
 ]])
 


hooks/post-receive
--
GNU M4 source repository




reply via email to

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