Module Name: src Committed By: rillig Date: Sat Oct 3 17:30:54 UTC 2020
Modified Files: src/usr.bin/make/unit-tests: Makefile Added Files: src/usr.bin/make/unit-tests: hanoi-include.exp hanoi-include.mk Log Message: make(1): add test demonstrating the Towers of Hanoi puzzle It's not the primary task of make to handle procedure calls with parameters, combined with lexical scoping, therefore the code does not look as straight-forward or clean as in other programming languages. It feels more like squeezing a programming problem from the imperative world into the world of declarative dependencies. A more idiomatic way of implementing this puzzle should be as a dependency graph since that's both the natural structure of the puzzle and the primary domain of make. Something like having a main target "hanoi-5" that depends on intermediate targets of the form "move-1.2.3.4.5-_._._._._-_._._._._", each representing a single configuration of the stacks. These targets could be generated dynamically. A benefit of this implementation would be that the puzzle could be resumed from an arbitrary configuration, just just from the initial configuration. To generate a diff of this commit: cvs rdiff -u -r1.158 -r1.159 src/usr.bin/make/unit-tests/Makefile cvs rdiff -u -r0 -r1.1 src/usr.bin/make/unit-tests/hanoi-include.exp \ src/usr.bin/make/unit-tests/hanoi-include.mk Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/usr.bin/make/unit-tests/Makefile diff -u src/usr.bin/make/unit-tests/Makefile:1.158 src/usr.bin/make/unit-tests/Makefile:1.159 --- src/usr.bin/make/unit-tests/Makefile:1.158 Sat Oct 3 14:39:36 2020 +++ src/usr.bin/make/unit-tests/Makefile Sat Oct 3 17:30:54 2020 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.158 2020/10/03 14:39:36 rillig Exp $ +# $NetBSD: Makefile,v 1.159 2020/10/03 17:30:54 rillig Exp $ # # Unit tests for make(1) # @@ -168,6 +168,7 @@ TESTS+= export-env TESTS+= export-variants TESTS+= forloop TESTS+= forsubst +TESTS+= hanoi-include TESTS+= impsrc TESTS+= include-main TESTS+= job-output-long-lines Added files: Index: src/usr.bin/make/unit-tests/hanoi-include.exp diff -u /dev/null src/usr.bin/make/unit-tests/hanoi-include.exp:1.1 --- /dev/null Sat Oct 3 17:30:54 2020 +++ src/usr.bin/make/unit-tests/hanoi-include.exp Sat Oct 3 17:30:54 2020 @@ -0,0 +1,32 @@ +Move the upper disk from stack A to stack C. +Move the upper disk from stack A to stack B. +Move the upper disk from stack C to stack B. +Move the upper disk from stack A to stack C. +Move the upper disk from stack B to stack A. +Move the upper disk from stack B to stack C. +Move the upper disk from stack A to stack C. +Move the upper disk from stack A to stack B. +Move the upper disk from stack C to stack B. +Move the upper disk from stack C to stack A. +Move the upper disk from stack B to stack A. +Move the upper disk from stack C to stack B. +Move the upper disk from stack A to stack C. +Move the upper disk from stack A to stack B. +Move the upper disk from stack C to stack B. +Move the upper disk from stack A to stack C. +Move the upper disk from stack B to stack A. +Move the upper disk from stack B to stack C. +Move the upper disk from stack A to stack C. +Move the upper disk from stack B to stack A. +Move the upper disk from stack C to stack B. +Move the upper disk from stack C to stack A. +Move the upper disk from stack B to stack A. +Move the upper disk from stack B to stack C. +Move the upper disk from stack A to stack C. +Move the upper disk from stack A to stack B. +Move the upper disk from stack C to stack B. +Move the upper disk from stack A to stack C. +Move the upper disk from stack B to stack A. +Move the upper disk from stack B to stack C. +Move the upper disk from stack A to stack C. +exit status 0 Index: src/usr.bin/make/unit-tests/hanoi-include.mk diff -u /dev/null src/usr.bin/make/unit-tests/hanoi-include.mk:1.1 --- /dev/null Sat Oct 3 17:30:54 2020 +++ src/usr.bin/make/unit-tests/hanoi-include.mk Sat Oct 3 17:30:54 2020 @@ -0,0 +1,41 @@ +# $NetBSD: hanoi-include.mk,v 1.1 2020/10/03 17:30:54 rillig Exp $ +# +# Implements the Towers of Hanoi puzzle, thereby demonstrating a bunch of +# useful programming techniques: +# +# * default assignment using the ?= assignment operator +# * including the same file recursively +# * extracting the current value of a variable using the .for loop +# * using shell commands for calculations since make is a text processor +# * using the :: dependency operator for adding commands to a target +# * on-the-fly variable assignment expressions using the ::= modifier +# +# usage: +# env N=3 make -f hanoi-include.mk +# endless loop: +# make -f hanoi-include.mk N=3 + +N?= 5 # Move this number of disks ... +FROM?= A # ... from this stack ... +VIA?= B # ... via this stack ... +TO?= C # ... to this stack. + +.if $N == 1 +. for from to in ${FROM} ${TO} +all:: + @echo "Move the upper disk from stack ${from} to stack ${to}." +. endfor +.else +_:= ${N::!=expr $N - 1} ${TMP::=${VIA}} ${VIA::=${TO}} ${TO::=${TMP}} +. include "${.PARSEDIR}/${.PARSEFILE}" +_:= ${N::!=expr $N + 1} ${TMP::=${VIA}} ${VIA::=${TO}} ${TO::=${TMP}} + +. for from to in ${FROM} ${TO} +all:: + @echo "Move the upper disk from stack ${from} to stack ${to}." +. endfor + +_:= ${N::!=expr $N - 1} ${TMP::=${VIA}} ${VIA::=${FROM}} ${FROM::=${TMP}} +. include "${.PARSEDIR}/${.PARSEFILE}" +_:= ${N::!=expr $N + 1} ${TMP::=${VIA}} ${VIA::=${FROM}} ${FROM::=${TMP}} +.endif