Re: M4 syntax $11 vs. ${11}

Eric Blake <[email protected]>
Newsgroups gmane.comp.gnu.m4.general,gmane.comp.gnu.m4.patches
Message-ID <[email protected]>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

According to Eric Blake on 1/18/2007 7:50 AM:
> 
> With 1.9b, I would like to implement the resolution of XCU ERN 111.  That
> is, I plan on adding support for ${11}, so that the GNU extension of more
> than 9 parameters is still alive (and in fact, I hope to borrow from shell
> syntax for other extensions such as ${1-default}).  I also plan on making
> $11 obey POSIX semantics if POSIXLY_CORRECT, else obey 1.4.x semantics but
> issue a warning that obsolete syntax was encountered.  Then, after a
> deprecation period, M4 2.1 could remove the POSIXLY_CORRECT check and
> always treat $11 the way POSIX requires.
> 

As a first step, we need syntax categories for { and }, similar to $.
I'm not sure whether $, {, and } should be category masks (for example,
allowing $ to be in both the 'A' and '$' categories at once, to both
participate in macro names during parsing as well trigger parameter
substitution during expansion), but for now I kept the status quo and
the new categories are mutually exclusive with other categories.

Followup patches that still need to be written include: allowing
- --changesyntax from the 1.9a command line, adding --warn-syntax to 1.4.9
and 1.9a, actually coding up ${11} parsing, proposing a patch to
autoconf to call changesyntax(O+{}) alongside changequote([,]).

