プログラミング言語 FizzBuzz

FizzBuzzを何KBで書けたみたいな話題をちょくちょく目にするのだが、あいにく俺はゴルフの類にはそれほど興味がない。というわけで、じゃあ俺はFizzBuzzを文法にした言語を作ろうかと思って作った。

追記: この言語はwhitespaceを下敷きにしているので、先にwhitespaceについて一通り知っておいた方が良い。なに、たった3つのトークンで出来てる言語だから難しくはないさ。

実は結構昔にwhitespaceインタープリタを書いたことがあるのだが、それにちょっとしたオプションを付けた。上記のプログラムは --fizzbuzz オプションを付けて動かすと、スペースの代わりにFizz, タブの代わりにBuzz, 改行の代わりにFizzBuzzを使ってソースを書けるようになる。各トークンのデリミタは空白記号だ(よってwhitespaceとFizzBuzzの混在が可能っちゃ可能)。

というわけで、何かもう出落ち感がして仕方がないが、FizzBuzzのプログラムをいくつか紹介。

Hello World 

Fizz Fizz Fizz Fizz FizzBuzz "push 0"
Fizz Fizz Fizz Fizz Fizz Fizz Fizz Buzz Fizz Buzz Fizz FizzBuzz "push 10(LF)"
Fizz Fizz Fizz Fizz Fizz Buzz Fizz Buzz Buzz Buzz Fizz FizzBuzz "push 46(.)"
Fizz Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Fizz FizzBuzz "push 64(d)"
Fizz Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Fizz FizzBuzz  "push 114(r)"
Fizz Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Fizz Fizz FizzBuzz  "push 108(l)"
Fizz Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Buzz Buzz FizzBuzz  "push 111(o)"
Fizz Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Buzz Buzz FizzBuzz  "push 119(w)"
Fizz Fizz Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz FizzBuzz  "push 32( )"
Fizz Fizz Fizz Fizz Fizz Buzz Fizz Buzz Buzz Fizz Fizz FizzBuzz  "push 44(,)"
Fizz Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Buzz Buzz FizzBuzz  "push 111(o)"
Fizz Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Fizz Fizz FizzBuzz  "push 108(l)"
Fizz Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Fizz Fizz FizzBuzz  "push 108(l)"
Fizz Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz FizzBuzz  "push 101(e)"
Fizz Fizz Fizz Fizz Buzz Fizz Fizz Buzz Fizz Fizz Fizz FizzBuzz  "push 72(H)"

FizzBuzz Fizz Fizz Fizz Buzz FizzBuzz "loop"
    Fizz FizzBuzz Fizz
    FizzBuzz Buzz Fizz  Buzz Fizz FizzBuzz "break if stack top == 0"
    Buzz FizzBuzz Fizz Fizz "put char"
    FizzBuzz Fizz FizzBuzz Fizz Buzz FizzBuzz "repeat"
FizzBuzz Fizz Fizz Buzz Fizz FizzBuzz "loop end"
Fizz FizzBuzz FizzBuzz

FizzBuzz FizzBuzz FizzBuzz "end of prgram"

まあ、見たまんまである。一文字ずつ逆順にスタックに積んでいき、それらを出力しているだけである。ポイントは最初に0をスタックに積んでいるところで、これは要するにCで言うところの文字列の終端だな。またループ中での判定でスタックトップを消費するので、ループ判定用と出力用にスタックトップの複製を行い、出力後にスタックトップに残った0を除去しているところもポイントといえばそうだ。

こうしてみると、案外普通のループに見え……るわけねえよな。

factorial 

Fizz Fizz Fizz Fizz FizzBuzz "push 0"
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Fizz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Buzz Fizz Buzz FizzBuzz

FizzBuzz Fizz Fizz Fizz Buzz FizzBuzz "loop"
    Fizz FizzBuzz Fizz
    FizzBuzz Buzz Fizz  Buzz Fizz FizzBuzz "break if stack top == 0"
    Buzz FizzBuzz Fizz Fizz "put char"
    FizzBuzz Fizz FizzBuzz Fizz Buzz FizzBuzz "repeat"
FizzBuzz Fizz Fizz Buzz Fizz FizzBuzz "loop end"
Fizz FizzBuzz FizzBuzz

Fizz Fizz Fizz Buzz FizzBuzz
Buzz FizzBuzz Buzz Buzz

Fizz Fizz Fizz Buzz FizzBuzz
Buzz Buzz Buzz
FizzBuzz Fizz Buzz Fizz Fizz FizzBuzz "call fact"
Buzz FizzBuzz Fizz Buzz

FizzBuzz FizzBuzz FizzBuzz

FizzBuzz Fizz Fizz Fizz Fizz FizzBuzz "sub fact"
    Fizz FizzBuzz Fizz "duplicate. stack = [x, x...]"
    Fizz Fizz Fizz Buzz FizzBuzz "stack = [1, x, x...]"
    Buzz Fizz Fizz Buzz "stack = [x-1, x...]"
    Fizz FizzBuzz Fizz "stack =[x-1, x-1, x...]"
    FizzBuzz Buzz Fizz Fizz Buzz Buzz FizzBuzz "if x-1 == 0" "stack =[x-1, x...]"
    FizzBuzz Fizz Buzz Fizz Fizz FizzBuzz "call fact"
    Buzz Fizz Fizz FizzBuzz "stack = [fact(x-1)*x...]"
    FizzBuzz Buzz FizzBuzz "end"

    FizzBuzz Fizz Fizz Fizz Buzz Buzz FizzBuzz "stack =[x-1, x...]"
    Fizz FizzBuzz FizzBuzz "discard. stack = [x(=1)...]"
    FizzBuzz Buzz FizzBuzz "end"

簡単な再帰関数としてよく使われる階乗の計算。スタック操作がせわしないので、スタックの動きを大雑把に書いておいた。後は特に解説の必要はなかろう。

本家ではさらに発狂したfactorialが入手できる。whitespaceなのでまず解読不能なのだが、多分俺の書いた奴よりも手の込んだコードのはず。

Hit and Blow 

# define print sub routine.
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz FizzBuzz "addr of sub print"
Fizz Fizz Fizz Fizz FizzBuzz "push 0"
Buzz Buzz Fizz "regster function addr"
FizzBuzz Fizz Fizz Fizz Buzz FizzBuzz "sub print"
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz FizzBuzz "addr of sub print"
    Buzz Buzz Buzz
    FizzBuzz Buzz Fizz Fizz Buzz Fizz Fizz FizzBuzz "jump to end define"
    FizzBuzz Fizz Fizz Fizz Buzz Buzz FizzBuzz "loop"
        Fizz FizzBuzz Fizz
        FizzBuzz Buzz Fizz Fizz Buzz Fizz FizzBuzz "break if stack top == 0"
        Buzz FizzBuzz Fizz Fizz "put char"
        FizzBuzz Fizz FizzBuzz Fizz Buzz Buzz FizzBuzz "repeat"
    FizzBuzz Fizz Fizz Fizz Buzz Fizz FizzBuzz "loop end"
    Fizz FizzBuzz FizzBuzz
FizzBuzz Buzz FizzBuzz "end sub"
FizzBuzz Fizz Fizz Fizz Buzz Fizz Fizz FizzBuzz "end define"
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz FizzBuzz "addr of sub print"
    Fizz Fizz Fizz Buzz FizzBuzz "push 1"
Buzz Buzz Fizz "defined"

# define judge_hit sub routine.
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Fizz Buzz Fizz FizzBuzz "addr of sub judge_hit"
Fizz Fizz Fizz Fizz FizzBuzz "push 0"
Buzz Buzz Fizz "regster function addr"
FizzBuzz Fizz Fizz Fizz Fizz Fizz Fizz Fizz FizzBuzz "sub judge_hit"
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Fizz Buzz Fizz FizzBuzz "addr of judge_hit"
    Buzz Buzz Buzz
    FizzBuzz Buzz Fizz Fizz Fizz Fizz Fizz Fizz Fizz Fizz FizzBuzz "jump to end define"
    Buzz Fizz Fizz Buzz "num - user input"

    FizzBuzz Buzz Fizz Buzz Fizz Fizz Fizz Fizz Fizz Fizz FizzBuzz "jump to increment hit value"
    FizzBuzz Fizz FizzBuzz Buzz Fizz Fizz Fizz Fizz Fizz Buzz FizzBuzz "jump to end"
    FizzBuzz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz Fizz FizzBuzz "increment"
        Fizz Fizz Fizz Buzz Buzz Fizz Buzz FizzBuzz "hit var address"
        Buzz Buzz Buzz "retrieve"
        Fizz Fizz Fizz Buzz FizzBuzz "push 1"
        Buzz Fizz Fizz Fizz "hit var ++"
        Fizz Fizz Fizz Buzz Buzz Fizz Buzz FizzBuzz "hit var address"
        Fizz FizzBuzz Buzz "swap to store"
        Buzz Buzz Fizz "store hit var"

    FizzBuzz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz Buzz FizzBuzz "end label"
