Re: format and eval

Eric Blake <[email protected]>
Newsgroups gmane.comp.gnu.m4.patches
Message-ID <[email protected]>
Gary V. Vaughan <gary <at> gnu.org> writes:

Hi Gary,

> On Sat, 06 Jan 2007 12:52:50 -0700, "Eric Blake" <ebb9 <at> byu.net> said:
> > I'm not sure if any
> > existing m4 scripts depended on this undocumented behavior.  If you think
> > it wise, I could do a followup patch to edit the branch to issue a
> > warning
> > but still perform the equality test, rather than this patch's behavior of
> > treating = as a hard error.
> 
> Yes, we should not introduce regressions in a maintenance release.  HEAD
> on the other hand is free to DTRT.

Done as follows; part 4 in this patch series.

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

	* src/eval.c (ASSIGN): New enumerator.
	(eval_lex): Recognize '='.
	(equality_term): Treat '=' like '==', but warn that it is
	deprecated.
	* doc/m4.texinfo (Eval): Document and test this.
	(Incompatibilities): Document the POSIX incompatibility.
	* NEWS: Document this change.

Index: NEWS
===================================================================
RCS file: /sources/m4/m4/NEWS,v
retrieving revision 1.1.1.1.2.87
diff -u -r1.1.1.1.2.87 NEWS
--- NEWS	6 Jan 2007 19:56:11 -0000	1.1.1.1.2.87
+++ NEWS	9 Jan 2007 16:08:04 -0000
@@ -8,11 +8,11 @@
   files larger than 2GiB on some platforms.
 * Fix a regression introduced in 1.4.8 that made m4 dump core when
   invoked as 'm4 -- file'.
-* The `eval' builtin now follows C precedence rules.  Additionally,
-  short-circuit operators correctly short-circuit division by zero.
-  The undocumented alias of '=' meaning '==' in eval now triggers
-  an error, so that a future version of M4 can implement a form of
-  variable assignment as an extension.
+* The `eval' builtin now follows C precedence rules.  Additionally, the
+  short-circuit operators correctly short-circuit division by zero.  The
+  previously undocumented alias of '=' meaning '==' in eval now triggers a
+  deprecation warning, so that a future version of M4 can implement a form
+  of variable assignment as an extension.
 
 Version 1.4.8 - 20 November 2006, by Eric Blake  (CVS version 1.4.7a)
 
Index: doc/m4.texinfo
===================================================================
RCS file: /sources/m4/m4/doc/m4.texinfo,v
retrieving revision 1.1.1.1.2.106
diff -u -r1.1.1.1.2.106 m4.texinfo
--- doc/m4.texinfo	6 Jan 2007 19:56:11 -0000	1.1.1.1.2.106
+++ doc/m4.texinfo	9 Jan 2007 16:08:04 -0000
@@ -4466,10 +4466,28 @@
 @end deffn
 
 All binary operators, except exponentiation, are left associative.  C
-operators that perform variable assignment, such as @samp{=} or
+operators that perform variable assignment, such as @samp{+=} or
 @samp{--}, are forbidden by @acronym{POSIX}, since @code{eval} only
 operates on constants, not variables.  Attempting to use them results
-in an error.
+in an error.  However, since traditional implementations treated
+@samp{=} as an undocumented alias for @samp{==} as opposed to an
+assignment operator, this usage is supported as a special case.  Be
+aware that a future version of @acronym{GNU} M4 may support assignment
+semantics as an extension when @acronym{POSIX} mode is not requested,
+and that using @samp{=} to check equality is not portable.
+
+@comment status: 1
+@example
+eval(`2 = 2')
+@error{}m4:stdin:1: Warning: recommend ==, not =, for equality operator
+@result{}1
+eval(`++0')
+@error{}m4:stdin:2: invalid operator in eval: ++0
+@result{}
+eval(`0 |= 1')
+@error{}m4:stdin:3: invalid operator in eval: 0 |= 1
+@result{}
+@end example
 
 Note that some older @code{m4} implementations use @samp{^} as an
 alternate operator for the exponentiation, although @acronym{POSIX}
@@ -4492,7 +4510,6 @@
 implementations of @code{m4} require explicit parentheses to get the
 correct result:
 
-@comment status: 1
 @example
 eval(`1 == 2 > 0')
 @result{}1
@@ -4508,24 +4525,15 @@
 @result{}0
 eval(`+ + - ~ ! ~ 0')
 @result{}1
-eval(`++0')
-@error{}m4:stdin:8: invalid operator in eval: ++0
-@result{}
-eval(`1 = 1')
-@error{}m4:stdin:9: invalid operator in eval: 1 = 1
-@result{}
-eval(`0 |= 1')
-@error{}m4:stdin:10: invalid operator in eval: 0 |= 1
-@result{}
 eval(`2 || 1 / 0')
 @result{}1
 eval(`0 || 1 / 0')
-@error{}m4:stdin:12: divide by zero in eval: 0 || 1 / 0
+@error{}m4:stdin:9: divide by zero in eval: 0 || 1 / 0
 @result{}
 eval(`0 && 1 % 0')
 @result{}0
 eval(`2 && 1 % 0')
-@error{}m4:stdin:14: modulo by zero in eval: 2 && 1 % 0
+@error{}m4:stdin:11: modulo by zero in eval: 2 && 1 % 0
 @result{}
 @end example
 
@@ -5672,7 +5680,9 @@
 ensure proper precedence.  As extensions to @acronym{POSIX},
 @acronym{GNU} @code{m4} gives well-defined semantics to operations that
 C leaves undefined, such as when overflow occurs, when shifting negative
-numbers, or when performing division by zero.
+numbers, or when performing division by zero.  @acronym{POSIX} also
+requires @samp{=} to cause an error, but many traditional
+implementations allowed it as an alias for @samp{==}.
 
 @item
 @acronym{POSIX} requires @code{translit} (@pxref{Translit}) to treat
Index: src/eval.c
===================================================================
RCS file: /sources/m4/m4/src/Attic/eval.c,v
retrieving revision 1.1.1.1.2.8
diff -u -r1.1.1.1.2.8 eval.c
--- src/eval.c	6 Jan 2007 19:56:11 -0000	1.1.1.1.2.8
+++ src/eval.c	9 Jan 2007 16:08:04 -0000
@@ -34,7 +34,7 @@
     PLUS, MINUS,
     EXPONENT,
     TIMES, DIVIDE, MODULO,
-    EQ, NOTEQ, GT, GTEQ, LS, LSEQ,
+    ASSIGN, EQ, NOTEQ, GT, GTEQ, LS, LSEQ,
     LSHIFT, RSHIFT,
     LNOT, LAND, LOR,
     NOT, AND, OR, XOR,
@@ -215,7 +215,7 @@
 	  eval_text++;
 	  return EQ;
 	}
-      return BADOP;
+      return ASSIGN;
     case '!':
       if (*eval_text == '=')
 	{
@@ -517,7 +517,10 @@
   if ((er = cmp_term (et, v1)) != NO_ERROR)
     return er;
 
-  while ((op = eval_lex (&v2)) == EQ || op == NOTEQ)
+  /* In the 1.4.x series, we maintain the traditional behavior that
+     '=' is a synonym for '=='; however, this is contrary to POSIX and
+     we hope to convert '=' to mean assignment in 2.0.  */
+  while ((op = eval_lex (&v2)) == EQ || op == NOTEQ || op == ASSIGN)
     {
       et = eval_lex (&v2);
       if (et == ERROR)
@@ -525,6 +528,13 @@
 
       if ((er = cmp_term (et, &v2)) != NO_ERROR)
 	return er;
+
+      if (op == ASSIGN)
+      {
+	M4ERROR ((warning_status, 0, "\
+Warning: recommend ==, not =, for equality operator"));
+	op = EQ;
+      }
       *v1 = (op == EQ) == (*v1 == v2);
     }
   if (op == ERROR)
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.