はじめに
こんにちは。バグ太郎です。タイトルの通り、今回は興味本位で調べたForthについて記事にしてみたいと思います。
Forthの主な特徴は手続き型でスタック指向、コードの記述に後置記法を用いる点です。
特徴
後置記法
後置記法は逆ポーランド記法とも言います。「1 + 2」という式(中置記法)を例とすると、後置記法では「1 2 +」と表現します。
後置記法は日本語の文法と似ている。と評されますが、
「1 2 +」を「1と2を足す」と読むことができる為です。
まあ、日本語と文法が似ていること自体はForthにおいて特に利点にはなりません。
日本において「1 + 2」という式でも普通に「1足す2」で通じますし。
日本語の文法そのままに日本語で記述できるMindというForthベースの言語もありますが、
Forthにおいて後置記法を採用しているのは「コンピュータで利用するのに適した形にしたかったから」と、単純に考えてよいかと思います。
スタック指向
Forthのデータ構造はスタックです。後置記法と組み合わせることで明確なデータスタックを用いることができます。
「1 2 +」の場合、1を積み、2を積み、2値を取り出して、結果を積みます。
気をつけることといえば、pushとpopしたときのスタックポインタの移動する方向でしょうか。
スタックなので当たり前ですが「1 2」と積んだ場合「2 1」という順番で取り出します。
手続き型
Forthは複数の命令を組み合わせて、実行する一連のステップを記述します。中置記法は演算子が数字の間に入るので「1+2」と書くことができますが、
後置記法は数字が続くために「12+」と空白を除いて書くことができません。
Forthにおいて各命令のデリミタには空白を用いるため、違和感なく「1 2 +」と同様の記述ができます。
実装してみると分かるのですが、適当なとこで改行しないと書いたコードを読み返したくはないです。
しかし命令ごとに改行すると過剰になって、無駄に縦に長くなります。
実行
Forthの環境はコンパイラとシェルが混ざったような感じです。一時的に実行を試すための環境が欲しい方はWebサービスを探してみるとよいかもしれません。
Forthはコンパイルしなくても基本的な命令は対話形式でそのまま実行できます。
もちろんサブルーチン(Forthではwordsという)を定義し、それを対話形式で呼び出すこともできます。
「1 2 +」の結果を出力
# 1 2 + .
定義するときは以下のような形で記述します。
wordsの定義
: ワード名 文 ;
ためしにFizzbuzzなるものを実装してみました。
最初は思い描いた平凡なフロー通りに書いて無駄が多かったのですが、スタック指向を理解するにつれ変形させていくのが楽しかったです。
みなさんも試しに実行してみてはいかがでしょうか。私が使用した主なワードは以下の通りです。
ちなみに、繰り返しなどの一部制御文を使用する場合はコンパイルが必要になるようです。
・dup
値をpopして複製してpushする。
・mod
剰余算を行う
・if - then:if 文 [else 文 ]then
分岐処理を行う。Forthにおいて0以外は真の扱いらしい。thenはendifでもよい。
・.(ピリオド)
値をpopして出力する。文字列を出力する場合は." XXX"と記述する。
・cr
改行を行う。
・do - loop: 終了値 開始値 do 文 loop
100 1 do なら1から99までくり返す。iと記載すると現在値がpushされる
以下が私が実装したものになります。"最大値 fizzbuzz"と打ち込んで実行します。
0=を使用しているのはorは使えたのになぜかnorやnotが使用できなかったためです。
私が考えたForthのFizzbuzz
: fizzbuzz
cr
1 + 1 do
i 5 mod 0= i 3 mod 0= 2dup or 0=
if i . then if ." Fizz" then if ." Buzz" then
cr
loop
;
意味単位で成型すればこんな感じ?
: fizzbuzz
cr
1 + 1 do
i 5 mod 0=
i 3 mod 0=
2dup or 0=
if i . then
if ." Fizz" then
if ." Buzz" then
cr
loop
;
Forthを使う機会があるかは別として、普段触れない指向を学んでみるのも面白いのではないでしょうか。