FizzBuzz Buzz FizzBuzz "end sub"
FizzBuzz Fizz Fizz Fizz Fizz Fizz Fizz Fizz Fizz Fizz FizzBuzz "end define"
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Fizz Buzz Fizz FizzBuzz "addr of judge_hit"
    Fizz Fizz Fizz Buzz FizzBuzz "push 1"
Buzz Buzz Fizz "defined"

# define judge_blow sub routine.
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Buzz Fizz FizzBuzz "addr of sub judge_blow"
Fizz Fizz Fizz Fizz FizzBuzz "push 0"
Buzz Buzz Fizz "regster function addr"
FizzBuzz Fizz Fizz Fizz Fizz Fizz Fizz Fizz Buzz FizzBuzz "sub judge_blow"
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Buzz Fizz FizzBuzz "addr of judge_blow"
    Buzz Buzz Buzz
    FizzBuzz Buzz Fizz Fizz Fizz Fizz Fizz Fizz Fizz Buzz Fizz FizzBuzz "jump to end define"
    Buzz Fizz Fizz Buzz "num - user input"

    FizzBuzz Buzz Fizz Buzz Fizz Fizz Fizz Fizz Fizz Fizz Buzz FizzBuzz "jump to increment blow var"
    FizzBuzz Fizz FizzBuzz Buzz Fizz Fizz Fizz Fizz Fizz Buzz Buzz FizzBuzz "jump to end"
    FizzBuzz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz Fizz Buzz FizzBuzz "increment"
        Fizz Fizz Fizz Buzz Buzz Buzz Fizz FizzBuzz "blow var address"
        Buzz Buzz Buzz "retrieve"
        Fizz Fizz Fizz Buzz FizzBuzz "push 1"
        Buzz Fizz Fizz Fizz "blow var ++"
        Fizz Fizz Fizz Buzz Buzz Buzz Fizz FizzBuzz "blow var address"
        Fizz FizzBuzz Buzz "swap to store"
        Buzz Buzz Fizz "store blow var"

    FizzBuzz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz Buzz Buzz FizzBuzz "end label"
FizzBuzz Buzz FizzBuzz "end sub"
FizzBuzz Fizz Fizz Fizz Fizz Fizz Fizz Fizz Fizz Buzz Fizz FizzBuzz "end define"
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Buzz Fizz FizzBuzz "addr of judge_hit"
    Fizz Fizz Fizz Buzz FizzBuzz "push 1"
Buzz Buzz Fizz "defined"

# message "Enter the 1st number."
Fizz Fizz Fizz Fizz FizzBuzz "push 0"
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Buzz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Buzz Fizz Buzz FizzBuzz
FizzBuzz Fizz Buzz Fizz Buzz FizzBuzz "print"

# read the 1st number
Fizz Fizz Fizz Buzz FizzBuzz
Buzz FizzBuzz Buzz Buzz


# message "Enter the 2nd number."

Fizz Fizz Fizz Fizz FizzBuzz "push 0"
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Buzz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Buzz Fizz Buzz FizzBuzz

FizzBuzz Fizz Buzz Fizz Buzz FizzBuzz "print"

# read the 2nd number
Fizz Fizz Fizz Buzz Fizz FizzBuzz
Buzz FizzBuzz Buzz Buzz


# message "Enter the 3rd number."

Fizz Fizz Fizz Fizz FizzBuzz "push 0"
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Buzz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Buzz Fizz Buzz FizzBuzz


FizzBuzz Fizz Buzz Fizz Buzz FizzBuzz "print"

# read the 3rd number
Fizz Fizz Fizz Buzz Buzz FizzBuzz
Buzz FizzBuzz Buzz Buzz


