LoginSignup
21
9

More than 5 years have passed since last update.

Forthについてのメモ書き

Last updated at Posted at 2017-12-18

本記事は
言語実装 Advent Calendar 2017
19日目向けの投稿です。

gyaboと申します。どうも学術よりのカレンダーだったようで、とても緊張しています。

Forthについて少し勉強したので書きます。
ついでにお試し処理系をC/C++言語で書きます。

Forthをご存知ですか?

Forth forth, FORTH
※どう書いてもいいらしいです。

兎に角、早速簡単にForthを使ってみましょう。

Forth はスタック指向であり逆ポーランド記法(RPN)

ex) 1 + 2を計算してprintf(印字)してください

[Forthで書くと]

1 2 + .

説明します。Forthはスタックを持っています。いろいろなものを積めます。
スタックの状態を以下に図示します。

※\は行末までコメントの意味。

1   \ 1  1をスタックに積む。
1 2 \ 2  2をスタックに積む。
3   \ +  +を計算する
    \ .  3 と出力される。. によってスタックの値は取り出されて空っぽになる

ex) HelloWorldしてください

すいません、わざとサブルーチン使います。

[Forthで書くと]

: HELLO ." HelloWorld"  CR ;
HELLO

意味を同様にコメントで書いていきます。

: \ サブルーチン宣言開始。次の"ワード"(後述)はサブルーチンの名前

." \ 文字列出力

HelloWorld" \ 文字列自身

CR \ printf("\n");

; \ サブルーチン宣言終了。"ディクショナリ"(後述)に登録される

HELLO \ サブルーチン呼び出し

サブルーチンも定義できるんですね。

こんな感じで、あらゆるメモリ操作、やりたいことのために、一時的に何かしらの保存領域としてスタックを使ったり、
どこかの関数やサブルーチンに値を受け渡しするときにスタックの仕掛けを使います。
もちろん分岐時の評価にもスタックを使います。
Forth自身の組み込み関数がスタックを使わないなら、スタックを通さなくても良くなる認識で、
いろんな処理系があるようです。

ex)1 + 2の結果を2回printfしてください
スタックのコピーを使います。

1 2 + DUP . .

. (印字)はスタックを破棄するので、事前にduplicate(DUP)します。

その他、単に生メモリにアクセスしたりなどもあったりします。足りない処理はとにかく自分で書きます。

Forthの文献で出てくるキーワード

スタック(stack)
計算するためのスタック。あらゆる計算はスタックで行われます。

ワード(word, words)
Forthが解釈する何かしらの最小単位です。

ディクショナリ(dictionary)
組み込み処理だったり登録したサブルーチン処理が登録されているところです。
ワードをディクショナリから検索して、登録されてたらそれを評価し、その繰り返しがForthの処理の基本です。

魅力 シンプル

勉強してて面白かったのは、Forthの処理系はとても小さいものが多く、またForthは明確な文法が存在しないようです。

魅力 シンプルなのでお試し実装が大量にあって勉強になる

※参考文献参照。pythonでのForth実装とか一杯あります。

魅力 Forthの処理系がやってることがシンプル

Wikipediaを抜粋してかみ砕くと、Forthがやってることは以下の通りです。

1) インタプリタはユーザ入力デバイス(この場合ファイルでも何かしらのメモリ領域でも何でもいい)から入力された行を読み

2) それから区切り文字としての空白を使って単語に構文解析される

3) インタプリタがワードを見つけると、ディクショナリ (dictionary) からそのワードの検索を試みる

4) もしそのワードが見つかれば、インタプリタはワードに関連付けられたコードを実行

5) もしワードを発見することができないなら、ワードを数だと仮定して数値への変換を試み、それをスタックにプッシュ

6) 変換が成功していれば、インタプリタは入力システムからの構文解析を継続する

7) 辞書の参照と数値への変換の両方が失敗した場合、インタプリタはそのワードが認識できないというエラーメッセージを出す

これを書くとForthのサブセットが完成するようです。

サブセットを実装してみた

なんというか手が完璧になまってたので、サブセットを実装しました。

tf.cpp
https://gist.github.com/kumaashi/6d4c83b635fdd996fd67bb8f887bec43

VC2015 64bitで動作確認しています。

以下にあるような見慣れないのはサポートしていません。

http://wiki.laptop.org/go/Forth_stack_operators
entryuserprimであとはひたすら拡張していくだけ、という認識です。
※ほんまかいな

付録 スレッデッドコード

Wikipediaによると、スレッデッドコード(英: threaded code)は、
プログラミング言語処理系におけるコード生成手法のひとつで
呼出すべきサブルーチンのアドレスを羅列する、というものです。
いろいろスレッデッドコードの手法があるようですが、Wikipediaのサンプルコードがよくできていたので解説します。
(少し変形)

thread:  ;実行すべき命令列
  &pushA
  &pushB
  &add
  ...

; ↓ここから実行開始

start:
  ip = &thread ;ipってレジスタにthreadのアドレスを格納
top:
  jump *ip++   ;pushAにジャンプしてipを次に進める


pushA:         ;Aをスタックに積んでくれるサブルーチン
  *sp++ = A    ;Aをスタックに積む
  jump top     ;topに強制ジャンプ

pushB:         ;Aをスタックに積んでくれるサブルーチン
  *sp++ = B    ;Bをスタックに積む
  jump top     ;topに強制ジャンプ

add:           ;スタックのトップとトップ-1を足してスタックに積む
  *sp++ = *--sp + *--sp
  jump top

参考文献

◆Wikipedia Forth
https://ja.wikipedia.org/wiki/Forth

◆FORTH の情報まとめてみた 2016 年版
https://qiita.com/ryos36/items/d2d50f9803cddd091905

◆6 行の Lua プログラムで、Forth の内部インタプリタを作る
https://qiita.com/iigura/items/855954ad000fe1da6c59

◆西尾泰和のはてなダイアリー : 最小限Forth + ワード定義機能付きForth
http://d.hatena.ne.jp/nishiohirokazu/20110401/1301667130

◆Forthを作るのじゃ | TECHSCORE BLOG
http://www.techscore.com/blog/2014/01/28/forth%E3%82%92%E4%BD%9C%E3%82%8B%E3%81%AE%E3%81%98%E3%82%83/

◆Wikipedia : スレッデッドコード
https://ja.wikipedia.org/wiki/%E3%82%B9%E3%83%AC%E3%83%83%E3%83%87%E3%83%83%E3%83%89%E3%82%B3%E3%83%BC%E3%83%89

◆[Factor] LOL -> FORTH -> Factor に出会う
http://basicwerk.com/blog/archives/1619

終わりに

FactorというFORTHの後釜的な処理系があるようです。
遊んだことがないので、今度遊んでみようと思います。
間違いなどあったら指摘ください。

以上です。
Let's enjoy FORTH!

21
9
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
9