Created
January 10, 2015 13:58
-
-
Save amagura/b3fc9ccab6e5433e7d40 to your computer and use it in GitHub Desktop.
M4 - 99 bottles of beer song
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dnl GNU M4 - A macro language | |
dnl by Alexej Magura | |
divert(-1) | |
dnl Removes all the trailing newlines and | |
dnl prevents unnecessary usage of `dnl' | |
dnl (i.e. using `dnl' to remove trailing newlines) | |
dnl The `expand` macros are from Autoconf. | |
dnl Everything else is me. | |
define(`expand', `_$0(-=<{($1)}>=-)') | |
define(`_expand',`changequote(`-=<{(', `)}>=-')$1changequote(`, ')') | |
dnl Return the expansion of ARG as a single string. | |
define(`cmp',dnl | |
`ifelse(eval((`$1' == `$2')), 1, 0, ifelse(eval((`$1' > `$2')), 1, 1, -1))') | |
dnl expands to: | |
dnl 0: `$1' and `$2' are equal | |
dnl 1: `$1' is greater than `$2' | |
dnl -1: `$2' is greater than `$1' | |
define(`for_', `pushdef(`hdx', `incr($1)')define(`$1', decr(expand($1)))dnl | |
hdx sing_and_drink(`hdx', `$2') | |
ifelse(cmp($1, $2), 1, `$0(`$1', `$2', `sing_and_drink(`$1', `$2')')')') | |
dnl Not a true generic for-loop, since | |
dnl it calls `song_and_drink' directly from with-in. | |
dnl NOTE that the `dnl' in `for' is required | |
dnl since we are inside of a macro definition. | |
define(`beer_left', 99) | |
define(`__drink__', `beer') | |
dnl since M4 is a preprocessing macro language | |
dnl it can be used to make simple textual replacements | |
define(`__bottle__', | |
`ifelse(`$2', `suffix',pushdef(`idx', decr(`$1'))ifelse(cmp($1, 1), 0, `idx bottle', | |
cmp($1, 0), 0, `no more bottles', | |
cmp($1, -1), 0, `99 bottles', | |
cmp($1, 2), 1, `idx bottles', | |
cmp($1, 2), 0, `idx bottle'), | |
cmp($1, 1), 1, `bottles', | |
cmp($1, 1), 0, `1 bottle', | |
cmp($1, 0), 0, `No more bottles')') | |
dnl `ifelse' works like a `switch' statement if it is given 6 or more args | |
define(`sing_and_drink', | |
`ifelse(cmp($1, $2), 1,`__bottle__($1) of __drink__ on the wall, __bottle__(incr($1), `suffix') of __drink__. | |
Take one down and pass it around, __bottle__(ifelse($1, 1, 0, $1), `suffix') of __drink__ on the wall. | |
',cmp($1, $2), 0, `__bottle__($1) of __drink__ on the wall, __bottle__($1, `suffix') of __drink__. | |
Go to the store and buy some more, __bottle__(decr($1), `suffix') of __drink__ on the wall. | |
')') | |
divert(0)dnl | |
for_(`beer_left', 1)dnl | |
sing_and_drink(1, 0) | |
sing_and_drink(0, 0)dnl |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment