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)