Forth
はじめに

Forthは、チャールズ・ムーアによって1970年に開発された、非常にユニークなプログラミング言語です。Forthは、プログラミング言語の概念を根本から見直し、シンプルさと効率性を追求した結果生まれました。
はじめに

Forthの最大の特徴は、スタックベースのプログラミングモデルと、インタープリタ方式による対話型の実行環境にあります。プログラムは、「ワード」と呼ばれる小さな命令の集合として定義されます。これらのワードは、スタックを介して通信を行います。つまり、ワードの入力と出力は全てスタックを経由するのです。
はじめに

このアプローチは、プログラムをモジュール化するのに非常に適しています。ワードは個別に定義され、組み合わせて新しいワードを構築できます。このような構造は、プログラムの拡張性と再利用性を高めます。また、Forthのコアシステムは非常にコンパクトで、数千行のコードからなるため、カスタマイズや移植が容易です。
はじめに

Forthは、組み込みシステムや制御システム、科学技術計算などの分野で幅広く利用されてきました。NASAのスペースシャトルやボーイング航空機の飛行制御システムなどでも採用されており、その信頼性の高さが評価されています。また、オープンソースのForth処理系も多数存在し、活発なコミュニティが形成されています。
はじめに

本書では、ForthのCore Word Setに準拠した標準的なForthシステムを題材とします。Forthの文法と概念から始まり、データ構造、メモリ管理、入出力、モジュール化、さらには応用的なトピックまでを解説します。サンプルコードと実践的なプロジェクトを通じて、Forthの実用性と可能性を体感していただけます。
はじめに

シンプルでありながら極めて表現力豊かなForthの世界に足を踏み入れ、その魅力を存分に味わってみてください。
Forthの基礎

Forthは一見すると非常にシンプルな構文を持っていますが、その裏には独自の概念と豊かな表現力が隠れています。この章では、Forthの基本的な構文と操作、ワード(関数)の定義方法などを解説します。
Forthの基礎

Forthのプログラムは、空白文字で区切られた「ワード」の並びで構成されます。ワードには、数値リテラル、制御構造、演算子、そして他のワードを呼び出す構文などがあります。Forthには高水準の構文がなく、基本的な構文要素は非常にシンプルです。
Forthの基礎

例えば、2 3 + と入力すると、2と3がスタックにプッシュされ、最後の+がスタック上の2つの数値を加算します。この結果である5がスタックに残ります。つまり、Forthではプログラムの実行とデータ操作が、ワードの解釈とスタック操作によって行われるのです。
Forthの基礎

Forthは、基本的に行指向の言語です。プログラムは複数行に分割できますが、改行の前後で文が継続する場合は、スペースを入れる必要があります。このため、適切なインデントを使ってプログラムの構造をわかりやすくすることが重要です。
Forthの基礎

スタックは、Forthにおける中心的なデータ構造です。ほとんどのワードは、スタックから値を取り出したり、スタックに値を格納したりします。スタックは、後入れ先出し(LIFO; Last In First Out)のデータ構造で、Forthの演算はスタック上で行われます。
Forthの基礎

基本的なスタック操作ワードには、DUP(重複)、SWAP(入れ替え)、DROP(削除)、OVER(コピー)などがあります。これらのワードを使ってスタックを操作し、必要なデータを演算の入力に設定します。
Forthの基礎

Forthには、算術演算(+、-、*、/など)、論理演算(AND、OR、NOT)、比較(=、<>、>、<など)の基本ワードが用意されています。これらのワードは、スタック上の値を取り、演算結果をスタックに格納します。
Forthの基礎

制御構造には、条件分岐(IF、ELSE、THEN)やループ(BEGIN、UNTIL、AGAIN)などがあります。Forthの制御構造は、スタックを活用した独特の動作をします。条件式の値は真理値ではなく、0か非0値で判断されます。
Forthの基礎

このABSSUMワードは、2つの数値の絶対値の和を計算します。IF...THEN構造を使って、数値の符号に応じて絶対値を求めています。
Forthの基礎

