# The following operators return a non-empty string if their result

# is true:

#

# gt First argument greater than second argument

# gte First argument greater than or equal to second argument

# lt First argument less than second argument

# lte First argument less than or equal to second argument

# eq First argument is numerically equal to the second argument

# ne First argument is not numerically equal to the second argument

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

lt = $(filter-out $(words $1),$(words $(call max,$1,$2)))

eq = $(filter $(words $1),$(words $2))

ne = $(filter-out $(words $1),$(words $2))

gte = $(call gt,$1,$2)$(call eq,$1,$2)

lte = $(call lt,$1,$2)$(call eq,$1,$2)

# increment adds 1 to its argument, decrement subtracts 1. Note that

# decrement does not range check and hence will not underflow, but

# will incorrectly say that 0 - 1 = 0

increment = $1 x

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

# double doubles its argument, and halve halves it

double = $1 $1

halve = $(subst xx,x,$(filter-out xy x y,$(join $1,$(foreach a,$1,y x))))

# This code implements a reverse polish notation calculator by

# transforming a comma-separated list of operators (+ - * /) and

# numbers stored in the calc variable into the appropriate calls to

# the arithmetic functions defined in this Makefile

# This is the current stack of numbers entered into the

# calculator. The push function puts an item onto the top of the stack

# (the start of the list) and pop removes the top item.

stack :=

push = $(eval stack := $$1 $(stack))

pop = $(word 1,$(stack))$(eval stack := $(wordlist 2,$(words $(stack)),$(stack)))

# pope and pushd are used to pop a number off the stack and encode it

# and push a number onto the stack after decoding

pope = $(call encode,$(call pop))

pushd = $(call push,$(call decode,$1))

# calculate runs through the input numbers and operations and either

# pushes a number on the stack, or pops two numbers off and does a

# calculation followed by pushing the result back. When calculate

# finished there will be one item on the stack which is the result.

comma := ,

calculate=$(foreach t,$(subst $(comma), ,$1),$(call handle,$t))$(stack)

# seq is a string equality operator that returns true (a non-empty

# string) if the two strings are equal

seq = $(filter $1,$2)

# handle is used by calculate to handle a single token. If it's an

# operator then the appropriate operator function is called, if it's a

# number then it is pushed.

handle = $(call pushd, \

$(if $(call seq,+,$1), \

$(call plus,$(call pope),$(call pope)), \

$(if $(call seq,-,$1), \

$(call subtract,$(call pope),$(call pope)), \

$(if $(call seq,*,$1), \

$(call multiply,$(call pope),$(call pope)), \

$(if $(call seq,/,$1), \

$(call divide,$(call pope),$(call pope)), \

$(call encode,$1))))))

.PHONY: calc

calc: ; @echo $(call calculate,$(calc))

Tags: