Borrow an idea from Java: even though eval always operates on signed inputs, the ability to do an unsigned right shift is valuable when operating on bitmasks.
* src/eval.c (eval_token): Add URSHIFT. (eval_lex): Tokenize it. (parse_expr): Evaluate it. * doc/m4.texi (Eval): Document this. * NEWS: Likewise. --- NEWS | 9 +++++---- doc/m4.texi | 29 ++++++++++++++++++++--------- src/eval.c | 15 ++++++++++++++- 3 files changed, 39 insertions(+), 14 deletions(-) diff --git a/NEWS b/NEWS index 97c4d9c0..0b499a20 100644 --- a/NEWS +++ b/NEWS @@ -126,10 +126,11 @@ GNU M4 NEWS - User visible changes. 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. Further, the builtin now refuses to recognize `=' as a - synonym for `==' (this had emitted a warning since 1.4.8b). +** Enhance the `eval' builtin to understand the `?:' and `>>>' operators, + and downgrade a failed parse due to an unknown operator from an error to + a warning (the same as for all other syntax errors). Further, the + builtin now refuses to recognize `=' as a synonym for `==' (this had + emitted a warning since 1.4.8b). ** A number of portability improvements inherited from gnulib. diff --git a/doc/m4.texi b/doc/m4.texi index 5a7980e7..12ea662e 100644 --- a/doc/m4.texi +++ b/doc/m4.texi @@ -7092,7 +7092,7 @@ Eval Multiplication, division, and modulo @item + - Addition and subtraction -@item << >> +@item << >> >>> Shift left or right @item > >= < <= Relational operators @@ -7199,12 +7199,19 @@ Eval @end example @cindex GNU extensions -As a 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. Also, the ternary C operator -@samp{?:} is supported, including the GNU extension of reusing the -non-zero value of the left side if the middle term is empty. +As a GNU extension, several additional operators are supported. Since +M4 1.4, the operator @samp{**} performs integral exponentiation. This +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. Additionally, M4 1.6 introduced the @samp{>>>} and +@samp{?:} operators. The operator @samp{>>>} has the same precedence as +@samp{>>}, but where @samp{>>} extends the sign bit into the most +significant bits, @samp{>>>} performs an unsigned shift that always +supplies zero bits on the left. Finally, the right-associative ternary +C operator @samp{?:} is supported, including the GNU extension of +reusing the non-zero value of the left side if the middle term is empty. +This operator evaluates the first term, then if the first is non-zero +evaluates the second term, otherwise it evaluates the third term. @example eval(`2 ** 3 ** 2') @@ -7221,6 +7228,10 @@ Eval eval(`4 ** -2') @error{}m4:stdin:6: warning: eval: negative exponent: '4 ** -2' @result{} +eval(`-1 >> 1') +@result{}-1 +eval(`-1 >>> 1') +@result{}2147483647 eval(`0 ? 2 : 3') @result{}3 eval(`1 ? 2 : 1/0') @@ -7232,12 +7243,12 @@ Eval eval(`1 ? 2 ? 3 : 4 : 5') @result{}3 eval(`1/0 ? 2 : 3') -@error{}m4:stdin:12: warning: eval: divide by zero: '1/0 ? 2 : 3' +@error{}m4:stdin:14: warning: eval: divide by zero: '1/0 ? 2 : 3' @result{} eval(`2 ?: 3') @result{}2 eval(`1 ? 2-=3 : 4') -@error{}m4:stdin:14: warning: eval: invalid operator: '1 ? 2-=3 : 4' +@error{}m4:stdin:16: warning: eval: invalid operator: '1 ? 2-=3 : 4' @result{} @end example diff --git a/src/eval.c b/src/eval.c index 163e2634..b236b12e 100644 --- a/src/eval.c +++ b/src/eval.c @@ -55,6 +55,7 @@ typedef enum eval_token LSEQ, LSHIFT = 90, RSHIFT, + URSHIFT, /* precedence given for binary op; PLUS and MINUS also serve as a unary op */ PLUS = 100, MINUS, @@ -255,7 +256,14 @@ eval_lex (int32_t *val) } else if (*eval_text == '>') { - if (*++eval_text == '=') + eval_text++; + if (*eval_text == '>') + { + if (*++eval_text == '=') + return BADOP; + return URSHIFT; + } + else if (*eval_text == '=') return BADOP; return RSHIFT; } @@ -481,6 +489,11 @@ parse_expr (int32_t *v1, eval_error er, unsigned min_prec) u1 >>= (uint32_t) (v2 & 0x1f); *v1 = *v1 < 0 ? ~u1 : u1; break; + case URSHIFT: + u1 = *v1; + u1 >>= (uint32_t) (v2 & 0x1f); + *v1 = u1; + break; case GT: *v1 = *v1 > v2; -- 2.49.0 _______________________________________________ M4-patches mailing list M4-patches@gnu.org https://lists.gnu.org/mailman/listinfo/m4-patches