Previous: , Up: Arithmetic   [Contents][Index]


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 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: , Up: Arithmetic   [Contents][Index]