Forthでは、新しいワードを定義してカスタマイズすることができます。ユーザー定義ワードは、:(コロン)で始まり、;(セミコロン)で終わります。その間に、既存のワードや制御構造を組み合わせることで、任意の処理を記述できます。
Forthの基礎

SQUAREは数値を2乗する単純なワードです。SUMAは2つの数値の和を求めるワードで、組み込みの+を利用しています。
Forthの基礎

定義の際、ワードの後ろに(と)でスタックの動作を記述するのがForthの慣習です。上の例では、SQUAREは1つの数値を取り、その2乗値をスタックに残します。
Forthの基礎

Forthのユーザー定義ワードは、小さな処理から大きな処理へと階層的に作り上げていくことができます。新しいワードを組み合わせて、さらに高度なワードを構築できる、というのがForthの大きな特徴です。
データ構造とメモリ管理

Forthは組み込みシステムなどのリソース制約の厳しい用途を想定して設計されているため、メモリの効率的な利用が重視されています。この章では、Forthにおけるデータ構造とメモリ管理の方法を説明します。
データ構造とメモリ管理

Forthにおけるメインのデータ構造は、パラメータスタックとリターンスタックの2つです。パラメータスタック(通常は単にスタックと呼ばれる)は、すでに説明した通り、数値やアドレスなどのデータを一時的に保持する役割を持ちます。
データ構造とメモリ管理

一方、リターンスタックは、ワード呼び出しの際にリターンアドレスを保存するために使用されます。ワードの実行が終わると、リターンスタックから次の実行位置がポップされます。この仕組みにより、Forthはスタック指向の構造化プログラミングが実現されています。
データ構造とメモリ管理

スタックとリターンスタックはそれぞれ限られたサイズを持っているため、スタックオーバーフローやアンダーフローを引き起こさないよう注意が必要です。?STACKやDEPTHなどのワードを使えば、スタックの状態をチェックできます。
データ構造とメモリ管理

Forthには、グローバル変数やローカル変数の概念がありません。代わりに、値を格納するためのメモリ領域を確保し、そのアドレスを使ってアクセスします。VARIABLEワードを使うと、新しい変数領域が確保され、その開始アドレスがスタックに置かれます。
データ構造とメモリ管理

変数の値を取り出すには@(フェッチ)、格納するには!(ストア)を使います。+!のように算術演算と!を組み合わせたワードもあります。
データ構造とメモリ管理

Forthではアドレスを直接スタックに置いて操作することもできます。HEREはディクショナリの次の空きアドレスを取得し、ALLOTはディクショナリ領域を確保します。
データ構造とメモリ管理

配列やレコード(構造体)といったデータ構造は、Forthではメモリブロックとしてアドレスで表現されます。配列の各要素にアクセスするには、インデックスとベースアドレスの計算が必要です。
データ構造とメモリ管理

CREATE...ALLOTで連続したメモリ領域を確保し、ARRAYにその開始アドレスが置かれます。要素へのアクセスには、ベースアドレスにインデックスをシフトして足し算します。
データ構造とメモリ管理

レコードは、必要なフィールドごとにメモリを確保して構築できます。レコードのフィールドへのアクセスには、オフセット値を使ってフィールドのアドレスを計算します。
データ構造とメモリ管理

Forthにおけるデータ構造は、非常に低レベルで表現されています。一方で、この低レベルなアクセス方式は、メモリの効率的な利用を可能にし、Forthをシステムプログラミングに適した言語にしています。
入出力と組み込みワード

Forthには標準の入出力ワードがあり、コンソールやファイルからの入出力を行えます。また、様々な組み込みワードが用意されており、これらを活用することでForthの機能を拡張できます。
入出力と組み込みワード

Forthには、キーボードからの文字入力や、コンソールへの文字出力を行うためのワードが用意されています。
入出力と組み込みワード