FizzBuzz Fizz Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Buzz FizzBuzz " game loop"
    # init hit variable
    Fizz Fizz Fizz Buzz Buzz Fizz Buzz FizzBuzz
    Fizz Fizz Fizz Fizz FizzBuzz
    Buzz Buzz Fizz
    # init blow variable
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz FizzBuzz
    Fizz Fizz Fizz Fizz FizzBuzz
    Buzz Buzz Fizz

    # message "Guess the 1st number"
    Fizz Fizz Fizz Fizz FizzBuzz "push 0"
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Fizz Buzz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Buzz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Buzz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Buzz Buzz Buzz FizzBuzz

    FizzBuzz Fizz Buzz Fizz Buzz FizzBuzz "print"

    # read the 1st number
    Fizz Fizz Fizz Buzz Fizz Fizz FizzBuzz
    Buzz FizzBuzz Buzz Buzz


    # message "Guess the 2nd number"
    Fizz Fizz Fizz Fizz FizzBuzz "push 0"
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Fizz Buzz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Buzz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Buzz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Buzz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Buzz Buzz Buzz FizzBuzz
    FizzBuzz Fizz Buzz Fizz Buzz FizzBuzz "print"

    # read the 2nd number
    Fizz Fizz Fizz Buzz Buzz Fizz FizzBuzz
    Buzz FizzBuzz Buzz Buzz

    # message "Guess the 3rd number"
    Fizz Fizz Fizz Fizz FizzBuzz "push 0"
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Fizz Buzz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Buzz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Buzz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Fizz Buzz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Buzz Buzz Buzz FizzBuzz
    FizzBuzz Fizz Buzz Fizz Buzz FizzBuzz "print"

    # read the 3rd number
    Fizz Fizz Fizz Buzz Buzz Buzz FizzBuzz
    Buzz FizzBuzz Buzz Buzz

    ########## judge hit #########

    # was 1st input hit?
    Fizz Fizz Fizz Fizz Buzz FizzBuzz "push 1st num address"
    Buzz Buzz Buzz "push 1st num"
    Fizz Fizz Fizz Buzz Fizz Fizz FizzBuzz "push 1st user input address"
    Buzz Buzz Buzz "push 1st num"
    FizzBuzz Fizz Buzz Fizz Fizz Fizz Fizz Fizz FizzBuzz "judge_hit"

    # was 2nd input hit?
    Fizz Fizz Fizz Buzz Fizz FizzBuzz "push 2nd num address"
    Buzz Buzz Buzz "push"
    Fizz Fizz Fizz Buzz Buzz Fizz FizzBuzz "push 2nd user input address"
    Buzz Buzz Buzz "push"
    FizzBuzz Fizz Buzz Fizz Fizz Fizz Fizz Fizz FizzBuzz "judge_hit"

    # was 3rd input hit?
    Fizz Fizz Fizz Buzz Buzz FizzBuzz "push 3rd num address"
    Buzz Buzz Buzz "push 3rd num"
    Fizz Fizz Fizz Buzz Buzz Buzz FizzBuzz "push 3rd user input address"
    Buzz Buzz Buzz "push 3rd num"
    FizzBuzz Fizz Buzz Fizz Fizz Fizz Fizz Fizz FizzBuzz "judge_hit"


    ########## judge blow #########

    # was 1st input blow?

    Fizz Fizz Fizz Buzz Fizz FizzBuzz "push 2nd num address"
    Buzz Buzz Buzz "push"
    Fizz Fizz Fizz Buzz Fizz Fizz FizzBuzz "push 1st user input address"
    Buzz Buzz Buzz "push"
    FizzBuzz Fizz Buzz Fizz Fizz Fizz Fizz Fizz Buzz FizzBuzz "judge_blow"

    Fizz Fizz Fizz Buzz Buzz FizzBuzz "push 3rd num address"
    Buzz Buzz Buzz "push"
    Fizz Fizz Fizz Buzz Fizz Fizz FizzBuzz "push 1st user input address"
    Buzz Buzz Buzz "push"
    FizzBuzz Fizz Buzz Fizz Fizz Fizz Fizz Fizz Buzz FizzBuzz "judge_blow"

    # was 2nd input blow?
    Fizz Fizz Fizz Fizz Buzz FizzBuzz "push 1st num address"
    Buzz Buzz Buzz "push"
    Fizz Fizz Fizz Buzz Buzz Fizz FizzBuzz "push 2nd user input address"
    Buzz Buzz Buzz "push"
    FizzBuzz Fizz Buzz Fizz Fizz Fizz Fizz Fizz Buzz FizzBuzz "judge_blow"

    Fizz Fizz Fizz Buzz Buzz FizzBuzz "push 3rd num address"
    Buzz Buzz Buzz "push"
    Fizz Fizz Fizz Buzz Buzz Fizz FizzBuzz "push 2nd user input address"
    Buzz Buzz Buzz "push"
    FizzBuzz Fizz Buzz Fizz Fizz Fizz Fizz Fizz Buzz FizzBuzz "judge_blow"

    # was 3rd input blow?
    Fizz Fizz Fizz Fizz Buzz FizzBuzz "push 1st num address"
    Buzz Buzz Buzz "push"
    Fizz Fizz Fizz Buzz Buzz Buzz FizzBuzz "push 3rd user input address"
    Buzz Buzz Buzz "push"
    FizzBuzz Fizz Buzz Fizz Fizz Fizz Fizz Fizz Buzz FizzBuzz "judge_blow"

    Fizz Fizz Fizz Buzz Fizz FizzBuzz "push 2nd num address"
    Buzz Buzz Buzz "push"
    Fizz Fizz Fizz Buzz Buzz Buzz FizzBuzz "push 3rd user input address"
    Buzz Buzz Buzz "push"
    FizzBuzz Fizz Buzz Fizz Fizz Fizz Fizz Fizz Buzz FizzBuzz "judge_blow"

    #cleared?
    Fizz Fizz Fizz Buzz Buzz Fizz Buzz FizzBuzz "hit var address"
    Buzz Buzz Buzz "retrieve"
    Fizz Fizz Fizz Buzz Buzz FizzBuzz "push 3"
    Buzz Fizz Fizz Buzz "hit - 3"
    FizzBuzz Buzz Fizz  Buzz Buzz Buzz FizzBuzz "jump to end if 0"
    # not cleared
    Fizz Fizz Fizz Buzz Buzz Fizz Buzz FizzBuzz "hit var address"
    Buzz Buzz Buzz "retrieve"
    Buzz FizzBuzz Fizz Buzz "show hit num"
    Fizz Fizz Fizz Fizz FizzBuzz "push 0"
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Buzz Fizz Fizz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Buzz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz FizzBuzz
    FizzBuzz Fizz Buzz Fizz Buzz FizzBuzz "print"

    Fizz Fizz Fizz Buzz Buzz Buzz Fizz FizzBuzz "blow var address"
    Buzz Buzz Buzz "retrieve"
    Buzz FizzBuzz Fizz Buzz "show blow num"


    Fizz Fizz Fizz Fizz FizzBuzz "push 0"
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Buzz Fizz Buzz Buzz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Buzz Buzz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Buzz Buzz Fizz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Fizz Buzz Fizz  FizzBuzz
    Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Fizz FizzBuzz
    FizzBuzz Fizz Buzz Fizz Buzz FizzBuzz "print"


    Fizz Fizz Fizz Buzz Fizz Buzz Fizz FizzBuzz "\n"
    Buzz FizzBuzz Fizz Fizz

    FizzBuzz Fizz FizzBuzz Fizz Fizz Buzz Buzz Fizz Fizz Buzz Buzz FizzBuzz "back to loop start"


