1. 22
  1. 19

    This implementation is not nearly pure GNU Make enough for me. :)

    Here’s one that is pure Make. Some of it is cribbed from The GNU Make Book and not all the definitions are necessary. Numbers are represented by a list of xs. So 5 would be the string x x x x x.

    It counts down from 100 instead of up. I don’t really care.

    _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))
    incr = x $1
    decr = $(wordlist 2,$(words $1),$1)
    max = $(subst xx,x,$(join $1,$2))
    min = $(subst xx,x,$(filter xx,$(join $1,$2)))
    eq = $(filter $(words $1),$(words $2))
    ne = $(filter-out $(words $1),$(words $2))
    gt = $(filter-out $(words $2),$(words $(call max,$1,$2)))
    gte = $(call gt,$1,$2)$(call eq,$1,$2)
    lt = $(filter-out $(words $1),$(words $(call max,$1,$2)))
    lte = $(call lt,$1,$2)$(call eq,$1,$2)
    add = $1 $2
    subtract = $(if $(call gte,$1,$2),$(filter-out xx,$(join $1,$2)),$(warning Underflow))
    multiply = $(foreach a,$1,$2)
    divide = $(if $(call gte,$1,$2),x $(call divide,$(call subtract,$1,$2),$2),)
    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))
    fbcheck = $(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 fbcheck,$1)$(call loop,$(call decr,$1)),)
    all: ; @echo $(call loop,$(call val,100))
    1. 7

      This implementation is not nearly pure GNU Make enough for me. :)

      That’s the spirit :-) I saw a blog post about doing this kind of arithmetic in make but didn’t want to go this far down the rabbit hole. I’m glad you did though.

      1. 4

        Comments and articles like these are why I love lobste.rs :D

        1. 3

          Wow. Some things people were not meant to know.

          This note implies GNU make is Turing complete.


        2. 6

          It relies on a specific and nonportable shell builtin.

          1. 3

            make‘s default shell is /bin/sh. It’s true that seq is not part of POSIX, but I tried this Makefile on macOS, NixOS, Arch Linux, and OpenBSD (you obviously need to pkg_add gmake) and it worked on all of them. It also works when explicitly setting the shell to Bash, ZSH, or OpenBSD’s kush. It did NOT work with Fish, though not because of seq (which is supported) but because the POSIX-style arithmetic is not supported. That’s portable enough for me but YMMV.

          2. 2

            I’ve been trying to think if this is doable in POSIX make, as underpowered as that is… sadly my make-fu is not strong enough. I don’t think it has those good functions in it.

            1. 2

              Much more interesting than FizzBuzz: https://nullprogram.com/blog/2016/04/30/

              1. 1

                omg incredible. so it can be done!