KEYはキーボード入力を待ち、押された文字のASCIIコードをスタックに置きます。EMITは逆に、スタック上の値を文字コードとして解釈し、コンソールに出力します。." Hello"のように、." の後に文字列を続けると、その文字列がコンソール出力されます。
入出力と組み込みワード

数値入出力には、?、U.、U.Rなどのワードが使えます。?は数値を入力受け付け、U.は符号なし数値を、U.Rは数値を指定した基数(2進数、16進数など)で出力します。
入出力と組み込みワード

ファイル入出力には、様々なワードが用意されています。OPEN-FILEでファイルを開き、READ-FILEやWRITE-FILEでデータの読み書きができます。
入出力と組み込みワード

ファイル名は、S" で文字列をスタックに置いた後、R/O(読み取り専用)やW/O(書き込み専用)といったモードを指定してファイルを開きます。THROWはエラーがあれば例外を発生させます。
入出力と組み込みワード

READ-FILEやWRITE-FILEでは、バッファ領域のアドレスと読み書きするバイト数をスタックに置く必要があります。
入出力と組み込みワード

Forthには、数学関数や論理演算、メモリ操作など、様々な組み込みワードが用意されています。必要に応じてこれらのワードを活用することで、プログラムにさまざまな機能を付加できます。
入出力と組み込みワード

MAXは2つの数値の最大値を、SWAPは2つの値の順序を入れ替え、DROPは最上位の値を捨てます。DUMPは指定したアドレスからのメモリ内容をダンプ出力します。
入出力と組み込みワード

組み込みワードには、浮動小数点演算、文字列処理、マルチタスク、IPCなど、様々な分野のものがあります。また、必要に応じてワードを自作したり、外部ライブラリからリンクしたりできます。Forthはコンパクトなシステムながら、組み込みワードの充実により高い機能性を発揮します。
アプリケーション開発

Forthは小規模な組み込みシステムから大規模なアプリケーションまで、幅広い用途に使用できる言語です。この章では、Forthにおけるアプリケーション開発の手法と、実例について解説します。
アプリケーション開発

Forthはワードをベースとしたモジュール性の高いプログラミングができます。大きなアプリケーションを開発する際は、適切にモジュール分割してワードを設計・管理することが重要です。
アプリケーション開発

Forthにはネームスペースの概念がありません。そのため、ワード名の重複を避けるためには、プレフィックスなどの命名規則を定めることが一般的です。たとえばSTRING-LENGTHのように、ワードの役割がわかるよう名前を付けます。
アプリケーション開発

また、ワードをまとめてファイルに保存し、必要に応じて読み込む方法があります。Forthの多くの処理系は、ワードの定義をソースファイルに保存したり、メモリイメージを永続化したりできます。
アプリケーション開発

作成したワードはMODULE>NAMEでモジュール名を付け、+MODULEでモジュールを完成させることができます。他のソースからUSE MODULE>NAMEとすれば、そのモジュールのワードが使用可能になります。
アプリケーション開発

大規模なシステムでは、このようなソースレベルの分割に加え、オーバーレイ、仮想メモリ、マルチタスク機能を活用することで、メモリの効率的な使用が可能です。
アプリケーション開発

Forthでもグラフィック処理が可能ですが、組み込みの機能は限られています。ほとんどの処理はユーザ定義ワードとして実装する必要があります。
アプリケーション開発

ビットマップ画像の表示や、ウィンドウ、マウスカーソルなどの基本的なGUIの作成はある程度可能です。高度な3Dグラフィックスなどを実現するには、外部ライブラリを利用する必要があります。
アプリケーション開発

上記では、フレームバッファの制御関数がロードされた前提で、DRAW-LINEを使ってDRAW-RECT(長方形描画)を実装しています。スタックを活用して座標値を受け渡し、基本的な幾何図形を描画しています。
アプリケーション開発

Forthはグラフィックスパイプラインなどの高度な機能を組み込んでいませんが、スタックベースの処理により、低レベルのデバイスアクセスが可能です。組み込みシステムのディスプレイやLED制御など、グラフィックス関連の処理に適しています。
アプリケーション開発

