количество непустых аргументов, переданных макросу

В GNU M4 я пытался написать функцию, которая определяет, сколько непустых (аргументов, не равных `') передано ей.

Он должен вызываться так:

ne_nargs(0, `1', `')
# 1

ne_nargs(0, `')
# 0

ne_nargs(0, `1')
# 1

Обратите внимание, что первым аргументом всегда должно быть 0.

Вот код, который у меня есть до сих пор:

define(`ne_nargs', `ifelse(`$#', `1`, $1,
   `ifelse(`$2', `', `pushdef(`$2', $1)ne_nargs(shift($@))',
     `pushdef(`$2', incr($1))ne_nargs(shift($@))')')')

И вот псевдокод для него:

if (number_of_args == 1); then
  return first_arg; // which is `0` by default.
else if (second_arg == ''); then
  second_arg = first_arg;
  return ne_nargs(shift(all_args));
else
  second_arg = (++first_arg);
  return ne_nargs(shift(all_args));

ne_nargs(`0', `', `1', `i', `', `l')

# what I get
m4:test.m4:8: empty string treated as 0 in builtin `incr'
m4:test.m4:8: empty string treated as 0 in builtin `incr'
1

# what I expect
3

Я не могу понять, что я делаю неправильно в определении ne_nargs, и, попробовав несколько разных способов абстрагирования частей макроса, я почти готов сдаться.


m4
person Alexej Magura    schedule 28.12.2014    source источник


Ответы (1)


Я не думаю, что вам следует пытаться перезаписать $@; вы можете видеть из предупреждений, что перезапись $2 определенно не влияет на $@. пример соединения в документации вместо этого смещает второй аргумент с помощью:

`$0(`$1', shift(shift($@)))'

Итак, работает следующее:

define(`ne_nargs', `ifelse(`$#', `2', `ifelse(`$2', `', `$1', incr(`$1'))',
  `ifelse(`$2', `', `$0(`$1', shift(shift($@)))',
    `$0(incr($1), shift(shift($@)))')')')
ne_nargs(`0', `', `1', `i', `', `l')

(Я не знаю хорошего способа очистки рекурсивного вызова, поэтому вызов с двумя аргументами не нужно проверять независимо, так что это может быть что-то, что можно улучшить, если вы беспокоитесь о СУХОСТИ.)

person lossleader    schedule 30.12.2014