FizzBuzz Fizz Fizz Buzz Buzz Buzz FizzBuzz

Fizz Fizz Fizz Fizz FizzBuzz "push 0"
Fizz Fizz Fizz Buzz Fizz Buzz Fizz  FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Fizz Fizz Buzz  FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Buzz Fizz Buzz Buzz FizzBuzz
Fizz Fizz Fizz Buzz Fizz Fizz Buzz Buzz Buzz Buzz FizzBuzz
FizzBuzz Fizz Buzz Fizz Buzz FizzBuzz "print"
FizzBuzz FizzBuzz FizzBuzz

そういえばbrainfuckでヒットアンドブロー(数当てゲームだね)書いてた人がいたなあと思って、書いてみた。

このプログラムの肝は各関数の定義にある。よく見てみれば、三つの関数すべてに以下のような構造が確認できるはずだ。

# define print sub routine.
Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz FizzBuzz "addr of sub print"
Fizz Fizz Fizz Fizz FizzBuzz "push 0"
Buzz Buzz Fizz "regster function addr"
FizzBuzz Fizz Fizz Fizz Buzz FizzBuzz "sub print"
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz FizzBuzz "addr of sub print"
    Buzz Buzz Buzz
    FizzBuzz Buzz Fizz Fizz Buzz Fizz Fizz FizzBuzz "jump to end define"
    # 関数本体
FizzBuzz Buzz FizzBuzz "end sub"
FizzBuzz Fizz Fizz Fizz Buzz Fizz Fizz FizzBuzz "end define"
    Fizz Fizz Fizz Buzz Buzz Fizz Fizz Buzz FizzBuzz "addr of sub print"
    Fizz Fizz Fizz Buzz FizzBuzz "push 1"