Forthの本質的な特性として、システムプログラミングに適していることがあげられます。小規模でコンパクト、高速動作、低レベルなメモリアクセスが可能というメリットがあります。
アプリケーション開発

OSカーネル、デバイスドライバ、BIOS、ブートローダなどの開発にForthは広く使われてきました。組み込みシステムでは、センサーやI/Oデバイスの制御に最適です。スタック指向のモデルにより、レジスタレベルの処理が直接かけるのも特徴です。
アプリケーション開発

例えば、Forthを使ってブートローダを実装する場合には、次のようなプログラムになります。
アプリケーション開発

BIOSなどの低レベル機能を呼び出してブートローダを構築する処理が、Forthの文法でコンパクトに記述できる様子がわかります。
アプリケーション開発

また、Forth自身が小規模で可搬性が高いため、Forth処理系そのものもForthで書かれた簡単なコアを、ホストOSやアーキテクチャに合わせてセルフホスト (移植) する手法が一般的です。これは、アプリケーションと実行環境を一体化して開発できる利点があります。
高度なトピック

ここまでForthの基本的な構文と概念、データ構造、アプリケーション開発の実例などを解説してきました。この章では、Forthの高度な利用方法としてパフォーマンス最適化、マルチスレッド・マルチタスク、メタプログラミングについて取り上げます。
高度なトピック

Forthはコンパクトで高速な言語ですが、さらなる最適化の余地があります。ワードの定義を工夫したり、ネイティブコードコンパイラを使ったりすることで、パフォーマンスを向上できます。
高度なトピック

ワード定義の最適化では、冗長な演算を排除したり、インラインコーディングの手法を用いたりします。例えば、次のようなワード定義があるとします。
高度なトピック

このMAX2は一時的に2つの値を複製(2DUP)し、IF..ELSE..THENの条件分岐で最大値を選びます。しかし、この一時複製が無駄な演算となっています。次のように書くとコードがシンプルになります。
高度なトピック

ワードの最適化には一般的なテクニックがあり、Forthのコンパイラ作者から提案されているものを参考にするとよいでしょう。
高度なトピック

また、Forthにはネイティブコードコンパイラと呼ばれるもので、ワードの実行コードをネイティブマシン語に変換できるものがあります。Forthの対話的な実行環境は便利ですが、ネイティブコードの方が高速に動作します。こうした最適化手法を使い分けることで、Forthのパフォーマンスを飛躍的に向上できます。
高度なトピック

Forthには並列実行の機構が組み込まれていないため、マルチスレッドやマルチタスク処理を実現するにはユーザ定義の実装が必要です。しかし、Forthの言語特性を活かせばきわめてコンパクトな並列処理ができます。
高度なトピック

マルチスレッドでは、スタックを分離し、スレッド毎にスタックのコピーを持つ手法が一般的です。スレッドの切り替えはスタックのコンテキストスイッチで実現できます。また、Forthのデータストアクセス方式を応用すれば、IPC(プロセス間通信)の仕組みを作ることもできます。
高度なトピック

この例では、新しいタスクを作成するワードNEW-TASKを定義しています。CREATE-STACKでスタックを新しく割り当て、DO-SOME-WORKのようなワード定義をタスクとして登録します。実行時にはスケジューラによってこれらのタスクが実行されます。
高度なトピック

マルチタスク機構を実装する例は多数あり、スレッド単位でデータを扱う方式、メッセージキューによる方式、それぞれ長所と短所があります。並列処理にはデッドロックなどの問題点もありますが、Forthではコンパクトでシンプルなコード記述が可能です。
高度なトピック

Forthにはプログラムを生成・変更するメタプログラミングの機能があり、コードを自動生成したり、プログラムを動的に変更したりできます。この機能は、Forthをドメイン固有言語(DSL)の開発などに適用できることを意味しています。
高度なトピック

