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 65c55209..97da55dd 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
@@ -7193,12 +7193,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')
@@ -7215,6 +7222,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')
@@ -7226,12 +7237,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 69cd5e41..e3bb8b2c 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;
}
@@ -490,6 +498,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
[email protected]
https://lists.gnu.org/mailman/listinfo/m4-patches