GNU Make and FizzBuzz

This is a pared down version of a comment I left on Lobsters. It's FizzBuzz implemented entirely in GNU Make. Some of this is taken from John Graham-Cumming's excellent The GNU Make Book.

# GNU Make implementation of FizzBuzz

_pow2 = $(if $1,$(foreach a,x x,$(call _pow2,$(wordlist 2,$(words $1),$1))),x x)
_all := $(call _pow2,1 2 3 4 5 6 7 8)
num = $(words $1)
val = $(wordlist 1,$1,$(_all))

decr = $(wordlist 2,$(words $1),$1)

max = $(subst xx,x,$(join $1,$2))

eq = $(filter $(words $1),$(words $2))
gt = $(filter-out $(words $2),$(words $(call max,$1,$2)))
gte = $(call gt,$1,$2)$(call eq,$1,$2)

subtract = $(if $(call gte,$1,$2),$(filter-out xx,$(join $1,$2)),$(warning Underflow))
mod = $(if $(call gte,$1,$2),$(call mod,$(call subtract,$1,$2),$2),$1)

fizz = $(call eq,$(call val,0),$(call mod,$1,$(call val,3)))
buzz = $(call eq,$(call val,0),$(call mod,$1,$(call val,5)))
fizzbuzz = $(and $(call fizz,$1),$(call buzz,$1))

check = $(if $(call fizzbuzz,$1),$(info FizzBuzz),\
	  $(if $(call fizz,$1),$(info Fizz),\
	    $(if $(call buzz,$1),$(info Buzz),\
	      $(info $(call num,$1)))))

loop = $(if $1,$(call check,$1)$(call loop,$(call decr,$1)),)

all: ; @: $(call loop,$(call val,100))

Here's the output. It counts down from 100, only because I didn't care one way or the other.

% make all
Buzz
Fizz
98
97
Fizz
Buzz
94
Fizz
92
91
FizzBuzz
89
88
Fizz
86
Buzz
Fizz
83
82
Fizz
Buzz
79
Fizz
77
76
FizzBuzz
74
73
Fizz
71
Buzz
Fizz
68
67
Fizz
Buzz
64
Fizz
62
61
FizzBuzz
59
58
Fizz
56
Buzz
Fizz
53
52
Fizz
Buzz
49
Fizz
47
46
FizzBuzz
44
43
Fizz
41
Buzz
Fizz
38
37
Fizz
Buzz
34
Fizz
32
31
FizzBuzz
29
28
Fizz
26
Buzz
Fizz
23
22
Fizz
Buzz
19
Fizz
17
16
FizzBuzz
14
13
Fizz
11
Buzz
Fizz
8
7
Fizz
Buzz
4
Fizz
2
1

-- Geoff (comment@wozniak.ca)
2022-07-13T21:15:00-04:00