メタプログラミングには、コンパイル時に評価される構文[...]と実行時構文EVALがあります。どちらもプログラムをデータとして扱えるため、動的にプログラムを生成・変更できます。
高度なトピック

この例では、ヒルベルト曲線を描画するコードを動的に生成しています。POSTPONEはワードのコンパイルを遅延させ、[: ... ;]の構文はその間のテキストを実行可能なコードとしてコンパイルします。この手法により、 Hilbertカーブの次元(n)に応じて、その描画コードを生成しています。
高度なトピック

Forthのメタプログラミング機能は、高度な用途に役立ちます。例えば、ユーザインターフェースビルダー、コードジェネレーター、プログラムシンセサイザなどでその力を発揮できます。Forthの柔軟性を最大限に活かせる側面といえるでしょう。
サンプルプログラムとプロジェクト

Forthの理解を深めるには、実際にコードを書いて動作を確認することが大切です。この章では、様々なサンプルコードを紹介するとともに、実践的なForthプロジェクトの例を示します。
サンプルプログラムとプロジェクト

以下はForthの基本的な機能を示すサンプルコード集です。
サンプルプログラムとプロジェクト

これらの例は、スタックを使った処理の流れ、ユーザ定義ワードの作成、再帰など、Forthのプログラミング手法の基本を示しています。コンパクトながらも表現力の高さがわかるでしょう。
サンプルプログラムとプロジェクト

次に、もう少し大がかりなForthプロジェクトの例を紹介します。
サンプルプログラムとプロジェクト

Chip-8はレトロなゲームコンソールで、Forthでその命令セットをエミュレートするプロジェクトです。グラフィックス、入力処理、命令デコーダなどを実装します。
サンプルプログラムとプロジェクト

ForthでOSカーネルの基本部分を実装し、ブートローダと合わせてシステムを構築するプロジェクト。メモリ管理、タスク管理、ファイルシステム、ドライバなどの機能が実装できます。
サンプルプログラムとプロジェクト

ForthでHTTPリクエストを処理するWebサーバーを作成。ソケット通信、文字列処理、ファイル入出力などの機能が必要になります。追加してWebアプリケーションフレームワークなども作れます。
サンプルプログラムとプロジェクト

Forthを使ってCPU命令セットを記述し、ゲートレベルまでFPGAに実装するプロセッサの設計プロジェクト。ハードウェア記述言語との連携が重要です。
サンプルプログラムとプロジェクト

このようなプロジェクトを通して、Forthの実用性とシステムプログラミングでの可能性を体験できます。Forthという言語自体を使って、OSやハードウェアコンポーネントを実装できるのが最大の特徴です。いずれのプロジェクトも一般的な規模になると、モジュール分割やワード管理、ツール活用などの工夫が必要になります。
参考資料

Forthについてより深く学ぶには、書籍や公開されているオンラインリソースを参照するのが有効な方法です。また、活発なForthコミュニティに参加することで、他の開発者からの助言を得られます。
参考資料

Forthの入門書から応用、さらには処理系の実装に至るまで、多くの優れた書籍が出版されています。
参考資料

これらの書籍を手に入れられれば、Forthの理解が格段に進むはずです。電子書籍としても出版されているものがあります。
参考資料

インターネット上にも無料で参照できるForth関連の豊富なリソースが存在します。
参考資料

Webサイト、ソースコード、ニュースレターなど、さまざまな形でリソースが公開されているので、活用していきたいものです。
参考資料

長年にわたりForth言語を支える活発なコミュニティが存在し、開発者同士が支え合う環境があります。
参考資料

オンラインフォーラムやメーリングリスト、対面の勉強会など、様々な形でForth開発者同士が交流を深めています。初心者でもこうしたコミュニティに参加することで、サポートを受けられます。Forthの小さな世界ですが、地域を越えて開発が行われているのが特徴です。
参考資料

Forthの参考文献やオンラインリソース、そしてコミュニティを上手く活用することで、この独特な言語の理解が一層深まるはずです。