2007-01-23  Eric Blake  <[email protected]>

	* m4/m4module.h (M4_SYNTAX_ASSIGN): Delete this unused
	extension to make enough room.
	(M4_SYNTAX_IGNORE): Change value to zero, since the (commented)
	code in input.c special cases this category.
	(M4_SYNTAX_LBRACE, M4_SYNTAX_RBRACE): New values in preparation
	for define(eleventh,${11}) extension.
	* m4/syntax.c: Update comments accordingly.
	(m4_syntax_create, m4_syntax_code): Handle { and }.
	* m4/input.c (m4__next_token): Likewise.
	* src/freeze.c (produce_frozen_state): Support new categories.
	(reload_frozen_state): When loading version 1, disable syntax
	features not present in 1.4.x.
	* tests/freeze.at: Sort and rename existing tests.
	(loading format 1): Ensure we don't break v1 frozen files that
	used raw ${.
	(loading format 2, reloading changecom, reloading changesyntax):
	New tests.
	* doc/m4.texinfo (Changesyntax, Frozen file format 1): Document
	the new syntax categories.
	(Arguments): Update the FIXME comment.
	(M4wrap): Merge examples from branch, before worrying about fixing
	m4wrap to obey POSIX.
	(Using frozen files): Start merging from branch.
	* NEWS: Update.

- --
Don't work too hard, make some time for fun as well!

Eric Blake             [email protected]
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (Cygwin)
Comment: Public key at home.comcast.net/~ericblake/eblake.gpg
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org

iD8DBQFFtht884KuGfSFAYARAmy7AKDJ4ET0q8mJ8GHH9BJI1+5I0oimNACgtRZF
cC750gJ/9NwMzdZYsIE/+0w=
=jNzN
-----END PGP SIGNATURE-----

_______________________________________________
M4-discuss mailing list
[email protected]
http://lists.gnu.org/mailman/listinfo/m4-discuss
m4.patch229 (text/plain, 25.1 KB)
Index: NEWS
===================================================================
RCS file: /sources/m4/m4/NEWS,v
retrieving revision 1.37
diff -u -p -r1.37 NEWS
--- NEWS	21 Jan 2007 04:09:06 -0000	1.37
+++ NEWS	23 Jan 2007 14:26:22 -0000
@@ -155,7 +155,9 @@ promoted to 2.0.
 
 *** The `changesyntax' builtin has been improved, to make it easier to add
     and remove characters from a syntax class without having to specify the
-    entire set of characters in that class.
+    entire set of characters in that class.  It also supports two new
+    syntax categories, `{' and `}', for extended argument handling in macro
+    definitions.
 
 *** New `m' flag to `-d'/`--debug' command-line option or `debugmode'
     builtin traces actions related to module loading and unloading, and
@@ -192,7 +194,7 @@ promoted to 2.0.
 ** Other changes
 
 *** The syntax of frozen files format V2 has been improved to save
-    additional state.  This includes the 'R' directive for default regular
+    additional state.  This includes the `R' directive for default regular
     expression syntax.  Also, a V2 file can now be represented completely
     in ASCII, thanks to escape sequences.  Unfortunately, files frozen by
     M4 1.4q that contain \ in macros cannot be read by 1.9b, but since 1.4q
Index: doc/m4.texinfo
===================================================================
RCS file: /sources/m4/m4/doc/m4.texinfo,v
retrieving revision 1.93
diff -u -p -r1.93 m4.texinfo
--- doc/m4.texinfo	15 Jan 2007 14:04:26 -0000	1.93
+++ doc/m4.texinfo	23 Jan 2007 14:26:24 -0000
@@ -1706,12 +1706,13 @@ consist of one
 or more digits, allowing macros to have any number of arguments.  This
 is not so in UNIX implementations of @code{m4}, which only recognize
 one digit.
-@comment FIXME - See Austin group XCU ERN 111.  This is controversial,
-@comment and POSIX is moving to reserve ${ for implementation use.  We
-@comment should phase out $10 and replace it with ${10}, and consider
-@comment other extensions like ${1-default}.  There are existing m4
-@comment scripts that depend on $10 being the first parameter
-@comment concatenated with 0, not the tenth argument.
+@comment FIXME - See Austin group XCU ERN 111.  POSIX says that $11 must
+@comment be the first argument concatenated with 1, and instead reserves
+@comment ${11} for implementation use.  Once this is implemented, the
+@comment documentation needs to reflect how these extended arguments
+@comment are handled, as well as backwards compatibility issues with
+@comment 1.4.x.  Also, consider adding further extensions such as
+@comment ${1-default}, which expands to `default' if $1 is empty.
 
 As a special case, the zeroth argument, @code{$0}, is always the name
 of the macro being expanded.
@@ -4154,6 +4155,15 @@ the single character @samp{,}.
 Characters that can introduce an argument reference in the body of a
 macro.  The default is the single character @samp{$}.
 
+@item Left brace
+Characters that introduce an extended argument reference in the body of
+a macro immediately after a character in the Dollar category.  The
+default is the single character @samp{@{}.
+
+@item Right brace
+Characters that conclude an extended argument reference in the body of a
+macro.  The default is the single character @samp{@}}.
+
 @item Left quote
 The set of characters that can start a single-character quoted string.
 The default is the single character @samp{`}.  For multiple-character
@@ -4523,11 +4533,54 @@ This is the first and last normal input 
 The saved input is only reread when the end of normal input is seen, and
 not if @code{m4exit} is used to exit @code{m4}.
 
+@comment FIXME: this contradicts POSIX, which requires that "If the
+@comment m4wrap macro is used multiple times, the arguments specified
+@comment shall be processed in the order in which the m4wrap macros were
+@comment processed."
 It is safe to call @code{m4wrap} from saved text, but then the order in
 which the saved text is reread is undefined.  If @code{m4wrap} is not used
 recursively, the saved pieces of text are reread in the opposite order
 in which they were saved (LIFO---last in, first out).
 
+Here is an example of implementing a factorial function using
+@code{m4wrap}:
+
+@example
+define(`f', `ifelse(`$1', `0', `Answer: 0!=1
+', eval(`$1>1'), `0', `Answer: $2$1=eval(`$2$1')
+', `m4wrap(`f(decr(`$1'), `$2$1*')')')')
+@result{}
+f(`10')
+@result{}
+^D
+@result{}Answer: 10*9*8*7*6*5*4*3*2*1=3628800
+@end example
+
+Invocations of @code{m4wrap} at the same recursion level are
+concatenated and rescanned as usual:
+
+@example
+define(`aa', `AA
+')
+@result{}
+m4wrap(`a')m4wrap(`a')
+@result{}
+^D
+@result{}AA
+@end example
+
+@noindent
+however, the transition between recursion levels behaves like an end of
+file condition between two input files.
+
+@comment status: 1
+@example
+m4wrap(`m4wrap(`)')len(abc')
+@result{}
+^D
+@error{}m4:stdin:1: end of file in argument list
+@end example
+
 @node File Inclusion
 @chapter File inclusion
 
@@ -6739,7 +6792,11 @@ Some bigger @code{m4} applications may b
 containing hundreds of definitions and other costly initializations.
 Usually, the common base is kept in one or more declarative files,
 which files are listed on each @code{m4} invocation prior to the
-user's input file, or else, @code{include}'d from this input file.
+user's input file, or else each input file uses @code{include}.
+
+Reading the common base of a big application, over and over again, may
+be time consuming.  @acronym{GNU} @code{m4} offers some machinery to
+speed up the start of an application using lengthy common bases.
 
 @menu
 * Using frozen files::          Using frozen files
@@ -6756,23 +6813,22 @@ user's input file, or else, @code{includ
 @cindex dumping into frozen file
 @cindex reloading a frozen file
 @cindex @acronym{GNU} extensions
-Reading the common base of a big application, over and over again, may
-be time consuming.  GNU @code{m4} offers some machinery to speed up
-the start of an application using lengthy common bases.  Presume the
-user repeatedly uses:
+Suppose a user has a library of @code{m4} initializations in
+@file{base.m4}, which is then used with multiple input files:
 
 @comment ignore
 @example
-m4 base.m4 input.m4
+$ @kbd{m4 base.m4 input1.m4}
+$ @kbd{m4 base.m4 input2.m4}
+$ @kbd{m4 base.m4 input3.m4}
 @end example
 
-@noindent
-with a varying contents of @file{input.m4}, but a rather fixed contents
-for @file{base.m4}.  Then, the user might rather execute:
+Rather than spending time parsing the fixed contents of @file{base.m4}
+every time, the user might rather execute:
 
 @comment ignore
 @example
-m4 -F base.m4f base.m4
+$ @kbd{m4 -F base.m4f base.m4}
 @end example
 
 @noindent
@@ -6780,20 +6836,22 @@ once, and further execute, as often as n
 
 @comment ignore
 @example
-m4 -R base.m4f input.m4
+$ @kbd{m4 -R base.m4f input1.m4}
+$ @kbd{m4 -R base.m4f input2.m4}
+$ @kbd{m4 -R base.m4f input3.m4}
 @end example
 
 @noindent
 with the varying input.  The first call, containing the @code{-F}
-option, only reads and executes file @file{base.m4}, so defining
-various application macros and computing other initializations.  Only
-once the input file @file{base.m4} has been completely processed, GNU
-@code{m4} produces on @file{base.m4f} a @dfn{frozen} file, that is, a
+option, only reads and executes file @file{base.m4}, defining
+various application macros and computing other initializations.
+Once the input file @file{base.m4} has been completely processed, @acronym{GNU}
+@code{m4} produces in @file{base.m4f} a @dfn{frozen} file, that is, a
 file which contains a kind of snapshot of the @code{m4} internal state.
 
 Later calls, containing the @code{-R} option, are able to reload
-the internal state of @code{m4}'s memory, from @file{base.m4f},
-@emph{prior} to reading any other input files.  By this mean,
+the internal state of @code{m4}, from @file{base.m4f},
+@emph{prior} to reading any other input files.  This means
 instead of starting with a virgin copy of @code{m4}, input will be
 read after having effectively recovered the effect of a prior run.
 In our example, the effect is the same as if file @file{base.m4} has
@@ -6807,7 +6865,7 @@ some care is taken, the command:
 
 @comment ignore
 @example
-m4 file1.m4 file2.m4 file3.m4 file4.m4
+$ @kbd{m4 file1.m4 file2.m4 file3.m4 file4.m4}
 @end example
 
 @noindent
@@ -6816,20 +6874,13 @@ output:
 
 @comment ignore
 @example
-m4 -F file1.m4f file1.m4
-m4 -R file1.m4f -F file2.m4f file2.m4
-m4 -R file2.m4f -F file3.m4f file3.m4
-m4 -R file3.m4f file4.m4
-@end example
-
-This could also be done in a simple way, if everything has been prepared
-before:
-
-@comment ignore
-@example
-m4 -F file1.m4f file1.m4 file2.m4 file3.m4 file4.m4
+$ @kbd{m4 -F file1.m4f file1.m4}
+$ @kbd{m4 -R file1.m4f -F file2.m4f file2.m4}
+$ @kbd{m4 -R file2.m4f -F file3.m4f file3.m4}
+$ @kbd{m4 -R file3.m4f file4.m4}
 @end example
 
+@comment FIXME - merge the rest of this section.
 Some care is necessary because not every effort has been made for
 this to work in all cases.  In particular, the trace attribute of
 macros is not handled.
@@ -6855,6 +6906,13 @@ Wow - thanks for really reading the manu
 this text is not removed before a release.
 FIXME - split out the two formats into separate nodes.
 
+When loading format 1, the syntax categories @samp{@{} and @samp{@}} are
+disabled (reverting braces to be treated like plain characters).  This
+is because frozen files created with M4 1.4.x did not understand
+@samp{$@{@dots{}@}} extended argument notation, and a frozen macro that
+contained this character sequence should not behave differently just
+because a newer version of M4 reloaded the file.
+
 @node Frozen file format 2
 @section Frozen file format 2
 
Index: m4/input.c
===================================================================
RCS file: /sources/m4/m4/m4/input.c,v
retrieving revision 1.59
diff -u -p -r1.59 input.c
--- m4/input.c	23 Dec 2006 00:02:20 -0000	1.59
+++ m4/input.c	23 Jan 2007 14:26:24 -0000
@@ -1,5 +1,5 @@
 /* GNU m4 -- A simple macro processor
-   Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2006 Free Software
+   Copyright (C) 1989, 1990, 1991, 1992, 1993, 1994, 2006, 2007 Free Software
    Foundation, Inc.
 
    This program is free software; you can redistribute it and/or modify
@@ -1170,11 +1170,13 @@ m4__next_token (m4 *context, m4_symbol_v
 	obstack_1grow (&token_stack, ch);
 
 	if (m4_has_syntax (M4SYNTAX, ch,
-			   M4_SYNTAX_OTHER | M4_SYNTAX_NUM | M4_SYNTAX_DOLLAR))
+			   (M4_SYNTAX_OTHER | M4_SYNTAX_NUM | M4_SYNTAX_DOLLAR
+                            | M4_SYNTAX_LBRACE | M4_SYNTAX_RBRACE)))
 	  {
 	    consume_syntax (context, &token_stack,
 			    (M4_SYNTAX_OTHER | M4_SYNTAX_NUM
-			     | M4_SYNTAX_DOLLAR));
+                             | M4_SYNTAX_DOLLAR | M4_SYNTAX_LBRACE
+                             | M4_SYNTAX_RBRACE));
 	    type = M4_TOKEN_STRING;
 	  }
 	else if (m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_SPACE))
@@ -1192,7 +1194,8 @@ m4__next_token (m4 *context, m4_symbol_v
 	obstack_1grow (&token_stack, ch);
 
 	if (m4_has_syntax (M4SYNTAX, ch,
-			   M4_SYNTAX_OTHER | M4_SYNTAX_NUM | M4_SYNTAX_DOLLAR))
+			   (M4_SYNTAX_OTHER | M4_SYNTAX_NUM | M4_SYNTAX_DOLLAR
+                            | M4_SYNTAX_LBRACE | M4_SYNTAX_RBRACE)))
 	  type = M4_TOKEN_STRING;
 	else if (m4_has_syntax (M4SYNTAX, ch, M4_SYNTAX_SPACE))
 	  type = M4_TOKEN_SPACE;
Index: m4/m4module.h
===================================================================
RCS file: /sources/m4/m4/m4/m4module.h,v
retrieving revision 1.104
diff -u -p -r1.104 m4module.h
--- m4/m4module.h	13 Jan 2007 13:55:37 -0000	1.104
+++ m4/m4module.h	23 Jan 2007 14:26:24 -0000
@@ -355,30 +355,32 @@ extern	bool		 m4_is_syntax_single_quotes
 extern	bool		 m4_is_syntax_single_comments	(m4_syntax_table *);
 extern	bool		 m4_is_syntax_macro_escaped	(m4_syntax_table *);
 
-/* These are values to be assigned to syntax table entries, although they
-   are bit masks for fast categorisation in m4__next_token(), only one
-   value per syntax table entry is allowed.  */
+/* These are values to be assigned to syntax table entries.  Although
+   they are bit masks for fast categorization in m4__next_token(),
+   only one value per syntax table entry is allowed.  The enumeration
+   is currently sorted in order of parsing precedence.  */
 enum {
-  M4_SYNTAX_OTHER		= (1 << 0),
-  M4_SYNTAX_IGNORE		= (1 << 1),
-  M4_SYNTAX_SPACE		= (1 << 2),
-  M4_SYNTAX_OPEN		= (1 << 3),
-  M4_SYNTAX_CLOSE		= (1 << 4),
-  M4_SYNTAX_COMMA		= (1 << 5),
-  M4_SYNTAX_DOLLAR		= (1 << 6),
-  M4_SYNTAX_ACTIVE		= (1 << 7),
-  M4_SYNTAX_ESCAPE		= (1 << 8),
-  M4_SYNTAX_ASSIGN		= (1 << 9),
-  M4_SYNTAX_ALPHA		= (1 << 10),
-  M4_SYNTAX_NUM			= (1 << 11),
-  M4_SYNTAX_LQUOTE		= (1 << 12),
-  M4_SYNTAX_BCOMM		= (1 << 13),
+  M4_SYNTAX_IGNORE		= 0,
+  M4_SYNTAX_ESCAPE		= 1 << 0,
+  M4_SYNTAX_ALPHA		= 1 << 1,
+  M4_SYNTAX_LQUOTE		= 1 << 2,
+  M4_SYNTAX_BCOMM		= 1 << 3,
+  M4_SYNTAX_OTHER		= 1 << 4,
+  M4_SYNTAX_NUM			= 1 << 5,
+  M4_SYNTAX_DOLLAR		= 1 << 6,
+  M4_SYNTAX_LBRACE		= 1 << 7,
+  M4_SYNTAX_RBRACE		= 1 << 8,
+  M4_SYNTAX_SPACE		= 1 << 9,
+  M4_SYNTAX_ACTIVE		= 1 << 10,
+  M4_SYNTAX_OPEN		= 1 << 11,
+  M4_SYNTAX_CLOSE		= 1 << 12,
+  M4_SYNTAX_COMMA		= 1 << 13,
 
   /* These values are bit masks to OR with categories above, a syntax entry
      may have any number of these in addition to a maximum of one of the
      values above.  */
-  M4_SYNTAX_RQUOTE		= (1 << 14),
-  M4_SYNTAX_ECOMM		= (1 << 15),
+  M4_SYNTAX_RQUOTE		= 1 << 14,
+  M4_SYNTAX_ECOMM		= 1 << 15
 };
 
 #define M4_SYNTAX_MASKS		(M4_SYNTAX_RQUOTE | M4_SYNTAX_ECOMM)
Index: m4/syntax.c
===================================================================
RCS file: /sources/m4/m4/m4/syntax.c,v
retrieving revision 1.20
diff -u -p -r1.20 syntax.c
--- m4/syntax.c	12 Jan 2007 23:07:27 -0000	1.20
+++ m4/syntax.c	23 Jan 2007 14:26:24 -0000
@@ -36,9 +36,10 @@
    M4_SYNTAX_CLOSE	Close list of macro arguments
    M4_SYNTAX_COMMA	Separates macro arguments
    M4_SYNTAX_DOLLAR	Indicates macro argument in user macros
+   M4_SYNTAX_LBRACE	Indicates start of extended macro argument
+   M4_SYNTAX_RBRACE	Indicates end of extended macro argument
    M4_SYNTAX_ACTIVE	This character is a macro name by itself
    M4_SYNTAX_ESCAPE	Use this character to prefix all macro names
-   M4_SYNTAX_ASSIGN	*Used to assign defaults in parameter lists
 
    M4_SYNTAX_ALPHA	Alphabetic characters (can start macro names)
    M4_SYNTAX_NUM	Numeric characters (can form macro names)
@@ -75,22 +76,29 @@
    The precedence as implemented by next_token () is:
 
    M4_SYNTAX_IGNORE	*Filtered out below next_token ()
-   M4_SYNTAX_ESCAPE	Reads macro name iff set, else next
-   M4_SYNTAX_ALPHA	Reads macro name
+   M4_SYNTAX_ESCAPE	Reads macro name iff set, else next character
+   M4_SYNTAX_ALPHA	Reads M4_SYNTAX_ALPHA and M4_SYNTAX_NUM as macro name
    M4_SYNTAX_LQUOTE	Reads all until balanced M4_SYNTAX_RQUOTE
    M4_SYNTAX_BCOMM	Reads all until M4_SYNTAX_ECOMM
 
    M4_SYNTAX_OTHER  }	Reads all M4_SYNTAX_OTHER, M4_SYNTAX_NUM
-   M4_SYNTAX_NUM    }	and M4_SYNTAX_DOLLAR
+   M4_SYNTAX_NUM    }	M4_SYNTAX_DOLLAR, M4_SYNTAX_LBRACE, M4_SYNTAX_RBRACE
    M4_SYNTAX_DOLLAR }
