Previous: Incr, Up: Arithmetic [Contents][Index]
Integer expressions are evaluated with eval
:
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 decreasing precedence.
Parentheses
Unary plus and minus, and bitwise and logical negation
Exponentiation
Multiplication, division, and modulo
Addition and subtraction
Shift left or right
Relational operators
Equality operators
Bitwise and
Bitwise exclusive-or
Bitwise or
Logical and
Logical or
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 ⇒1 eval(`++0') 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 result:
eval(`1 == 2 > 0') ⇒1 eval(`(1 == 2) > 0') ⇒0 eval(`! 0 * 2') ⇒2 eval(`! (0 * 2)') ⇒1 eval(`1 | 1 ^ 1') ⇒1 eval(`(1 | 1) ^ 1') ⇒0 eval(`+ + - ~ ! ~ 0') ⇒1 eval(`2 || 1 / 0') ⇒1 eval(`0 || 1 / 0') error→m4:stdin:9: divide by zero in eval: 0 || 1 / 0 ⇒ eval(`0 && 1 % 0') ⇒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') ⇒512 eval(`(2 ** 3) ** 2') ⇒64 eval(`0 ** 1') ⇒0 eval(`2 ** 0') ⇒1 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') ⇒-15 eval(`-99 / 10') ⇒-9 eval(`-99 % 10') ⇒-9 eval(`99 % -10') ⇒9 eval(index(`Hello world', `llo') >= 0) ⇒1 eval(`0r1:0111 + 0b100 + 0r3:12') ⇒12 define(`square', `eval(`($1) ** 2')') ⇒ square(`9') ⇒81 square(square(`5')` + 1') ⇒676 define(`foo', `666') ⇒ eval(`foo / 6') error→m4:stdin:11: bad expression in eval: foo / 6 ⇒ eval(foo / 6) ⇒111
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).
define(`max_int', eval(`0x7fffffff')) ⇒ define(`min_int', incr(max_int)) ⇒ eval(min_int` < 0') ⇒1 eval(max_int` > 0') ⇒1 ifelse(eval(min_int` / -1'), min_int, `overflow occurred') ⇒overflow occurred min_int ⇒-2147483648 eval(`0x80000000 % -1') ⇒0 eval(`-4 >> 1') ⇒-2 eval(`-4 >> 33') ⇒-2
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', `10') ⇒666 eval(`666', `11') ⇒556 eval(`666', `6') ⇒3030 eval(`666', `6', `10') ⇒0000003030 eval(`-666', `6', `10') ⇒-0000003030 eval(`10', `', `0') ⇒10 `0r1:'eval(`10', `1', `11') ⇒0r1:01111111111 eval(`10', `16') ⇒a eval(`1', `37') error→m4:stdin:9: radix 37 in builtin `eval' out of range ⇒ eval(`1', , `-1') error→m4:stdin:10: negative width to builtin `eval' ⇒ eval() error→m4:stdin:11: empty string treated as 0 in builtin `eval' ⇒0
Previous: Incr, Up: Arithmetic [Contents][Index]