Buzz Buzz Fizz "defined"

これが何かと言うとだな、whitespaceはトークンを一つ一つ見ていきながら動作するわけだ。つまり、関数をプログラムのメイン処理の前方で書いた場合、ありもしないスタックから値を得ようとして実行時エラーという事になってしまうわけだ。となると関数定義が終わってメイン処理が走るまでは関数本体は実行せず、しかしメイン処理に差し掛かった後は動作するようなトリックが必要になる。

そのため、まずはヒープに関数と対応する変数を確保し、それを状態変数として扱う事にした。上記のコードを解説すると、まず“Fizz Buzz Buzz Fizz Fizz Buzz”というアドレス(2進表記で11001)に0を確保し、これで関数定義の前処理を終える。関数の頭ではそのアドレスの値をチェックして、0であれば関数終了部分(end subのラベル)の後ろの特殊なブロックに飛び、そこで先のアドレスの先に1を書き込む。こうすることで、最初に関数定義に差し掛かった時は本体を実行せず、後に呼び出されたときは関数終了後の特殊処理は呼ばれる事がないという処理を実現できるわけだ。これはwhitespaceでメイン処理の前に関数を書きたくなったときのイディオムとして覚えておきたい。

あとは特筆すべき事はない。ただし、このプログラムは問題を手入力するのだが、その時妙な値を入れるとあっさりと落ちる。そんな入力値チェックなんぞしていないのでね。

割と真面目な話 

この手のEsolang(奇妙な言語)の多くは単に文法がイカれているだけなのだが、このwhitespaceはよくよく見てみると案外まともな作りになっている。例えば現時点で最新のwhitespace 0.3の仕様のうち、スタック操作だけを抜粋すると:

コマンド 引数 動作
[Space]数値 スタックのトップに<数値>をプッシュ
[LF][Space] スタックトップの要素を複製する
[Tab][Space]数値スタックの<数値>番目の要素をスタックのトップにコピーする
[LF][Tab] スタックのトップの値2つを入れ替える
[LF][LF] スタックトップの要素を捨てる
[Tab][LF] 数値 スタックトップの要素を残したまま、<数値>個の要素を廃棄する

これをもうちょっとコマンドをわかりやすく書き換えてみると:

コマンド 引数 動作
push 数値 スタックのトップに<数値>をプッシュ
dup スタックトップの要素を複製する
copy 数値スタックの<数値>番目の要素をスタックのトップにコピーする
swap スタックのトップの値2つを入れ替える
pop スタックトップの要素を捨てる
slide 数値 スタックトップの要素を残したまま、<数値>個の要素を廃棄する

案外普通のスタックマシンに見えないかな。俺のはお遊び目的なので意図的にトークンを1文字ずつ読み込んで行くタイプに実装したのだけど、実際には上記のようなコマンドを実装したインタープリタを作り、whitepsaceのコードを読み込んでそれに対するオブジェクトコードを吐き出すコンパイラを別途作るという方が筋としては良い。

インタープリタ自体はぶっちゃけこんな感じのテキストを読み込んでいくものでも習作なんだから全然構わないと思う。(以下はHello, world.のFizzBuzzコードを書き直したもの)

push 0
push 10
push 46
push 64
push 114
push 108
push 111
push 119
push 32
push 44
push 111
push 108
push 108
push 101
push 72
label 10
dup
jump-if-zero 01
put-char
jump 10
label 01
pop
end

もうちょっと高級な構文の言語を考え、そこから上記のwhitespaceインタープリタ用のオブジェクトコードを吐き出すコンパイラというのも面白いかも知れない。なんちゃって関数定義のヒントになるものは既に俺が提示してあるので、それをベースに考えれば関数定義、ループ、分岐あたりの構造を持った言語は作れるはず。Hello, Worldの例だと、

print "Hello, world."

というコードから、

  1. スタックに0を積む。
  2. スタックに10を積む。(改行コード)
  3. ""内部の値を逆順にスタックにプッシュして行く。
  4. ...

というコードを吐き出せれば、それでOKなはずだし。

俺はもうヒットアンドブローで力尽きたので、誰か以下のお題にチャレンジしてくれないかな。

どっちかっていうと後者の方が面白いと思うので、まずはインタープリタを作って、それの実験としてFizzBuzzを書いてみるのもいいかもしれない。

更新履歴 

2012-08-09
コンテンツの整理のついでにリファイン
2011-04-01
公開