+   M4_SYNTAX_LBRACE }
+   M4_SYNTAX_RBRACE }
 
-   M4_SYNTAX_SPACE	Reads all M4_SYNTAX_SPACE
-   M4_SYNTAX_ACTIVE	Returns a single char as a word
-   the rest		Returned as a single char
-
-   The $ is not really a part of m4's input syntax in the sense that a
-   string is parsed equally whether there is a $ or not.  The character
-   $ is used by convention in user macros.  */
+   M4_SYNTAX_SPACE	Reads all M4_SYNTAX_SPACE, depending on buffering
+   M4_SYNTAX_ACTIVE	Returns a single char as a macro name
+
+   M4_SYNTAX_OPEN   }	Returned as a single char
+   M4_SYNTAX_CLOSE  }
+   M4_SYNTAX_COMMA  }
+
+   The $, {, and } are not really a part of m4's input syntax, because a
+   a string is parsed equally whether there is a $ or not.  These characters
+   are instead used during user macro expansion.
+
+   M4_SYNTAX_RQUOTE and M4_SYNTAX_ECOMM do not start tokens.  */
 
 static bool	check_is_single_quotes		(m4_syntax_table *);
 static bool	check_is_single_comments	(m4_syntax_table *);
@@ -120,16 +128,18 @@ m4_syntax_create (void)
       case '$':
 	syntax->orig[ch] = M4_SYNTAX_DOLLAR;
 	break;
