Prev: Incr Up: Arithmetic
12.2 Evaluating integer expressions
Integer expressions are evaluated with `eval':
-- Builtin: eval (EXPRESSION, [RADIX = `10'], [WIDTH])
Expands to the value of EXPRESSION. The expansion is empty if a
problem is encountered while parsing the arguments. If specified,
RADIX and WIDTH control the format of the output.
Calculations are done with 32-bit signed numbers. Overflow
silently results in wraparound. A warning is issued if division
by zero is attempted, or if EXPRESSION could not be parsed.
Expressions can contain the following operators, listed in order of
`+ - ~ !'
Unary plus and minus, and bitwise and logical negation
`* / %'
Multiplication, division, and modulo
Addition and subtraction
Shift left or right
`> >= < <='
The macro `eval' is recognized only with parameters.
All binary operators, except exponentiation, are left associative. C
operators that perform variable assignment, such as `+=' or `--', are
not implemented, since `eval' only operates on constants, not
variables. Attempting to use them results in an error. However, since
traditional implementations treated `=' as an undocumented alias for
`==' as opposed to an assignment operator, this usage is supported as a
special case. Be aware that a future version of GNU M4 may support
assignment semantics as an extension when POSIX mode is not requested,
and that using `=' to check equality is not portable.
eval(`2 = 2')
error-->m4:stdin:1: Warning: recommend ==, not =, for equality operator
error-->m4:stdin:2: invalid operator in eval: ++0
eval(`0 |= 1')
error-->m4:stdin:3: invalid operator in eval: 0 |= 1
Note that some older `m4' implementations use `^' as an alternate
operator for the exponentiation, although POSIX requires the C behavior
of bitwise exclusive-or. The precedence of the negation operators, `~'
and `!', was traditionally lower than equality. The unary operators
could not be used reliably more than once on the same term without
intervening parentheses. The traditional precedence of the equality
operators `==' and `!=' was identical instead of lower than the
relational operators such as `<', even through GNU M4 1.4.8. Starting
with version 1.4.9, GNU M4 correctly follows POSIX precedence rules.
M4 scripts designed to be portable between releases must be aware that
parentheses may be required to enforce C precedence rules. Likewise,
division by zero, even in the unused branch of a short-circuiting
operator, is not always well-defined in other implementations.
Following are some examples where the current version of M4 follows C
precedence rules, but where older versions and some other
implementations of `m4' require explicit parentheses to get the correct
eval(`1 == 2 > 0')
eval(`(1 == 2) > 0')
eval(`! 0 * 2')
eval(`! (0 * 2)')
eval(`1 | 1 ^ 1')
eval(`(1 | 1) ^ 1')
eval(`+ + - ~ ! ~ 0')
eval(`2 || 1 / 0')
eval(`0 || 1 / 0')
error-->m4:stdin:9: divide by zero in eval: 0 || 1 / 0
eval(`0 && 1 % 0')
eval(`2 && 1 % 0')
error-->m4:stdin:11: modulo by zero in eval: 2 && 1 % 0
As a GNU extension, the operator `**' 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.
eval(`2 ** 3 ** 2')
eval(`(2 ** 3) ** 2')
eval(`0 ** 1')
eval(`2 ** 0')
eval(`0 ** 0')
error-->m4:stdin:5: divide by zero in eval: 0 ** 0
eval(`4 ** -2')
error-->m4:stdin:6: negative exponent in eval: 4 ** -2
Within EXPRESSION, (but not RADIX or WIDTH), numbers without a
special prefix are decimal. A simple `0' prefix introduces an octal
number. `0x' introduces a hexadecimal number. As GNU extensions, `0b'
introduces a binary number. `0r' introduces a number expressed in any
radix between 1 and 36: the prefix should be immediately followed by
the decimal expression of the radix, a colon, then the digits making
the number. For radix 1, leading zeros are ignored, and all remaining
digits must be `1'; for all other radices, the digits are `0', `1', `2',
.... Beyond `9', the digits are `a', `b' ... up to `z'. Lower and
upper case letters can be used interchangeably in numbers prefixes and
as number digits.
Parentheses may be used to group subexpressions whenever needed.
For the relational operators, a true relation returns `1', and a false
relation return `0'.
Here are a few examples of use of `eval'.
eval(`-3 * 5')
eval(`-99 / 10')
eval(`-99 % 10')
eval(`99 % -10')
eval(index(`Hello world', `llo') >= 0)
eval(`0r1:0111 + 0b100 + 0r3:12')
define(`square', `eval(`($1) ** 2')')
square(square(`5')` + 1')
eval(`foo / 6')
error-->m4:stdin:11: bad expression in eval: foo / 6
eval(foo / 6)
As the last two lines show, `eval' does not handle macro names, even
if they expand to a valid expression (or part of a valid expression).
Therefore all macros must be expanded before they are passed to `eval'.
Some calculations are not portable to other implementations, since
they have undefined semantics in C, but GNU `m4' has well-defined
behavior on overflow. When shifting, an out-of-range shift amount is
implicitly brought into the range of 32-bit signed integers using an
implicit bit-wise and with 0x1f).
eval(min_int` < 0')
eval(max_int` > 0')
ifelse(eval(min_int` / -1'), min_int, `overflow occurred')
eval(`0x80000000 % -1')
eval(`-4 >> 1')
eval(`-4 >> 33')
If RADIX is specified, it specifies the radix to be used in the
expansion. The default radix is 10; this is also the case if RADIX is
the empty string. A warning results if the radix is outside the range
of 1 through 36, inclusive. The result of `eval' is always taken to be
signed. No radix prefix is output, and for radices greater than 10,
the digits are lower case. The WIDTH argument specifies the minimum
output width, excluding any negative sign. The result is zero-padded
to extend the expansion to the requested width. A warning results if
the width is negative. If RADIX or WIDTH is out of bounds, the
expansion of `eval' is empty.
eval(`666', `6', `10')
eval(`-666', `6', `10')
eval(`10', `', `0')
`0r1:'eval(`10', `1', `11')
error-->m4:stdin:9: radix 37 in builtin `eval' out of range
eval(`1', , `-1')
error-->m4:stdin:10: negative width to builtin `eval'
error-->m4:stdin:11: empty string treated as 0 in builtin `eval'
automatically generated by info2www