m4: Eval

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