+      case '{':
+	syntax->orig[ch] = M4_SYNTAX_LBRACE;
+	break;
+      case '}':
+	syntax->orig[ch] = M4_SYNTAX_RBRACE;
+	break;
       case '`':
 	syntax->orig[ch] = M4_SYNTAX_LQUOTE;
 	break;
       case '#':
 	syntax->orig[ch] = M4_SYNTAX_BCOMM;
 	break;
-      case '=':
-	/* FIXME -revisit the assign syntax attribute.  */
-	/* syntax->orig[ch] = M4_SYNTAX_ASSIGN; */
-	/* break; */
       case '\0':
 	/* FIXME - revisit the ignore syntax attribute.  */
 	/* syntax->orig[ch] = M4_SYNTAX_IGNORE; */
@@ -169,26 +179,26 @@ m4_syntax_code (char ch)
 
   switch (ch)
     {
-    /* FIXME - revisit the ignore syntax attribute.  */
-    case 'I': case 'i': code = M4_SYNTAX_IGNORE; break;
-    case 'O': case 'o': code = M4_SYNTAX_OTHER;  break;
-    case 'S': case 's': code = M4_SYNTAX_SPACE;  break;
-    case 'W': case 'w': code = M4_SYNTAX_ALPHA;  break;
-    case 'D': case 'd': code = M4_SYNTAX_NUM;    break;
-
-    case '(': code = M4_SYNTAX_OPEN;   break;
-    case ')': code = M4_SYNTAX_CLOSE;  break;
-    case ',': code = M4_SYNTAX_COMMA;  break;
-    /* FIXME - revisit the assign syntax attribute.  */
-    case '=': code = M4_SYNTAX_ASSIGN; break;
-    case '@': code = M4_SYNTAX_ESCAPE; break;
-    case '$': code = M4_SYNTAX_DOLLAR; break;
-
-    case 'L': case 'l': code = M4_SYNTAX_LQUOTE; break;
-    case 'R': case 'r': code = M4_SYNTAX_RQUOTE; break;
-    case 'B': case 'b': code = M4_SYNTAX_BCOMM;  break;
-    case 'E': case 'e': code = M4_SYNTAX_ECOMM;  break;
-    case 'A': case 'a': code = M4_SYNTAX_ACTIVE;  break;
+       /* Sorted according to the order of M4_SYNTAX_* in m4module.h.  */
+       /* FIXME - revisit the ignore syntax attribute.  */
+    case 'I': case 'i':	code = M4_SYNTAX_IGNORE; break;
+    case '@':		code = M4_SYNTAX_ESCAPE; break;
+    case 'W': case 'w':	code = M4_SYNTAX_ALPHA;  break;
+    case 'L': case 'l':	code = M4_SYNTAX_LQUOTE; break;
+    case 'B': case 'b':	code = M4_SYNTAX_BCOMM;  break;
+    case 'O': case 'o':	code = M4_SYNTAX_OTHER;  break;
+    case 'D': case 'd':	code = M4_SYNTAX_NUM;    break;
+    case '$':		code = M4_SYNTAX_DOLLAR; break;
+    case '{':		code = M4_SYNTAX_LBRACE; break;
+    case '}':		code = M4_SYNTAX_RBRACE; break;
+    case 'S': case 's':	code = M4_SYNTAX_SPACE;  break;
+    case 'A': case 'a':	code = M4_SYNTAX_ACTIVE; break;
+    case '(':		code = M4_SYNTAX_OPEN;   break;
+    case ')':		code = M4_SYNTAX_CLOSE;  break;
+    case ',':		code = M4_SYNTAX_COMMA;  break;
+
+    case 'R': case 'r':	code = M4_SYNTAX_RQUOTE; break;
+    case 'E': case 'e':	code = M4_SYNTAX_ECOMM;  break;
 
     default: code = -1;  break;
     }
