Hello, Forth World!!

はい。今日も新たな言語に挑戦してみます。前回は、s kだけで全部出来ちゃうよ〜という純粋関数型言語Unlambdaでしたが、今回はもうちょっと高級に攻めてみたいと思います。

今日の言語はForth。噂によると相当早い言語らしい。なんか聞いたことがあったけど、どんな言語かは知らなかったので謎を追っていきます。処理系はgforthを使います。

Hello, Forth World!!

とりあえず、Hello, world。

." Hello, Forth World!!"
Hello, Forth World!! ok

ドットでprint。文字列の場合は、ドットと文字列の間はスペースは開けちゃダメらしい。

Hello, worldは謎が多いので次へ行きます。

(追記:突っ込みを頂きました。 ." という関数みたい。)

足し算

高級過ぎたので、もうちょっと低レベルに足し算行きます。

1 1 +

なんか見たことあるなぁ。と思ったら正解。.は表示なので、

1 1 + .
2

で、表示出来ます。

Forthは単なるスタック型言語でした。逆ポーランド電卓の高級な奴。

しかし、逆ポーランド電卓に少し毛が生えた感じじゃない。「もっさり」毛が生えてる。順を追って見ていこう。

スタック操作

スタックの中を除きましょう。

1 2 .s
<2> 1 2  ok

<2>はスタックの詰まれた数。

取り出すときは、

1 2 3 . . .
3 2 1  ok

1を積んで、2を積んで、3を積んで、3を取り出して表示、2を取り出して表示、1を取り出して表示。

うぅん。簡単!!


スタックを捨てるdrop

1 drop .s
<0>  ok


スタックのコピーdup

1 .s dup .s
<1> 1 <2> 1 1  ok


一個飛び越えてコピーover

1 2 .s over .s
<2> 1 2 <3> 1 2 1  ok

おもろい。


入れ替えるswap。

.s swap .s
<2> 1 2 <2> 2 1  ok


スタック3つをローテーション

.s rot .s
<3> 1 2 3 <3> 2 3 1  ok

楽しい。まだまだいっぱいあるみたい。


さすがスタック型言語です。充実っぷりはリスト並です。

dropコマンドの繰り返し

こらすげぇ。

1 2 3 2drop  ok
.s <1> 1  ok

viっぽくてステキです。

四則演算

計算。

1 2 + .     3  ok
3 4 - .     -1  ok
5 6 * .     30  ok
7 8 / .     0  ok
9 10 mod .  9  ok

符合つき整数みたい。

続けて計算。

1 2 + 3 4 + * .
21

いち と に を たして さん と よん を たして かける。 ひょうじ。

Forthは日本語で読めます。スタック思考な日本人的には最適な言語かも。

コメント

プログラムにはコメントを。

1 1 + \ 足し算します。
( これもコメント )

\と括弧がコメントっす。Forthには括弧が要らないので、コメントに使っちゃうみたい。Lisper的にはありえないっす!!

文字列

文字列は、s" Hello"らしい。

s" Hello" .s
<2> 147052888 5

文字長と、ポインタをスタックに積んでる。Java系の文字格納法らしい。JavaVMはForthを参考に作ったらしいので、なんとなく納得した。

表示方法は後ほど・・・。

関数

というかマクロに近い。

: square ( n -- n^2 )
  dup * ;

括弧の中はコメントなので、激しく無意味だけど、慣習的にこうするらしい。実体は、

: square dup * ;

こうなって、

2 square .
4

ははぁん。

see

デコンパイル出来る。

see square
: square
  dup * ;

組込みは、

Code +
( $804E346 )  mov     dword ptr 805E480 , ebp  \ $89 $2D $80 $E4 $5 $8
( $804E34C )  lea     eax , dword ptr 4 [edi]  \ $8D $47 $4
( $804E34F )  mov     edx , dword ptr [edi]  \ $8B $17
( $804E351 )  add     ebp , # 4  \ $83 $C5 $4
( $804E354 )  add     dword ptr [eax] , edx  \ $1 $10
( $804E356 )  mov     edi , eax  \ $89 $C7
( $804E358 )  mov     ecx , dword ptr FC [ebp]  \ $8B $4D $FC
( $804E35B )  jmp     ecx  \ $FF $E1
end-code

ほぉぉぉぉぉぉ。

ローカル変数付き関数

{}はかなり高級。「ローカル変数が持てる」凄いっす。

: swap { a b -- b a }
  b a ;

本物っぽい関数に出来る。どうなってんだ。

: square { a -- a^2 }
  a dup * ;

後ろのは相変わらずコメント。

どうなってるのかわからん。

seeしてみる。

see square
: square
  >l lp- @local1 dup * lp+ ;

{}にすると。Cのローカル変数みたいな感じになるらしい。アセンブラよりは断然楽。

if

激しく読みづらいけどもちろんifもある。

: abs ( n1 -- +n2 )
    dup 0 < if
        negate
    endif ;

アセンブラと同じ順。比較して、ジャンプ。アセンブラに毛が生えた程度。

比較はこんな感じ。

1 2 < .
-1  ok
2 1 <
. 0  ok

trueだと-1,falseだと0。何故-1なのか微妙な所だけど、ダンプしたときにフラグが全部立ってた方が見やすいとか。そんな感じかも。

elseもある。elseifは無いかも。

ガーン

書いたのに、消えてしまったorz

ま、Forthには、構造体やらクラスまであって、ただの逆ポーランド言語じゃない。

gforthのマニュアルは、Gforth Manualにあるので、ガッツリよんでくれぃ〜。