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=4e149960673934a405b3dec721b2a1d2e88b2f8d The branch, branch-1.6 has been updated via 4e149960673934a405b3dec721b2a1d2e88b2f8d (commit) from 6a95d853eb3c7493345ea093e8efa9f35a49c143 (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 4e149960673934a405b3dec721b2a1d2e88b2f8d Author: Eric Blake <[email protected]> Date: Wed Dec 24 14:15:13 2008 -0700 Enhance eval, as allowed by POSIX 2008. * src/eval.c (enum eval_token): Add QUESTION and COLON. (enum eval_error): Add MISSING_COLON. (condition_term): New function. (eval_lex, simple_term): Support new operator. (evaluate): Likewise. Warn, not error, on invalid operator. * doc/m4.texinfo (Eval): Update documentation. (Improved forloop): Adjust test. * NEWS: Document the change. Signed-off-by: Eric Blake <[email protected]> ----------------------------------------------------------------------- Summary of changes: ChangeLog | 12 +++++++++ NEWS | 4 +++ doc/m4.texinfo | 30 ++++++++++++++-------- src/eval.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 4 files changed, 103 insertions(+), 18 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7f3bde2..d15e52a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2008-12-24 Eric Blake <[email protected]> + + Enhance eval, as allowed by POSIX 2008. + * src/eval.c (enum eval_token): Add QUESTION and COLON. + (enum eval_error): Add MISSING_COLON. + (condition_term): New function. + (eval_lex, simple_term): Support new operator. + (evaluate): Likewise. Warn, not error, on invalid operator. + * doc/m4.texinfo (Eval): Update documentation. + (Improved forloop): Adjust test. + * NEWS: Document the change. + 2008-12-23 Eric Blake <[email protected]> Issue deprecation warning for -o/--error-output. diff --git a/NEWS b/NEWS index ebd2cbb..2e1a286 100644 --- a/NEWS +++ b/NEWS @@ -107,6 +107,10 @@ Foundation, Inc. context of a macro name, rather than acting on the empty string. This was already done for `define', `pushdef', `builtin', and `indir'. +** Enhance the `eval' builtin to understand the `?:' operator, and + downgrade a failed parse due to an unknown operator from an error to a + warning. + ** A number of portability improvements inherited from gnulib. * Noteworthy changes in Version 1.4.10b (2008-02-25) [beta] diff --git a/doc/m4.texinfo b/doc/m4.texinfo index 2ab7290..93adb64 100644 --- a/doc/m4.texinfo +++ b/doc/m4.texinfo @@ -6670,6 +6670,8 @@ Bitwise or Logical and @item || Logical or +...@item ?: +Conditional ternary @end table The macro @code{eval} is recognized only with parameters. @@ -6678,7 +6680,7 @@ The macro @code{eval} is recognized only with parameters. All binary operators, except exponentiation, are left associative. C operators that perform variable assignment, such as @samp{+=} or @samp{--}, are not implemented, since @code{eval} only operates on -constants, not variables. Attempting to use them results in an error. +constants, not variables. Attempting to use them results in a warning. 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 @@ -6686,16 +6688,15 @@ 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: eval: recommend ==, not =, for equality @result{}1 eval(`++0') -...@error{}m4:stdin:2: eval: invalid operator: ++0 +...@error{}m4:stdin:2: Warning: eval: invalid operator: `++0' @result{} eval(`0 |= 1') -...@error{}m4:stdin:3: eval: invalid operator: 0 |= 1 +...@error{}m4:stdin:3: Warning: eval: invalid operator: `0 |= 1' @result{} @end example @@ -6738,12 +6739,12 @@ eval(`+ + - ~ ! ~ 0') eval(`2 || 1 / 0') @result{}1 eval(`0 || 1 / 0') -...@error{}m4:stdin:9: Warning: eval: divide by zero: 0 || 1 / 0 +...@error{}m4:stdin:9: Warning: eval: divide by zero: `0 || 1 / 0' @result{} eval(`0 && 1 % 0') @result{}0 eval(`2 && 1 % 0') -...@error{}m4:stdin:11: Warning: eval: modulo by zero: 2 && 1 % 0 +...@error{}m4:stdin:11: Warning: eval: modulo by zero: `2 && 1 % 0' @result{} @end example @@ -6751,7 +6752,8 @@ eval(`2 && 1 % 0') As a @acronym{GNU} extension, the operator @samp{**} performs integral exponentiation. The operator is right-associative, and if evaluated, the exponent must be non-negative, and at least one of the arguments -must be non-zero, or a warning is issued. +must be non-zero, or a warning is issued. Also, the C operator +...@samp{?:} is supported. @example eval(`2 ** 3 ** 2') @@ -6764,10 +6766,16 @@ eval(`2 ** 0') @result{}1 eval(`0 ** 0') @result{} -...@error{}m4:stdin:5: Warning: eval: divide by zero: 0 ** 0 +...@error{}m4:stdin:5: Warning: eval: divide by zero: `0 ** 0' eval(`4 ** -2') -...@error{}m4:stdin:6: Warning: eval: negative exponent: 4 ** -2 +...@error{}m4:stdin:6: Warning: eval: negative exponent: `4 ** -2' @result{} +eval(`0 ? 2 : 3') +...@result{}3 +eval(`1 ? 2 : 1/0') +...@result{}2 +eval(`0 ? 1/0 : 3') +...@result{}3 @end example Within @var{expression}, (but not @var{radix} or @var{width}), numbers @@ -6811,7 +6819,7 @@ square(square(`5')` + 1') define(`foo', `666') @result{} eval(`foo / 6') -...@error{}m4:stdin:11: Warning: eval: bad expression: foo / 6 +...@error{}m4:stdin:11: Warning: eval: bad expression: `foo / 6' @result{} eval(foo / 6) @result{}111 @@ -8254,7 +8262,7 @@ forloop(`', `1', `2', ` odd iterator name') forloop(`i', `5 + 5', `0xc', ` 0x`'eval(i, `16')') @result{} 0xa 0xb 0xc forloop(`i', `a', `b', `non-numeric bounds') -...@error{}m4:stdin:6: Warning: eval: bad expression (bad input): (a) <= (b) +...@error{}m4:stdin:6: Warning: eval: bad input: `(a) <= (b)' @result{} @end example diff --git a/src/eval.c b/src/eval.c index 1b617ed..c5ad30d 100644 --- a/src/eval.c +++ b/src/eval.c @@ -39,6 +39,7 @@ typedef enum eval_token LNOT, LAND, LOR, NOT, AND, OR, XOR, LEFTP, RIGHTP, + QUESTION, COLON, NUMBER, EOTEXT } eval_token; @@ -56,6 +57,7 @@ typedef enum eval_error about a syntax error. */ SYNTAX_ERROR, MISSING_RIGHT, + MISSING_COLON, UNKNOWN_INPUT, EXCESS_INPUT, INVALID_OPERATOR, @@ -63,6 +65,7 @@ typedef enum eval_error } eval_error; +static eval_error condition_term (const call_info *, eval_token, int32_t *); static eval_error logical_or_term (const call_info *, eval_token, int32_t *); static eval_error logical_and_term (const call_info *, eval_token, int32_t *); static eval_error or_term (const call_info *, eval_token, int32_t *); @@ -283,6 +286,10 @@ eval_lex (int32_t *val) return LEFTP; case ')': return RIGHTP; + case '?': + return QUESTION; + case ':': + return COLON; default: return ERROR; } @@ -303,7 +310,7 @@ evaluate (const call_info *me, const char *expr, size_t len, int32_t *val) if (et == EOTEXT) err = EMPTY_ARGUMENT; else - err = logical_or_term (me, et, val); + err = condition_term (me, et, val); if (err == NO_ERROR && *eval_text != '\0') { @@ -313,6 +320,8 @@ evaluate (const call_info *me, const char *expr, size_t len, int32_t *val) err = EXCESS_INPUT; } + if (err != NO_ERROR) + expr = quotearg_style_mem (locale_quoting_style, expr, len); switch (err) { /* Cases where result is printed. */ @@ -325,8 +334,11 @@ evaluate (const call_info *me, const char *expr, size_t len, int32_t *val) /* Cases where error makes result meaningless. */ case MISSING_RIGHT: - m4_warn (0, me, _("bad expression (missing right parenthesis): %s"), - expr); + m4_warn (0, me, _("missing right parenthesis: %s"), expr); + break; + + case MISSING_COLON: + m4_warn (0, me, _("missing colon: %s"), expr); break; case SYNTAX_ERROR: @@ -334,15 +346,15 @@ evaluate (const call_info *me, const char *expr, size_t len, int32_t *val) break; case UNKNOWN_INPUT: - m4_warn (0, me, _("bad expression (bad input): %s"), expr); + m4_warn (0, me, _("bad input: %s"), expr); break; case EXCESS_INPUT: - m4_warn (0, me, _("bad expression (excess input): %s"), expr); + m4_warn (0, me, _("excess input: %s"), expr); break; case INVALID_OPERATOR: - m4_error (0, 0, me, _("invalid operator: %s"), expr); + m4_warn (0, me, _("invalid operator: %s"), expr); break; case DIVIDE_ZERO: @@ -370,6 +382,55 @@ evaluate (const call_info *me, const char *expr, size_t len, int32_t *val) `---------------------------*/ static eval_error +condition_term (const call_info *me, eval_token et, int32_t *v1) +{ + int32_t v2; + int32_t v3; + eval_error er; + + if ((er = logical_or_term (me, et, v1)) != NO_ERROR) + return er; + + if ((et = eval_lex (&v2)) == QUESTION) + { + et = eval_lex (&v2); + if (et == ERROR) + return UNKNOWN_INPUT; + + /* Implement short-circuiting of valid syntax. */ + /* C requires 'logical_or_term ? expression : condition_term'; + if we ever introduce assignment_term or comma_term, then + condition_term and expression are no longer synonymous. */ + er = condition_term (me, et, &v2); + if (er != NO_ERROR + && !(*v1 == 0 && er < SYNTAX_ERROR)) + return er; + + et = eval_lex (&v3); + if (et == ERROR) + return UNKNOWN_INPUT; + if (et != COLON) + return MISSING_COLON; + + et = eval_lex (&v3); + if (et == ERROR) + return UNKNOWN_INPUT; + + er = condition_term (me, et, &v3); + if (er != NO_ERROR + && !(*v1 != 0 && er < SYNTAX_ERROR)) + return er; + + *v1 = *v1 ? v2 : v3; + } + if (et == ERROR) + return UNKNOWN_INPUT; + + eval_undo (); + return NO_ERROR; +} + +static eval_error logical_or_term (const call_info *me, eval_token et, int32_t *v1) { int32_t v2; @@ -832,7 +893,7 @@ simple_term (const call_info *me, eval_token et, int32_t *v1) if (et == ERROR) return UNKNOWN_INPUT; - if ((er = logical_or_term (me, et, v1)) != NO_ERROR) + if ((er = condition_term (me, et, v1)) != NO_ERROR) return er; et = eval_lex (&v2); hooks/post-receive -- GNU M4 source repository