Index: src/freeze.c
===================================================================
RCS file: /sources/m4/m4/src/freeze.c,v
retrieving revision 1.59
diff -u -p -r1.59 freeze.c
--- src/freeze.c	21 Jan 2007 04:09:06 -0000	1.59
+++ src/freeze.c	23 Jan 2007 14:26:24 -0000
@@ -267,9 +267,9 @@ produce_frozen_state (m4 *context, const
 
   produce_resyntax_dump (context, file);
 
-  /* Dump syntax table. */
+  /* Dump syntax table.  */
 
-  str = "IS(),$A@OWDLRBE";
+  str = "I@WLBOD${}SA(),RE";
   while (*str)
     produce_syntax_dump (file, M4SYNTAX, *str++);
 
@@ -492,6 +492,9 @@ reload_frozen_state (m4 *context, const 
 	m4__module_open (context, "traditional", NULL);
       else
 	m4__module_open (context, "gnu", NULL);
+      /* Disable { and } categories, since ${11} was not supported in
+         1.4.x.  */
+      m4_set_syntax (context->syntax, 'O', '+', "{}");
       break;
     default:
       if (version > 2)
Index: tests/freeze.at
===================================================================
RCS file: /sources/m4/m4/tests/freeze.at,v
retrieving revision 1.8
diff -u -p -r1.8 freeze.at
--- tests/freeze.at	31 Aug 2006 03:21:35 -0000	1.8
+++ tests/freeze.at	23 Jan 2007 14:26:24 -0000
@@ -1,5 +1,5 @@
 # Hand crafted tests for GNU M4.                               -*- Autotest -*-
-# Copyright (C) 2006 Free Software Foundation, Inc.
+# Copyright (C) 2006, 2007 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -39,7 +39,7 @@ GNU M4 1.4.5
 $ cat frozen.m4
 divert(`-1')
 define(`foo', `\FOO')
-pushdef(`foo', `bar')
+pushdef(`foo', `bar${1}')
 define(`my_define', defn(`define'))
 define(`my_changeword', defn(`changeword'))
 pushdef(`my_define', `define')
@@ -72,12 +72,12 @@ F9,6
 my_definedefine
 T3,4
 foo\FOO
-T3,3
-foobar
+T3,7
+foobar${1}
 F3,3
 dnldnl
-D1,4
-bar
+D1,8
+bar${1}
 
 D0,0
 
@@ -85,7 +85,7 @@ D0,0
 ]])
 
 AT_DATA([input.m4],
-[[foo /* foo */ popdef([foo])foo
+[[foo([2]) /* foo */ popdef([foo])foo
 my_define([bar], [1])[]popdef([my_define]) bar
 my_define([bar], [2])[]popdef([my_define]) bar
 my_define([bar], [3])[]popdef([my_define]) bar
@@ -93,12 +93,12 @@ my_define([bar], [4])[]popdef([my_define
 ]])
 
 AT_CHECK_M4([-R frozen.m4f input.m4], [0],
-[[bar /* foo */ \FOO
+[[bar${1} /* foo */ \FOO
  1
 define 1
  3
 my_define(bar, 4) 3
-bar
+bar${1}
 ]],
 [[m4:input.m4:5: Warning: popdef: undefined macro `my_define'
 ]])
@@ -106,9 +106,162 @@ bar
 AT_CLEANUP
 
 
-## -------------------------- ##
-## Reloading unknown builtins ##
-## -------------------------- ##
+## ---------------- ##
+## loading format 2 ##
+## ---------------- ##
+
+AT_SETUP([loading format 2])
+AT_KEYWORDS([frozen])
+
+AT_DATA([frozen.m4f],
+[[# Handcrafted file, obeying the version 2 spec
+V2
+# missing close quote should be supplied
+Q1,0
+>
+# missing close comment should be supplied
+C1,0
+<
+M2
+m4
+M3
+gnu
+F7,7,3
+builtinbuiltingnu
+# Testing escape sequences
+T4,5
+blah\t\477\040\X5C
+]])
+
+AT_DATA([input.m4],
+[[< comment: builtin()
+builtin(>define', foo, bar)
+foo
+blah
+]])
+
+AT_CHECK_M4([-R frozen.m4f input.m4], [0],
+[[< comment: builtin()
+
+bar
+	'7 \
+]])
+
+AT_CLEANUP
+
+
+## --------- ##
+## changecom ##
+## --------- ##
+
+AT_SETUP([reloading changecom])
+AT_KEYWORDS([frozen])
+
+# Check that changesyntax is maintained across freeze boundaries.
+
+AT_DATA([[frozen.m4]],
+[[changecom`'changequote(<,>)dnl
+]])
+
+AT_DATA([[unfrozen.m4]],
+[[define(<foo>, <bar>)
+foo # foo
+]])
+
+# First generate the `expout' output by running over the sources before
+# freezing.
+AT_CHECK_M4([frozen.m4 unfrozen.m4], [0],
+	    [stdout], [stderr])
+
+mv stdout expout
+mv stderr experr
+
+# Now freeze the first source file.
+AT_CHECK_M4([-F frozen.m4f frozen.m4], [0])
+
+# Now rerun the original sequence, but using the frozen file.
+AT_CHECK_M4([-R frozen.m4f unfrozen.m4], [0],
+	    [expout], [experr])
+
+AT_CLEANUP
+
+
+## ------------ ##
+## changesyntax ##
+## ------------ ##
+
+AT_SETUP([reloading changesyntax])
+AT_KEYWORDS([frozen])
+
+# Check that changesyntax is maintained across freeze boundaries.
+
+AT_DATA([[frozen.m4]],
+[[changesyntax(`W+.', `({', `)}')dnl
+define{`a.b', `hello $1'}dnl
+]])
+
+AT_DATA([[unfrozen.m4]],
+[[a.b{world}
+]])
+
+# First generate the `expout' output by running over the sources before
+# freezing.
+AT_CHECK_M4([frozen.m4 unfrozen.m4], [0],
+	    [stdout], [stderr])
+
+mv stdout expout
+mv stderr experr
+
+# Now freeze the first source file.
+AT_CHECK_M4([-F frozen.m4f frozen.m4], [0])
+
+# Now rerun the original sequence, but using the frozen file.
+AT_CHECK_M4([-R frozen.m4f unfrozen.m4], [0],
+	    [expout], [experr])
+
+AT_CLEANUP
+
+
+## ------------- ##
+## regexp syntax ##
+## ------------- ##
+
+AT_SETUP([reloading regexp syntax])
+AT_KEYWORDS([frozen])
+
+# Check that regular expression syntax is maintained across freeze boundaries.
+
+AT_DATA([[frozen.m4]],
+[[changeresyntax(`POSIX_EXTENDED')dnl
+]])
+
+AT_DATA([[unfrozen.m4]],
+[[regexp(`GNUs not Unix', `\w(\w*)$')
+regexp(`GNUs not Unix', `\w\(\w*\)$', `GNU_M4')
+]])
+
+# First generate the `expout' output by running over the sources before
+# freezing.
+AT_CHECK_M4([frozen.m4 unfrozen.m4], [0],
+	    [stdout], [stderr])
+
+mv stdout expout
+mv stderr experr
+
+# Now freeze the first source file.
+AT_CHECK_M4([-F frozen.m4f frozen.m4], [0],
+	    [ignore], [ignore])
+
+# Now rerun the original sequence, but using the frozen file.
+AT_CHECK_M4([-R frozen.m4f unfrozen.m4], [0],
+	    [expout], [experr])
+
+AT_CLEANUP
+
+
+## ---------------- ##
+## unknown builtins ##
+## ---------------- ##
 
 AT_SETUP([reloading unknown builtin])
 AT_KEYWORDS([frozen])
@@ -158,39 +311,3 @@ c:	`'
 ]])
 
 AT_CLEANUP
-
-## ---------------------- ##
-## Freezing regexp syntax ##
-## ---------------------- ##
-
-AT_SETUP([regexp syntax])
-AT_KEYWORDS([frozen])
-
-# Check that regular expression syntax is maintained across freeze baundaries.
-
-AT_DATA([[frozen.m4]],
-[[changeresyntax(`POSIX_EXTENDED')dnl
-]])
-
-AT_DATA([[unfrozen.m4]],
-[[regexp(`GNUs not Unix', `\w(\w*)$')
-regexp(`GNUs not Unix', `\w\(\w*\)$', `GNU_M4')
-]])
-
-# First generate the `expout' output by running over the sources before
-# freezing.
-AT_CHECK_M4([frozen.m4 unfrozen.m4], 0,
-	    [stdout], [stderr])
-
-mv stdout expout
-mv stderr experr
-
-# Now freeze the first source file.
-AT_CHECK_M4([-F frozen.m4f frozen.m4], 0,
-	    [ignore], [ignore])
-
-# Now rerun the original sequence, but using the frozen file.
-AT_CHECK_M4([-R frozen.m4f unfrozen.m4], 0,
-	    [expout], [experr])
-
-AT_CLEANUP([frozen.m4f])
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.