このハンドブックは、Ficl(Forth-Inspired Command Language)の使用法と機能について包括的に説明するものです。Ficlは、組み込みシステムやリソースの制限された環境で使用することを目的とした、ANS Forthに基づく拡張可能な言語インタプリタです。

Ficlは、Forthのシンプルさと柔軟性を活かしながら、より広範なユーザーに向けて設計されています。本書では、Ficlの基本構文から始めて、逐次的に高度なトピックや活用法について掘り下げていきます。Ficlを利用することで、ユーザーは効率的かつ迅速に、組み込みシステムや小規模プロジェクトでの開発を行うことができます。

このハンドブックは、Ficlの新規ユーザーから経験豊富なプログラマーまで、幅広い読者層を対象としています。Ficlの基本概念や実用的な例を通じて、読者が短時間で理解を深め、自身のプロジェクトでFiclを有効活用できるようにサポートします。

導入 編集

まず Ficl の処理系を導入しましょう。

FreeBSD 編集

Portsコレクションの lang/ficl から導入できます。

ソースコードを入手してインストール 編集

GNU/Linux には、あまり Ficl をパッケージ化しているディストリビューションはないようです。

ソースコードを入手して、ビルドしインストールしましょう。

$ mkdir ~/ficl
$ cd ficl
$ wget https://downloads.sourceforge.net/project/ficl/ficl-all/ficl4.1/ficl-4.1.0.tar.gz
$ tar zxvBpf ficl-4.1.0.tar.gz 
$ cd ficl-4.1.0/
$ make
$ ./ficl
$ sudo install -c ficl /usr/local/bin/

Ficlの起動と終了 編集

Ficlを起動して使用する方法は、通常のForthシステムと似ていますが、具体的な手順についてはFiclの実装に依存します。一般的な方法を以下に示します。

$ ficl
loading CORE EXT words 
loading SEARCH & SEARCH-EXT words 
loading Johns-Hopkins locals 
loading MARKER 
loading ficl O-O extensions 
loading ficl utility classes 
loading ficl string class 
Ficl version 4.1.0
Apr 15 2024 
ok> 1 2 3 * + . cr ↵
7 
ok> bye ↵
$
シェルから ficl をタイプして起動します。
ok> が Ficl のプロンプトでこの状態が解釈モード(Interpretation mode)です。
ここでは、1 2 3 * + . cr を入力して、値7を得ています。
Ficlは、bye で終了します。

ファイルの実行 編集

あらかじめファイルに書かれたコードの実行は、コマンドラインからファイル名を与えます。

$ cat hello.fr 
\ hello.fr:
.( Hello, world!) cr
bye

$ ficl hello.fr 
loading CORE EXT words 
loading SEARCH & SEARCH-EXT words 
loading Johns-Hopkins locals 
loading MARKER 
loading ficl O-O extensions 
loading ficl utility classes 
loading ficl string class 
Ficl version 4.1.0
Apr 15 2024 
loading hello.fr 
Hello, world!

ソースの最後に bye がないと ok> が出て解釈モードになります。

構文の基礎 編集

Ficlの構文は、基本的なスタックベースの逆ポーランド記法に基づいています。このセクションでは、Ficlの基本的な構文について説明します。

スタックとワード 編集

Ficlでは、スタックが中心的な役割を果たします。数値やデータはスタックにプッシュ(積み上げ)され、ワード(単語)はスタックから値をポップ(取り出し)して処理します。ワードは辞書に登録された名前付きのコードであり、それぞれが特定の機能を持ちます。ワードは、Ficlプログラムの基本的なビルディングブロックです。

命令の形式 編集

Ficlの命令は基本的に次の形式を取ります:

<引数1> <引数2> ... <引数n> <ワード>

ここで、<引数>はスタックにプッシュされる値やデータを表し、<ワード>はこれらの引数を処理する特定の命令を示します。

コメント 編集

Ficlでは、コメントは括弧で囲んで表現されます。例えば:

( これはコメントです )

\ から行末までもコメントです

3 4 + \ 3 + 4 の結果をスタックトップに残す

コメントはインタプリタに無視されます。

スタックエフェクト 編集

Ficlの各ワードは、スタック上で特定の操作を行います。ワードのドキュメントでは、それがスタックに対してどのような影響を与えるかを示す記述があります。例えば:

+ ( a b -- c )

この記述は、+ワードが2つの引数(ab)を消費し、1つの結果(c)をスタックに残すことを意味します。

編集

以下は、Ficlでの簡単な計算の例です:

3 4 + .

この例では、34がスタックにプッシュされ、+ワードが実行されてスタック上で加算が行われます。最後の.はスタックのトップの値を出力するワードです。

コード 3 4 + .
スタックトップ 3 4 7
3
出力 7

以上がFiclの基本的な構文についての概要です。次のセクションでは、さらに詳細なワードの説明をします。

スタック操作 編集

Ficlでは、以下のような基本的なスタック操作がサポートされています:

  • dup : スタックのトップにある値を複製する
  • drop : スタックのトップから値を削除する
  • swap : スタックのトップの2つの値を交換する
  • over : スタックの2つ目の値をトップに複製する
  • rot : スタックのトップの3つの値を回転させる

これらの操作を組み合わせて、さまざまな計算や処理を行うことができます。

ワードの定義 編集

ワードはFiclプログラムの基本的な構成要素です。新しいワードを定義するには、:(コロン)を使用します。例えば、以下のようにして新しいワードを定義します:

: double ( n -- n*2 ) 2 * ;

この例では、doubleというワードはスタックから値を取り出して2倍にし、結果をスタックに戻します。

ワードの実装 編集

ワードの実装は、:(コロン)で始まり、:から;(セミコロン)までの間に記述されます。これは新しいワードの開始と終了を示します。例えば、上記のdoubleワードは、2 * ;で実装されています。2 *はスタックから値を取り出して2倍にし、;はワードの定義の終了を示します。

スタックエフェクトのコメント 編集

ワードの定義には、()で囲まれたコメントが含まれることが一般的です。これにより、ワードが期待するスタックの状態を説明することができます。例えば、( n -- n*2 )は、doubleがスタックから整数を取り出し、その2倍の値をスタックに戻すことを示しています。

ワードの使用 編集

定義されたワードは、Ficlプログラム内で他のワードと同様に使用できます。例えば、先ほど定義したdoubleワードは、以下のようにして使用できます:

5 double .

このコードは、スタックに5をプッシュし、それをdoubleワードで処理して結果を表示します。

これがFiclにおける基本的なワード定義の手順です。ワード定義を使ってFiclプログラムを効果的に構築するためには、これらの手順を理解し、適切に使用することが重要です。

文字列処理 編集

ワード ." は、Ficlにおいて文字列を表示するために使用されるワードです。このワードはダブルクォート (") で囲まれた文字列を表示します。


." はコンパイル時に使用されると、コンパイラによって文字列リテラルが生成されます。このリテラルは実行時に評価され、文字列が表示されます。

使用例 編集

以下は ." の基本的な使用例です:

: say-hello ( -- )
 ." Hello, world!" cr
;
say-hello \ Hello, world!

このコードでは、Hello, world! という文字列が表示されます。cr は改行を意味し、表示された文字列の後に改行が挿入されます。

条件分岐 編集

Ficlにおける条件分岐は、主にスタックの状態を調べることで実現されます。Ficlでは条件分岐に IFELSETHEN というワードの組み合わせが使われます。ここでは、基本的な条件分岐の使い方を説明します。

IF-ELSE-THEN 編集

Ficlでは、IFELSETHEN を組み合わせて条件分岐を行います。基本的な構文は以下の通りです:

IF
    (true branch)
ELSE
    (false branch)
THEN
  • IF は条件式を評価し、その結果が真(非ゼロ)であれば、true branch(真の場合の処理)が実行されます。
  • ELSE は条件が偽(ゼロ)である場合に実行される処理を指定します。ELSE は省略可能です。
  • THEN は条件分岐の終了を示します。

条件分岐の例 編集

例として、スタックのトップにある値が正かどうかを判定して処理を分岐するプログラムを示します。

: check-positive ( n -- )
    0<
    IF
        ." Negative" cr
    ELSE
        ." Positive" cr
    THEN ;

この例では、check-positive という新しいワードを定義しています。このワードはスタックから整数を1つ取り出し、その値が正(0より大きい)かどうかを判定します。

  • 0< はスタックトップの値が0未満かどうかを評価します。結果は真(非ゼロ)または偽(ゼロ)となります。
  • IF は条件が真の場合(つまり負の値の場合)に " Negative" というメッセージを表示します。
  • ELSE は条件が偽の場合(つまり正の値またはゼロの場合)に " Positive" というメッセージを表示します。ここでは省略しています。
  • THEN は条件分岐の終了を示します。

この例を使用すると、以下のようにして条件分岐を行うことができます:

5 check-positive

このコードは Positive を出力します。同様に、負の値を入力すると Negative が出力されます。

これがFiclにおける基本的な条件分岐の使い方です。条件に応じて処理を切り替えるために IFELSETHEN を適切に使用することで、柔軟なプログラミングが可能です。

多方向分岐 編集

Ficlには CASE ワードがあり、複数の条件に基づいて分岐するために使用されます。CASE ワードは、与えられた値に対して複数の条件を評価し、一致する条件に応じて異なる処理を実行します。ここでは、Ficlにおける CASE ワードの基本的な使い方を説明します。

CASE-OF-ENDOF-ENDCASE 編集

Ficlにおける CASE 文の基本的な使い方は次の通りです:

value
CASE
    constant1 OF
        (condition1 code)
    ENDOF
    constant2 OF
        (condition2 code)
    ENDOF
    ...
    constantN OF
        (conditionN code)
    ENDOF
        (default code)
    ENDCASE
  • value は条件式であり、この値に基づいて CASE 文が評価されます。
  • OF は個々の条件節の開始を示します。
  • ENDOF は個々の条件節の終了を示します。
  • DEFAULT はどの条件にも一致しない場合のデフォルトの処理を指定します。
  • ENDCASECASE 文の終了を示します。

各条件節は、constantvalue と一致する場合に実行されるコードを含みます。

CASE-OF-ENDOF-ENDCASEの例 編集

例として、value の値に応じて異なるメッセージを出力する CASE 文を示します。

: print-message ( n -- )
    CASE
        1 OF
            ." One" cr
        ENDOF
        2 OF
            ." Two" cr
        ENDOF
        3 OF
            ." Three" cr
        ENDOF
            ." Other" cr
    ENDCASE ;

5 print-message

この例では、print-message という新しいワードを定義しています。このワードはスタックから整数を取り出し、その値に応じて異なるメッセージを出力します。

  • CASE ブロック内の 1 OF は、value1 の場合に実行されるコードを定義しています。
  • ENDOF は各条件節の終了を示します。
  • DEFAULT はどの条件にも一致しない場合に実行されるデフォルトのコードを定義しています。

上記の例を実行すると、5 を入力した場合は Other というメッセージが出力されます。他の値を入力すると、対応するメッセージが出力されます。

これがFiclにおける CASE ワードの基本的な使い方です。CASE 文を使用することで、複数の条件に基づいて柔軟にプログラムを制御することができます。

ループ 編集

Ficlでは、繰り返し処理を行うためのワードもサポートされています。例えば、以下のように使用します:

: 10times
10 0 do
    i .
loop
;

この例では、0から9までの数値を順番にスタックにプッシュして、loopまでの間に繰り返し処理が行われます。iはループカウンタを示し、.はカウンタの値を出力します。

以上が、Ficlの基本的なワードの概要です。これらの基礎を理解することで、Ficlを使用してさまざまな計算や制御構造を実装することができます。詳細な操作や応用例については、Ficlのドキュメントやチュートリアルを参照してください。

Ficlのパース戦略 編集

Ficlのパーサーは、他のFORTHとは異なり、拡張可能なパーサーチェーンを持っています。具体的には、Ficlのパーサーは1つの巨大な関数ではなく、単純なトークナイザーと一連のパースステップで構成されています。パースステップは、特定の種類のトークンを処理し、トークンに適切な操作を行います。

パーサーは次のように動作します。

  1. 新しいトークン(内部に空白のないテキストの文字列)を読み込みます。
  2. パーサーチェーン内の各パースステップに対して、そのトークンを渡してパースステップを呼び出します。パースステップがトークンを適切に処理した場合、次のトークンに進みます。
  3. パーサーがすべてのパースステップを試し、どれもトークンを処理しなかった場合、トークンは不正であり、エラーが表示され、仮想マシンがリセットされます。

パースステップは、ネイティブ関数またはFiclスクリプト関数として書くことができます。新しいパースステップはいつでもチェーンに追加できます。

そして、デフォルトのFiclパーサーチェーンは、以下のようになっています。

  • ?word: ローカル変数辞書やシステム辞書でトークンを検索し、見つかればそれに対応する処理を行います。
  • ?prefix: プレフィックスが有効な場合に、トークンの先頭部分を既知のプレフィックスのリストと一致させ、関連付けられた処理を行います。
  • ?number: トークンを数値に変換しようとします。
  • ?float: トークンを浮動小数点数に変換しようとします。

これらのパースステップは、Ficlの柔軟性を高め、新しい機能を追加する際にも役立ちます。

prefixの追加 編集

Ficlでは、ユーザーコードで prefix を新たに作ることが出来ます。

ok> start-prefixes
ok> : 0b  2 __tempbase ; immediate
ok> end-prefixes   
ok> 0b1100 . cr
12 
ok>

ここでは 0b を前置する二進数リテラルを定義しています。

ANS Forthへの準拠状況 編集

Ficlは、Forth言語の実装であり、ANS Forth規格に準拠していますが、完全に準拠しているわけではありません。以下は、FiclがANS Forthにどの程度準拠しているかを示す一般的な概要です。

  1. コアワードの実装: FiclはANS Forthのコアワードの多くを実装しています。これにはスタック操作、制御構造、データ型、変数、定数などが含まれます。
  2. ワードセット: FiclはANS Forthの基本的なワードセットに加えて、いくつかの追加のワードセットもサポートしています。これには、Forthの実行環境やアプリケーション開発を支援するための拡張機能が含まれます。
  3. 標準準拠度の程度: FiclはANS Forthの基本的な機能には準拠していますが、すべての機能や拡張機能を実装しているわけではありません。特定の機能やワードがサポートされていない場合もあります。
  4. Ficl固有の拡張: Ficlは独自の拡張機能や機能を持っており、これらはANS Forthとは異なる場合があります。Ficlは独自のニーズや要件に合わせてカスタマイズされています。

したがって、FiclはANS Forthとの互換性を重視していますが、完全な準拠ではないことに留意する必要があります。特定のプロジェクトや環境でFiclを使用する場合は、詳細なドキュメントやリファレンスを参照して、サポートされている機能や動作を理解することが重要です。

機能の準拠状況は、ワードENVRIRONMENT?を使って問い合わせることが出来ます。

.( address-unit-bits) bl emit s" address-unit-bits" environment?  [if] . [then] cr
.( core) bl emit s" core" environment?  [if] . [then] cr
.( core-ext) bl emit s" core-ext" environment?  [if] . [then] cr
.( /counted-string) bl emit s" /counted-string" environment?  [if] . [then] cr
.( exception) bl emit s" exception" environment?  [if] . [then] cr
.( exception-ext) bl emit s" exception-ext" environment?  [if] . [then] cr
.( ficl-robust) bl emit s" ficl-robust" environment?  [if] . [then] cr
.( file) bl emit s" file" environment?  [if] . [then] cr
.( file-ext) bl emit s" file-ext" environment?  [if] . [then] cr
.( floating) bl emit s" floating" environment?  [if] . [then] cr
.( floating-ext) bl emit s" floating-ext" environment?  [if] . [then] cr
.( floating-stack) bl emit s" floating-stack" environment?  [if] . [then] cr
.( floored) bl emit s" floored" environment?  [if] . [then] cr
.( /hold) bl emit s" /hold" environment?  [if] . [then] cr
.( #locals) bl emit s" #locals" environment?  [if] . [then] cr
.( locals) bl emit s" locals" environment?  [if] . [then] cr
.( locals-ext) bl emit s" locals-ext" environment?  [if] . [then] cr
.( max-char) bl emit s" max-char" environment?  [if] . [then] cr
.( max-n) bl emit s" max-n" environment?  [if] . [then] cr
.( max-d) bl emit s" max-d" environment?  [if] . [then] cr
.( max-u) bl emit s" max-u" environment?  [if] u. [then] cr
.( memory-alloc) bl emit s" memory-alloc" environment?  [if] . [then] cr
.( /pad) bl emit s" /pad" environment?  [if] . [then] cr
.( return-stack-cells) bl emit s" return-stack-cells" environment?  [if] . [then] cr
.( search-order) bl emit s" search-order" environment?  [if] . [then] cr
.( search-order-ext) bl emit s" search-order-ext" environment?  [if] . [then] cr
.( stack-cells) bl emit s" stack-cells" environment?  [if] . [then] cr
.( tools) bl emit s" tools" environment?  [if] . [then] cr
.( tools-ext) bl emit s" tools-ext" environment?  [if] . [then] cr
.( wordlists) bl emit s" wordlists" environment?  [if] . [then] cr
実行結果
address-unit-bits 8 
core -1 
core-ext 0 
/counted-string 256 
exception -1 
exception-ext -1 
ficl-robust 2 
file -1 
file-ext -1 
floating 0 
floating-ext 0 
floating-stack 128 
floored 0 
/hold 256 
#locals 64 
locals -1 
locals-ext -1 
max-char 255 
max-n 2147483647 
max-d 2147483647 
max-u 4294967295 
memory-alloc -1 
/pad 256 
return-stack-cells 128 
search-order -1 
search-order-ext -1 
stack-cells 128 
tools -1 
tools-ext 0 
wordlists 16

倍長整数 編集

Ficlは、「Providing names from the Double-Number word set[1]」としており「Double-Number word setの一部を提供する標準システム」とラベル付けされます。

実装されているワード
2constant 2value 2literal 2variable dnegate
倍長整数リテラル
倍長整数は専用のリテラルを持っています。
倍長整数リテラルは整数リテラルに . を補うことで表現します。
倍長整数リテラルの例
0. 1. -2.
実行例
ok> 123. 456. .s
[data stack has 4 entries, top at 0x5643495da440]
[0x5643495da440   0]:          456 (0x000001c8)
[0x5643495da438   1]:            0 (0x00000000)
[0x5643495da430   2]:          123 (0x0000007b)
[0x5643495da428   3]:            0 (0x00000000)
[data stack base at 0x5643495da428]
ok> -1. -2. .s
[data stack has 8 entries, top at 0x5643495da460]
[0x5643495da460   0]:           -2 (0xfffffffffffffffe)
[0x5643495da458   1]:            0 (0x00000000)
[0x5643495da450   2]:           -1 (0xffffffffffffffff)
[0x5643495da448   3]:            0 (0x00000000)
[0x5643495da440   4]:          456 (0x000001c8)
[0x5643495da438   5]:            0 (0x00000000)
[0x5643495da430   6]:          123 (0x0000007b)
[0x5643495da428   7]:            0 (0x00000000)
[data stack base at 0x5643495da428]
ok>

浮動小数点数 編集

Ficlは、「Providing names from the Floating-Point word set[1]」としており「Floating-Point Extensions word setの一部を提供する標準システム」とラベル付けされます。

Ficlは、データスタックとは別にフローティングポイントスタック(FPスタック)を持ちます。

ok> 3.14e 5e fdup f* f* f. cr
78.500000 
ok> 1e 2e 3e 4e 5e f.s
[float stack has 5 entries, top at 0x558b5e04ccc8]
[0x558b5e04ccc8   0]         5.000000 (0x5d82d24540a00000)
[0x558b5e04ccc0   1]         4.000000 (0x5d82d24540800000)
[0x558b5e04ccb8   2]         3.000000 (0x5d82d24540400000)
[0x558b5e04ccb0   3]         2.000000 (0x5d82d24540000000)
[0x558b5e04cca8   4]         1.000000 (0x5d82d2453f800000)
[float stack base at 0x558b5e04cca8]
ok> f+ f+ f+ f+ f.s
[float stack has 1 entries, top at 0x558b5e04cca8]
[0x558b5e04cca8   0]        15.000000 (0x5d82d24541700000)
[float stack base at 0x558b5e04cca8]

浮動小数点数関係のワードは原則的にfを名前に前置します。

アライメント 編集

ドキュメントおよびソースコードのコメントでは FICL_ALIGN を参照すると書かれていますが、実際は FICL_PLATFORM_ALIGNMENT が参照されています。

これは実行時にも

ok> s" FICL_PLATFORM_ALIGNMENT" environment?  [if] . [then] cr
8

のように参照できます。

オブジェクト指向プログラミング 編集

Ficlのオブジェクト指向(OO)システムの特徴 編集

  • 遅延バインドと早期バインド: Ficlのオブジェクトは通常遅延バインドされます。これは、特定のオブジェクトに対して常に適切なメソッドが呼び出されることを保証します。しかし、コンパイル時にオブジェクトのクラスがわかる場合は、早期バインドも利用できます。
  • 単一継承、集約、およびオブジェクトの配列: FiclのOOPは単一継承をサポートし、さらに集約やオブジェクトの配列も可能です。
  • 独立したメソッド名前空間: クラスごとに独立したメソッド名前空間があり、メソッドはそのクラスまたはオブジェクトのコンテキスト内でのみ可視です。サブクラスではメソッドをオーバーライドまたは追加することができます。
  • クラスとオブジェクトの統一された構文: Ficlでは、すべてのクラスがオブジェクトであり、クラスメソッドにはサブクラス化やインスタンス化などの機能が含まれます。
  • 既存のデータ構造のラッピング: Ficlはオブジェクトラッパーを使用して既存のデータ構造を適応できます。Cで書かれてインスタンス化されたデータ構造をFiclクラスでモデル化し、そのインスタンスを作成することができます。

Ficlのオブジェクト指向プログラミングの概念 編集

この文書では、オブジェクト指向プログラミングの基本的な概念や用語に触れています。オブジェクト指向プログラミングに馴染みがない場合は、一般的な概要を参照することをお勧めします。

Ficlのオブジェクトモデル 編集

Ficlの全てのクラスは、共通の基本クラスであるOBJECTから派生しています。すべてのクラスはMETACLASSのインスタンスでもあります。これは、Ficlがクラスもオブジェクトとして扱うことを意味します。METACLASSはクラスに送信されるメッセージのためのメソッドを実装します。

Ficlのオブジェクト指向構文チュートリアル 編集

オブジェクトの作成とクラスの定義 編集

まずは、オブジェクトを作成しクラスを定義する方法から始めましょう。

  1. クラスの定義
    クラスを定義するには、基底クラスからEND-CLASSまでの間にフィールドとメソッドを定義します。例えば、complexクラスを定義するとします。
    complex.fr
    only
    also oop definitions
    
    object --> sub complex
      cell: .real
      cell: .imag
      
      : init ( f: real imag -- )
        locals| class inst |
        inst class --> .real f!
        inst class --> .imag f!
      ;
    
      : @ ( -- f: real imag )
        locals| class inst |
        inst class --> .real f@
        inst class --> .imag f@
      ;
    
      : . ( f: -- f: )
        locals| class inst |
        inst class --> @ f. f.
      ;
    
    end-class
    
    3e 4e complex --> new cplx
    cplx --> . cr \ 3.000000 4.000000
    
    ここでは、complexというクラスが定義されています。.real.imagは各軸の座標を示すインスタンス変数です。initメソッドは初期化時に呼び出され、@は各軸の値をフロートスタックに積むメソッドです。.メソッドは各軸の値を表示します。
  2. オブジェクトのインスタンス化
    定義したクラスを使用してオブジェクトをインスタンス化します。
    3e 4e complex --> new cplx
    
    これにより、complexクラスのインスタンスであるcplxオブジェクトが作成されます。
    ここではフィールドの初期値をフロートスタックを経由して渡しています。
  3. メソッドの呼び出し
    作成したオブジェクトに対してメソッドを呼び出す方法を示します。
    cplx --> . cr \ 3.000000 4.000000
    
    cplx --> .のように、オブジェクト名に続けてメソッドを指定することで、対応するメソッドが実行されます。

クラス間の継承 編集

Ficlでは単一継承がサポートされています。既存のクラスを拡張して新しいクラスを定義することができます。

OBJECT --> SUB C1
: M1   { 2:THIS -- }  ." C1's M1" CR ;
END-CLASS

C1 --> SUB C2
: M1   { 2:THIS -- }  ." C2's M1" CR ;
END-CLASS

上記の例では、C1クラスをベースにしてC2クラスを定義しています。M1メソッドがC1からC2でオーバーライドされています。

オブジェクト指向プログラミングの利点 編集

Ficlのオブジェクト指向プログラミングを活用することで、データと操作がひとつのまとまりとして扱えるため、コードの保守性や再利用性が向上します。また、クラスやオブジェクトの階層構造を使ってシステムを設計することで、問題をより効率的に解決できるようになります。

不足している標準ワードの追加 編集

Ficlは、ANS Forthに基いていますがすべての標準を実装してはいません。 このため適宜、必要なワードを追加する必要が生じます。 特に浮動小数点数に関するワードは基本的なワードセットにとどまっています。

FABSを実装 編集

浮動小数点数の絶対値を返すワード FABS は Ficl では未実装です。 FABS は比較的簡単な機能なので Forth で実装してみます。

fabs.fr
: fabs ( F: x -- | x | )
  fdup 0e f< if fnegate else
  fdup 0e f= if fdrop 0e then then 
;
0.0 と一致したら 0.0 を返しているのは、-0.0 対策です。

使ってみます

$ ./ficl fabs.fr 
loading CORE EXT words 
loading SEARCH & SEARCH-EXT words 
loading Johns-Hopkins locals 
loading MARKER 
loading ficl O-O extensions 
loading ficl utility classes 
loading ficl string class 
Ficl version 4.1.0
Apr 16 2024 
loading fabs.fr 

ok> -12.3e fabs f. cr
12.300000 
ok> 42.1e fabs f. cr
42.099998 
ok> see fabs
: fabs
   0   fdup (instruction 177)
   1   0.0e (instruction 34)
   2   f< (instruction 190)
   3   branch0 8
   5   fnegate (instruction 159)
   6   branch 15
   8   fdup (instruction 177)
   9   0.0e (instruction 34)
  10   f= (instruction 192)
  11   branch0 15
  13   fdrop (instruction 175)
  14   0.0e (instruction 34)
;
ok> see abs
: abs
   0   dup (instruction 45)
   1   0< (instruction 83)
   2   branch0 5
   4   negate (instruction 62)
;
ok>

FSQRTを実装(Ficlを改造) 編集

浮動小数点数の平方根を返すワード FSQRT は Ficl では未実装です。 FSQRT は Forth で実装するには手強いのでCで実装します。

float.c の差分
$ diff -rud --show-c-function float.c.orig float.c
--- float.c.orig        2010-09-14 03:43:04.000000000 +0900
+++ float.c     2024-04-16 10:44:21.236338034 +0900
@@ -159,7 +159,7 @@ static ficlInteger ficlFloatStackDisplay
 {
     struct stackContext *context = (struct stackContext *)c;
     char buffer[64];
*    sprintf(buffer, "[0x%08x %3d] %16f (0x%08x)\n", cell, context->count++, (double)(cell->f), cell->i);
+    sprintf(buffer, "[0x%08lx %3d] %16f (0x%08lx)\n", (long unsigned)cell, context->count++, (double)(cell->f), (long)cell->i);
     ficlVmTextOut(context->vm, buffer);
        return FICL_TRUE;
 }
@@ -400,6 +400,22 @@ int ficlVmParseFloatNumber( ficlVm *vm,
 }
 
 
+/*******************************************************************
+** Floating-point Square root.
+** fsqrt ( F: r -- sqrt(r) )
+*******************************************************************/
+static void ficlPrimitiveFSqrt(ficlVm *vm)
+{
+    FICL_STACK_CHECK(vm->floatStack, 1, 1);
+
+    float f = ficlStackPopFloat(vm->floatStack);
+ 
+    f = sqrt(f);
+    
+    ficlStackPushFloat(vm->floatStack, f);
+}
+
 #if FICL_WANT_LOCALS
 
 static void ficlPrimitiveFLocalParen(ficlVm *vm)
@@ -439,6 +455,8 @@ void ficlSystemCompileFloat(ficlSystem *
     ficlDictionarySetPrimitive(dictionary, "f.s",       ficlVmDisplayFloatStack,  FICL_WORD_DEFAULT);
     ficlDictionarySetPrimitive(dictionary, "fe.",       ficlPrimitiveEDot,           FICL_WORD_DEFAULT);
 
+    ficlDictionarySetPrimitive(dictionary, "fsqrt",     ficlPrimitiveFSqrt,           FICL_WORD_DEFAULT);
+    
 #if FICL_WANT_LOCALS
     ficlDictionarySetPrimitive(dictionary, "(flocal)",   ficlPrimitiveFLocalParen,     FICL_WORD_COMPILE_ONLY);
     ficlDictionarySetPrimitive(dictionary, "(f2local)",  ficlPrimitiveF2LocalParen,  FICL_WORD_COMPILE_ONLY);

ビルドの上、使ってみます。

$ ./ficl
loading CORE EXT words 
loading SEARCH & SEARCH-EXT words 
loading Johns-Hopkins locals 
loading MARKER 
loading ficl O-O extensions 
loading ficl utility classes 
loading ficl string class 
Ficl version 4.1.0
Apr 16 2024 
ok> 2e fsqrt f. cr
1.414214 
ok> 3e fdup f* 4e fdup f* f+ fsqrt f. cr
5.000000 
ok> see fsqrt
fsqrt is a primitive
ok>

FSQRTを実装(Johns-Hopkins localsを使用しFiclで実装) 編集

前項では、Ficlを改造してCレベルの実装しましたが、Ficlのコードだけで実装してみました。 とは言うものの、FloatスタックをFOVERなどを駆使して実装するのは興味深いのですが技巧的になりすぎるので、ここでは Johns-Hopkins localsを使用し名前付き引数と名前付きローカル変数を使ってライトに実装しました。

: fabs ( F: x -- | x | )
  fdup 0e f< if fnegate else
  fdup 0e f= if fdrop 0e then then 
;

-1e fabs f. cr  / 1.000000 
0e fabs f. cr   / 0.000000 
42e fabs f. cr  / 42.000000 

: fsqrt { f:x | f:guess f:last -- √x }
 x 0e f< if  \ 負の数の平方根は定義されていないため、NaNを返す
     0e 0e f/
 else
   x 0e f= if  \ 零の平方根は零なのでそのまま返す
     0e
   else  \ ニュートン法を使って平方根を計算する
     x 2e f/ to guess \ 初期推定値として x の半分を使う

     begin
        guess to last
        x last f/ last f+ 2e f/ to guess  \ ニュートン法の更新式
        last guess f- fabs 1e-8 f>  \ 誤差が許容範囲内になったら計算結果を返す
     while
     repeat
     guess
   then
 then
;

.( -1.0 FSQRT ) -1e fsqrt f. cr  \ -1.0 FSQRT -nan 
.( 0.0 FSQRT )   0e fsqrt f. cr  \ 0.0 FSQRT 0.000000 
.( 1.0 FSQRT )   1e fsqrt f. cr  \ 1.0 FSQRT 1.000000 
.( 2.0 FSQRT )   2e fsqrt f. cr  \ 2.0 FSQRT 1.414214 
.( 3.0 FSQRT )   3e fsqrt f. cr  \ 3.0 FSQRT 1.732051 
.( 4.0 FSQRT )   4e fsqrt f. cr  \ 4.0 FSQRT 2.000000

{ f:x | f:guess f:last -- √x } は、コメントではなく、Johns-Hopkins localsというFiclの引数とローカル変数を扱う仕組み { を利用しています。

具体的には:

  • f:x は、ワード本体で使用される浮動小数点数の引数xを宣言しています。
  • | は、入力引数とローカル変数を分ける記号です。
  • f:guess f:last は、ローカル変数としてguesslastという2つの浮動小数点数変数を宣言しています。
  • -- √x は、このワードの出力がxの平方根であることを示すスタックコメントです。

ワードto ( x -- ) は、つづく名前を持つローカル変数にスタックからポップした値をアサインします。kのとき使用されるスタックは f: で指定されていればフロートスタックが使われます。

Johns-Hopkins localsを使うと、記述性・可読性が向上しますがANS Forthの機能でないのが悩ましいところです。

ニュートン法を用いて実数の平方根を求めるアルゴリズム
ニュートン法(またはニュートン・ラフソン法)を使用して実数の平方根を求めるアルゴリズムは、与えられた数   の平方根   を見つける手法です。ニュートン法は、方程式   の解を数値的に近似するための反復的な手法であり、ここでは   として考えます。

具体的な手順は以下の通りです:

  1. 初期推定値の設定: 平方根の推定値   を選びます。この値は   の近似値である必要がありますが、一般的には   よりも小さい値が使われます。例えば、  とすることが一般的です。
  2. 反復計算: 反復的に以下の式を用いて推定値を修正します。
     
    ここで、
     
      の関数であり、
     
      の導関数です。
  3. 収束条件の確認: 収束条件を満たすまで反復計算を行います。通常は、  が非常に小さい値(上に例では、  よりも小さい)になったときに反復を終了します。


トラブルシューティング 編集

よくある問題と対処法 編集

エラーメッセージの意味と対応 編集

附録 編集

全ワード一覧 編集

Ficlの全ワード一覧
ワード スタック操作 カテゴリ 種別 読み 説明
! ( x a-addr -- ) core primitive store x を a-addr に保存
# ( ud1 -- ud2 ) core primitive number-sign ud2 = u1 / BASE ⇒ <# #>
#> ( xd -- c-addr u ) core primitive number-sign-greater 数値文字列変換 ⇒ <# #
#s ( ud1 -- ud2 ) core primitive number-sign-s #に従ってud1の1桁をud2(商)がゼロになるまで変換します。⇒ <# #>
' ( "<spaces>name" -- xt ) core primitive tick name の実行トークン xt を返す
( ( "ccc<paren>" -- ) core primitive immediate paren ) までがコメント
(+loop) ( -- ) ficl primitive compile-only paren-plus-loop-paren ficl独自:
(.") ( -- ) ficl primitive compile-only paren-dot-quote-paren ficl独自:
(2constant) ( -- ) ficl kind (2constant) desc.
(2literal) ( -- ) ficl kind (2literal) desc.
(2local) ( -- ) ficl kind (2local) desc.
(;) ( -- ) ficl kind (;) desc.
(?do) ( -- ) ficl kind (?do) desc.
(@2Local) ( -- ) ficl kind (@2Local) desc.
(@2Local0) ( -- ) ficl kind (@2Local0) desc.
(@f2Local) ( -- ) ficl kind (@f2Local) desc.
(@fLocal) ( -- ) ficl kind (@fLocal) desc.
(@local) ( -- ) ficl kind (@local) desc.
(@local0) ( -- ) ficl kind (@local0) desc.
(@local1) ( -- ) ficl kind (@local1) desc.
(To2Local0) ( -- ) ficl kind (To2Local0) desc.
(branch) ( -- ) ficl kind (branch) desc.
(branch-final) ( -- ) ficl kind (branch-final) desc.
(branch0) ( -- ) ficl kind (branch0) desc.
(branch0-final) ( -- ) ficl kind (branch0-final) desc.
(c") ( -- ) ficl kind (c") desc.
(colon) ( -- ) ficl kind (colon) desc.
(constant) ( -- ) ficl kind (constant) desc.
(create) ( -- ) ficl kind (create) desc.
(do) ( -- ) ficl kind (do) desc.
(does) ( -- ) ficl kind (does) desc.
(exit) ( -- ) ficl kind (exit) desc.
(f2constant) ( -- ) ficl kind (f2constant) desc.
(f2local) ( -- ) ficl kind (f2local) desc.
(fconstant) ( -- ) ficl kind (fconstant) desc.
(fliteral) ( -- ) ficl kind (fliteral) desc.
(flocal) ( -- ) ficl kind (flocal) desc.
(link) ( -- ) ficl kind (link) desc.
(literal) ( -- ) ficl kind (literal) desc.
(local) ( c-addr u -- ) core primitive compile-only paren-local-paren u <> 0 なら c-addr のローカル変数を宣言、u = 0 ならスコープ終了
(loop) ( -- ) ficl kind (loop) desc.
(of) ( -- ) ficl kind (of) desc.
(parse-step) ( -- ) ficl kind (parse-step) desc.
(to2Local) ( -- ) ficl kind (to2Local) desc.
(toF2Local) ( -- ) ficl kind (toF2Local) desc.
(toFLocal) ( -- ) ficl kind (toFLocal) desc.
(toLocal) ( -- ) ficl kind (toLocal) desc.
(toLocal0) ( -- ) ficl kind (toLocal0) desc.
(toLocal1) ( -- ) ficl kind (toLocal1) desc.
(unlink) ( -- ) ficl kind (unlink) desc.
(user) ( -- ) ficl kind (user) desc.
(variable) ( -- ) ficl kind (variable) desc.
* ( n1 n2 -- n3 ) core primitive star n3 = n1 n2
*/ ( n1 n2 n3 -- n4 ) core primitive star-slash n4 = n1 * n2 / n3
*/mod ( n1 n2 n3 -- n4 n5 ) core primitive star-slash-mod n4 = n1 * n2 / n3, n5 = n1 * n2 % n3
+ ( n1 n2 -- n3 ) core primitive plus n3 = n1 + n2
+! ( n a-addr -- ) core primitive plus-store *a-addr += n
+loop ( C: do-sys -- ) core primitive immediate compile-only plus-loop do
, ( x -- ) core primitive comma データスペースにセルを1つ確保し、そのセルにxを保存する。
- ( n1 n2 -- n3 ) core primitive minus n3 = n1 - n2
-roll ( n -- ) ficl primitive minus-roll roll
-rot ( n -- ) ficl primitive minus-rote rot
. ( n -- ) core primitive dot n をフリーフィールドフォーマットで表示
." ( "ccc<quote>" -- ) core primitive immediate compile-only dot-quote " をデリミタにパースした内容を表示
.( ( "ccc<paren>" -- ) core primitive immediate dot-paren ) をデリミタにパースした内容を表示
.env ( -- ) ficl kind .env desc.
.hash ( -- ) ficl kind .hash desc.
.s ( -- ) tools primitive dot-s データスタックの内容を1要素1行でトップから表示
.s-simple ( -- ) ficl primitive dot-s-simple データスタックの内容を1行で表示
.ver ( -- ) ficl primitive mnum Ficlのバージョンを Ficl version 4.1.0 の書式で表示
/ ( n1 n2 -- n3 ) core primitive slash n3 = n1 / n2
/mod ( n1 n2 -- n3 n4 ) core primitive slash-mod n3 = n1 / n2, n4 = n1 % n2
0< ( n -- flag ) core primitive zero-less flag = n < 0 ? true : false
0<> ( n -- flag ) core primitive zero-not-equals flag = n != 0 ? true : false
0= ( n -- flag ) core primitive zero-not-equals flag = n == 0 ? true : false
0> ( n -- flag ) core primitive zero-greater flag = n > 0 ? true : false
1+ ( n1 -- n2) core primitive one-plus n2 = n1 + 1
1- ( n1 -- n2 ) core primitive one-minus n2 = n1 - 1
2! ( x1 x2 a-addr -- ) core primitive two-store *a-addr = x1, *(a-addr + 1) = x2 ⇒ 2@
2* ( n1 -- n2 ) core primitive two-star n2 = n1 * 2
2+ ( n1 -- n2 ) ficl primitive two-plus n2 = n1 + 2
2- ( n1 -- n2 ) ficl primitive two-minus n2 = n1 - 2
2/ ( n1 -- n2 ) core primitive two-slash n2 = n1 / 2
2>r ( x1 x2 -- ) ( R: -- x1 x2 ) core primitive compile-only two-to-r データスタックからリターンスタックにセルペアを移動 ⇒ >r
2@ ( a-addr -- x1 x2 ) core primitive two-fetch x1 = *a-addr, x2 = *(a-addr + 1) ⇒ 2!
2constant ( x1 x2 "<spaces>name" -- ) core primitive two-constant セルペア定数の定義 ⇒ constant
2drop ( x1 x2 -- ) core primitive two-drop セルペアをデータスタックから削除 ⇒ drop
2dup ( x1 x2 -- x1 x2 x1 x2 ) core primitive two-dupe セルペアを複製 ⇒ dup
2literal ( x1 x2 -- ) core primitive immediate two-literal セルペアリテラル ⇒ literal
2local ( -- ) ficl bl word count (2local) two-local ficl独自:
2over ( x1 x2 x3 x4 -- x1 x2 x3 x4 x1 x2 ) core primitive two-over セルペア x1 x2 をスタックトップに複製 ⇒ over
2r@ ( -- x1 x2 ) ( R: x1 x2 -- x1 x2 ) core ext primitive compile-only two-r-fetch セルペア x1 x2 をリターンスタックからデータスタックに複製 ⇒ r@
2swap ( x1 x2 x3 x4 -- x3 x4 x1 x2 ) core primitive two-swap スタックトップの2つのセルペアを入れ替え ⇒ swap
2value ( x1 x2 "<spaces>name" -- ) double ext primitive immediate two-value セルペアに名前をつけます ⇒ value to
2variable ( "<spaces>name" -- ) double primitive immediate two-variable セルペア変数を宣言 ⇒ variable 2! 2@
: ( C: "<spaces>name" -- colon-sys ) core primitive colon ワード定義開始 ⇒ ;
:noname ( C: -- colon-sys ) ( S: -- xt ) core ext primitive colon-no-name : までのワード列をコンパイルしスタックに残す
; ( C: colon-sys -- ) core primitive immediate compile-only semicolon : あるいは :noname を終了
< ( n1 n2 -- flag ) core primitive less-than flag = n1 < n2 ? true : false
<# ( -- ) core kind less-number-sign 数値文字列化開始 ⇒ #>
<> ( n1 n2 -- flag )( -- ) core ext = 0= not-equals flag = n1 != n2 ? true : false
= ( n1 n2 -- flag ) core kind equals flag = n1 != n2 ? true : false
> ( n1 n2 -- flag ) core primitive greater-than flag = n1 > n2 ? true : false
>body ( xt -- a-addr ) core primitive to-body a-addr は、create が定義したxtの直後にhereして得られるアドレス
>float false ) ( F: -- r | ~ ) floating primitive to-float c-addr u で指定された文字列を、内部の浮動小数点数表現に変換
>in ( -- a-addr ) core primitive to-in a-addr は、入力バッファの先頭からパース領域の先頭までのオフセット(文字数)を含むセルのアドレス
>name ( a-addr -- w-addr u) ficl primitive to-name ficl独自:
>number ( ud1 c-addr1 u1 -- ud2 c-addr2 u2 ) core primitive to-number 文字列数値変換の1桁分
>r ( x -- ) ( R: -- x ) core primitive compile-only to-r データスタックからリターンスタックにxを移動 ⇒ 2>r r>
>search ( wid -- ) ficl primitive to-search ficl独自: wid をsearch orderにプッシュします。
? ( a-addr -- ) tools @ . question *a-addr を表示
?do ( C: -- do-sys ) core ext primitive immediate compile-only question-do : ... ?do ... loop ;
?dup ( x -- 0 | x x ) core primitive question-dupe スタックトップが0でなければ複製 ⇒ dup
?float ( c-addr u -- x*i flag ) ficl primitive question-float トークンを浮動小数点数に変換しようとする。
?number ( c-addr u -- x*i flag ) ficl primitive question-number トークンを数値に変換しようとする。
?object ( x-addr -- flag ) ficl primitive question-object x-addr がオブジェクトを参照していたら flag は true
?prefix ( c-addr u -- x*i flag ) ficl primitive question-prefix プレフィックスが有効な場合に、トークンの先頭部分を既知のプレフィックスのリスト <prefixes> から検索し、関連付けられた処理を行う。
?word ( c-addr u -- x*i flag ) ficl primitive question-word ローカル変数辞書やシステム辞書でトークンを検索し、見つかればそれに対応する処理を行う。
@ ( a-addr -- x ) core primitive fetch x = *a-addr
[ ( -- ) core primitive immediate compile-only left-bracket 解釈モードに遷移 ⇒ ] literal
['] ( "<spaces>name" -- ) core primitive immediate compile-only bracket-tick name の xt をスタックに残す
[char] ( "<spaces>name" -- ) core primitive immediate compile-only mnum name の最初の一文字をスタックに残す
[else] ( "<spaces>name ..." -- ) tools ext softcore bracket-else 解釈モードで実行可能な else
[endif] ( -- ) ficl immediate bracket-endif 解釈モードで実行可能な endif
[if] ( flag | flag "<spaces>name ..." -- ) tools ext immediate bracket-if 解釈モードで実行可能な if
[then] ( -- ) tools ext immediate bracket-then 解釈モードで実行可能な then
\ ( "ccc<eol>" -- ) core primitive immediate backslash コメント(行末まで)
] ( -- ) core primitive right-bracket [ literal
__tempbase ( -- ) ficl primitive __tempbase ficl独自:
abort ( i * x -- ) ( R: j * x -- ) exception ext primitive abort empty quit
abort" ( "ccc<quote>" -- ) exception ext immediate abort-quote ( i * x x1 -- | i * x ) ( R: j * x -- | j * x ) x1 が真の場合、-2 throw の機能を実行します。例外スタックに例外フレームがない場合、ccc を表示します。
abs ( n -- u ) core primitive abs n |
accept ( c-addr n1 -- n2 ) core primitive accept 最大で n1 文字の文字列を受け取る。 n2 は実際に受け取った文字数
add-parse-step ( xt -- ) ficl primitive add-parse-step パースチェーンにパースステップを追加する。xtはパースステップとして使用するFiclワードのアドレス(実行トークン)。
again ( C: dest -- ) core ext primitive immediate compile-only again ex.  : x ... begin ... again ... ; exit などで脱出しない限り永久ループ
align ( -- ) core primitive align データスペースポインタをアライメント
aligned ( addr -- a-addr ) core primitive aligned a-addr に、addr 以上の最初の整列されたアドレスを返す
allocate ( u -- a-addr ior ) memory primitive allocate u アドレス単位の領域確保。ior が 0 なら a-addr に先頭アドレスを、それ以外は実装定義の I/O 結果コードでa-addrは無効
allot ( n -- ) core primitive allot データスペースポインタ を n 勧めます。n が負なら開放します。
also ( -- ) search ext search> dup >search >search also サーチオーダーの先頭を複製
and ( x1 x2 -- x3 ) core primitive and x3 = x1 & x2
base ( -- a-addr ) core primitive base a-addr は、現在の数値変換基数(2...36) を格納するセルのアドレス
begin ( C: -- dest ) core primitive immediate compile-only begin ex.  : x ... begin ... again ... ; exit などで脱出しない限り永久ループ
bin ( fam1 -- fam2 ) file 8 or bin ファイルアクセス方法 fam1 を変更し、追加で "binary"、つまり行指向でないファイルアクセス方法を選択し、アクセス方法 fam2 を提供します。
bl ( -- char ) core primitive bl スペースのキャラクターコードをスタックに積む
body> ( -- ) ficl primitive body-from ficl独自:
brand-wordlist ( -- ) ficl last-word >name drop wid-set-name brand-wordlist ficl独自:
break ( -- ) ficl primitive break ficl独自:
bye ( -- ) tools ext primitive bye ホストオペレーションシステムに復帰
c! ( char c-addr -- ) core primitive c-store c-addr に char を格納
c" ( "ccc<quote>" -- ) core primitive immediate c-quote 文字列 ccc で構成されるカウント付き文字列 c-addr を返す
c, ( char -- ) core primitive c-comma データスペースに1文字分のスペースを確保し、char をそのスペースに格納する
c@ ( c-addr -- char ) code primitive c-fetch c-addr に格納された文字を取得
case ( C: -- case-sys ) core ext primitive immediate compile-only case : x ... case test1 of ... endof testn of ... endof ... ( default ) endcase ... ;
catch ( i * x xt -- j * x 0 | i * x n ) exception primitive catch 例外スタックに例外フレームをプッシュし、次に xt の実行トークン(execute と同様に)を実行します。xt の実行中に throw が実行された場合、catch の直後の地点に制御が転送されるようにします。

xt の実行が正常に完了した場合(つまり、この catch によってプッシュされた例外フレームが throw の実行によってポップされなかった場合)、例外フレームをポップし、データスタックの先頭にゼロを返します。xt execute によって返されるスタックアイテムの上に、0 が返されます。それ以外の場合は、実行意味論の残りの部分は throw によって与えられます。

cd ( -- ) ficl primitive cd ficl独自:
cell+ ( a-addr1 -- a-addr2 ) core primitive cell-plus アドレス単位でセルのサイズを a-addr1 に追加し、a-addr2 を得る
cells ( n1 -- n2 ) core primitive cells n2 に、n1 個のセルのサイズをアドレス単位で表したものを残す
char ( "<spaces>name" -- char ) core primitive char 先頭の空白デリミタをスキップし、スペースで区切られた名前を解析し、その最初の文字の値をスタックに格納する。
char+ ( c-addr1 -- c-addr2 ) core primitive char-plus c-addr1 に文字のアドレス単位でのサイズを追加し、c-addr2 を得る。
chars ( n1 -- n2 ) core primitive chars n2 に、n1 文字のアドレス単位でのサイズを返す。
clock ( -- clk ) ficl primitive clock clk = clock(3).
clocks/sec ( -- cps ) ficl primitive clocks-per-sec cps = CLOCKS_PER_SEC..
close-file ( fileid -- ior ) file primitive close-file fileid で識別されるファイルを閉じる。ior は実装定義の I/O 結果コード。 ⇒ open-file
compare ( c-addr1 u1 c-addr2 u2 -- n ) string primitive compare c-addr1 u1 の文字列を、c-addr2 u2 の文字列と比較。nは-1,0あるいは1。
compare-insensitive ( c-addr1 u1 c-addr2 u2 -- n ) ficl primitive compare-insensitive compare と異なり大文字小文字を区別しません。
compile, ( xt -- ) core ext , compile-comma 現在の定義の実行セマンティクスに、xt で表される定義の実行セメンテックスを追加。
compile-only ( -- ) ficl compile-only compile-only ficl独自: 最も最近に定義されたワードをコンパイル状態の間のみ実行可能としてマークします。
constant ( x "<spaces>name" -- ) ficl primitive mnum 先頭の空白デリミタをスキップし、空白で区切られた名前を解析します。定数 name の定義を作成する。実行時: ( -- x ) x をスタックにプッシュする。 ⇒ 2constant fconstant
convert ( -- ) ficl char+ literal 65535 >number drop convert ficl独自:
count ( c-addr1 -- c-addr2 u ) core primitive count c-addr1 に格納されたカウント付き文字列の文字列仕様を返す。c-addr2 は c-addr1 の次の文字のアドレス。u は c-addr1 の文字の内容、c-addr2 の文字列の長さを文字数で表す。
cr ( -- ) core primitive c-r 次の出力が次の行の先頭に表示されるようにする。
create ( "<spaces>name" -- ) core primitive create 先頭の空白デリミタをスキップし空白で区切られた名前を解析します。name の実行セマンティクスを以下で定義されるように持つ定義を作成する。データスペースポインタがアラインされていない場合、それをアラインするのに十分なデータ領域を予約する。新しいデータスペースポインタが name のデータフィールドを定義する。CREATE は name のデータフィールドにデータ領域を割り当てない。

実行時: ( -- a-addr ) a-addr は name のデータフィールドのアドレス。name の実行セマンティクスは does> を使用して拡張することができる。

create-file ( c-addr u fam -- fileid ior ) file primitive create-file 文字列 c-addr と u で指定された名前のファイルを作成し、ファイルアクセス方法 fam で開く。fam の値の意味は実装依存。同じ名前のファイルが既に存在する場合、空のファイルとして再作成する。

ファイルが正常に作成および開かれた場合、ior はゼロ、fileid はその識別子であり、ファイルはファイルの先頭に位置づけられている。 それ以外の場合、ior は実装定義の I/O 結果コードであり、fileid は未定義。

debug ( -- ) ficl
: debug
  ' debug-xt
;
immediate
debug ficl独自:
debug-xt ( -- ) ficl primitive debug-xt ficl独自:
decimal ( -- ) core primitive decimal 数値変換基数を十進数に設定する
definitions ( -- ) search primitive definitions コンパイルされた単語リストを検索順序の最初の単語リストと同じにする。後続の定義の名前がコンパイルされた単語リストに配置されることを指定する。検索順序の後続の変更は、コンパイルされた単語リストに影響を与えない。
delete-file ( c-addr u -- ior ) file primitive delete-file 文字列 c-addr u で指定されたファイルを削除する。ior は、実装定義の I/O 結果コード。
depth ( -- +n ) core primitive depth +n は、+n がスタックに置かれる前にデータスタックに含まれる単一セル値の数。
dnegate ( d1 -- d2 ) double primitive d-negate d2 は d1 の符号反転。
do ( C: -- do-sys ) core primitive do do-sys を制御フロー・スタックに配置します。以下に示すランタイムの意味論を現在の定義に追加します。loop のような do-sys の消費者によって解決されるまで、セマンティクスは不完全です。

実行時: ( n1 | u1 n2 | u2 -- ) ( R: -- loop-sys ) インデックス n2 | u2 およびリミット n1 | u1 を持つループ制御パラメータを設定します。n1 | u1 と n2 | u2 が両方とも同じ型でない場合、曖昧な状態が存在します。ループ制御パラメータが破棄されるまで、すでに返り値スタックにあるものは利用できなくなります。

do-vocabulary ( -- ) ficl : do-vocabulary (does) @ search> drop >search ; do-vocabulary ficl独自:
doLocal ( -- ) ficl primitive immediate compile-only do-local desc.
does> ( C: colon-sys1 -- colon-sys2 ) core primitive immediate compile-only does コンパイル時:

(C: colon-sys1 -- colon-sys2) 現在の定義に以下のランタイムの意味論を追加します。現在の定義が DOES> のコンパイルによって辞書内で見つけられるかどうかは、実装によって定義されます。colon-sys1 を消費し、colon-sys2 を生成します。以下に示す初期化の意味論を現在の定義に追加します。


ランタイム: ( -- ) ( R: nest-sys1 -- ) 最新の定義(name と呼ばれる)の実行セマンティクスを、以下に示す name の実行セマンティクスで置き換えます。nest-sys1 で指定された呼び出し定義に制御を戻します。name が CREATE または CREATE を呼び出すユーザー定義の単語で定義されていない場合、曖昧な状態が存在します。

drop ( x -- ) core primitive drop スタックから x を削除 ⇒ 2drop fdrop
dump ( addr u -- ) tools : dump ( addr u -- ) 0 ?do dup c@ . 1+ i 7 and 7 = if cr endif loop drop ; dump addr から始まる u 個の連続するアドレスの内容を表示します。
dup ( x -- x x ) core primitive dupe x を複製 ⇒ 2dup fdup
else (C: orig1 -- orig2) core primitive immediate compile-only mnum コンパイル時:

(C: orig1 -- orig2) 新しい未解決の逆参照 orig2 の場所を制御フロー・スタックに置きます。以下に示すランタイムの意味論を現在の定義に追加します。orig2 が解決されるまで(たとえば、then によって)、意味論は不完全です。追加されたランタイムの意味論の後に続く場所を使って、逆参照 orig1 を解決します。


実行時: ( -- ) orig2 の解決によって指定された場所で実行を継続します。

emit ( x -- ) core primitive emit emit
empty ( xn..x1 -- ) ficl : empty ( xn..x1 -- ) depth 0 ?do drop loop ; empty スタックをクリア
end-locals ( -- ) ficl : end-locals ( -- ) 0 0 (local) ; immediate end-locals ローカル変数の使用を終了
end-prefixes ( -- ) ficl : end-prefixes save-current @ set-current ; end-prefixes プレフィックス定義の終了を宣言し、start-prefixes が呼び出される前に使用されていたワードリストに戻るようにFicl仮想マシンに指示する。
endcase (C: case-sys -- ) core ext primitive immediate compile-only endcase コンパイル時:

(C: case-sys -- ) case...of...endof...endcase 構造の終わりをマークします。全体の構造を解決するために case-sys を使用します。以下に示すランタイムの意味論を現在の定義に追加します。


ランタイム: (x -- ) case セレクタ x を破棄し、実行を継続します。

endif ( -- ) ficl kind endif then のシノニム
endof ( C: case-sys1 of-sys -- case-sys2 ) core ext primitive immediate compile-only endof コンパイル時:

(C: case-sys1 of-sys -- case-sys2) case 構造の of...endof 部分の終わりをマークします。次の制御の転送のための次の場所は、of-sys によって指定された参照を解決します。以下に示すランタイムの意味論を現在の定義に追加します。case-sys1 を case-sys2 で置き換え、endcase で解決するために制御フロー・スタックに置きます。


実行時: ( -- ) case-sys2 のコンシューマによって指定された場所で実行を継続します。

env-2constant ( -- ) ficl kind env-2constant desc.
env-constant ( -- ) ficl kind env-constant desc.
environment? ( -- ) ficl kind environment-quote desc.
erase ( -- ) ficl kind erase desc.
evaluate ( -- ) ficl kind evaluate desc.
execute ( -- ) ficl kind execute desc.
exit ( -- ) ficl kind exit desc.
exit-inner ( -- ) ficl kind exit-inner desc.
expect ( -- ) ficl kind expect desc.
f! ( -- ) ficl kind f-store desc.
f* ( -- ) ficl kind f* desc.
f*i ( -- ) ficl kind f*i desc.
f+ ( -- ) ficl kind f+ desc.
f+! ( -- ) ficl kind f+! desc.
f+i ( -- ) ficl kind f+i desc.
f- ( -- ) ficl kind f- desc.
f-i ( -- ) ficl kind f-i desc.
f-roll ( -- ) ficl kind f-roll desc.
f-rot ( -- ) ficl kind f-rot desc.
f. ( -- ) ficl kind f. desc.
f.s ( -- ) ficl kind f.s desc.
f/ ( -- ) ficl kind f/ desc.
f/i ( -- ) ficl kind f/i desc.
f0< ( -- ) ficl kind mnum desc.
f0= ( -- ) ficl kind desc.
f0> ( -- ) ficl kind f0> desc.
f2! ( -- ) ficl kind f2! desc.
f2@ ( -- ) ficl kind f2@ desc.
f2constant ( -- ) ficl kind f2constant desc.
f2drop ( -- ) ficl kind f2drop desc.
f2dup ( -- ) ficl kind f2dup desc.
f2over ( -- ) ficl kind f2over desc.
f2swap ( -- ) ficl kind f2swap desc.
f2value ( -- ) ficl kind f2value desc.
f< ( -- ) ficl kind mnum desc.
f= ( -- ) ficl kind desc.
f> ( -- ) ficl kind f> desc.
f?dup ( -- ) ficl kind f?dup desc.
f@ ( -- ) ficl kind f@ desc.
fallthrough ( -- ) ficl kind fallthrough desc.
false ( -- ) ficl kind false desc.
fconstant ( -- ) ficl kind fconstant desc.
fdepth ( -- ) ficl kind fdepth desc.
fdrop ( -- ) ficl kind fdrop desc.
fdup ( -- ) ficl kind fdup desc.
fe. ( -- ) ficl kind fe. desc.
ficl-named-wordlist ( hash-size name -- ) ficl : ficl-named-wordlist \ ( hash-size name -- ) run: ( -- wid ) ficl-wordlist dup create , brand-wordlist does> @ ; ficl-named-wordlist ficl独自: ワードリストの名前を取り、その名前を wid としてプッシュするワードを作成します。
ficl-set-current ( wid -- old-wid ) ficl : ficl-set-current ( wid -- old-wid ) get-current swap set-current ; ficl-set-current ficl独自: wid をコンパイルワードリストとして設定し、以前のコンパイルワードリストをスタックに残します。
ficl-vocabulary ( nBins "name" -- ) ficl : ficl-vocabulary ( nBuckets name -- ) ficl-named-wordlist do-vocabulary ; ficl-vocabulary ficl独自: 指定されたハッシュテーブルのビン数で ficl-wordlist を作成し、名前にバインドし、その名前に語彙のセマンティクスを関連付けます。
ficl-wordlist ( nBins -- wid ) ficl primitive ficl-wordlist ficl独自: 指定されたハッシュテーブルのビン数でワードリストを作成し、そのワードリストのアドレスをスタックに残します。
ficlInstruction0 ( -- ) ficl kind ficlInstruction0 desc.
ficlInstruction1 ( -- ) ficl kind ficlInstruction1 desc.
ficlInstruction10 ( -- ) ficl kind ficlInstruction10 desc.
ficlInstruction11 ( -- ) ficl kind ficlInstruction11 desc.
ficlInstruction12 ( -- ) ficl kind ficlInstruction12 desc.
ficlInstruction13 ( -- ) ficl kind ficlInstruction13 desc.
ficlInstruction14 ( -- ) ficl kind ficlInstruction14 desc.
ficlInstruction15 ( -- ) ficl kind ficlInstruction15 desc.
ficlInstruction16 ( -- ) ficl kind ficlInstruction16 desc.
ficlInstruction2 ( -- ) ficl kind ficlInstruction2 desc.
ficlInstruction3 ( -- ) ficl kind ficlInstruction3 desc.
ficlInstruction4 ( -- ) ficl kind ficlInstruction4 desc.
ficlInstruction5 ( -- ) ficl kind ficlInstruction5 desc.
ficlInstruction6 ( -- ) ficl kind ficlInstruction6 desc.
ficlInstruction7 ( -- ) ficl kind ficlInstruction7 desc.
ficlInstruction8 ( -- ) ficl kind ficlInstruction8 desc.
ficlInstruction9 ( -- ) ficl kind ficlInstruction9 desc.
ficlInstructionExitInnerLoop ( -- ) ficl kind ficlInstructionExitInnerLoop desc.
ficlInstructionF0 ( -- ) ficl kind ficlInstructionF0 desc.
ficlInstructionF1 ( -- ) ficl kind ficlInstructionF1 desc.
ficlInstructionFNeg1 ( -- ) ficl kind ficlInstructionFNeg1 desc.
ficlInstructionInvalid ( -- ) ficl kind ficlInstructionInvalid desc.
ficlInstructionNeg1 ( -- ) ficl kind ficlInstructionNeg1 desc.
ficlInstructionNeg10 ( -- ) ficl kind ficlInstructionNeg10 desc.
ficlInstructionNeg11 ( -- ) ficl kind ficlInstructionNeg11 desc.
ficlInstructionNeg12 ( -- ) ficl kind ficlInstructionNeg12 desc.
ficlInstructionNeg13 ( -- ) ficl kind ficlInstructionNeg13 desc.
ficlInstructionNeg14 ( -- ) ficl kind ficlInstructionNeg14 desc.
ficlInstructionNeg15 ( -- ) ficl kind ficlInstructionNeg15 desc.
ficlInstructionNeg16 ( -- ) ficl kind ficlInstructionNeg16 desc.
ficlInstructionNeg2 ( -- ) ficl kind ficlInstructionNeg2 desc.
ficlInstructionNeg3 ( -- ) ficl kind ficlInstructionNeg3 desc.
ficlInstructionNeg4 ( -- ) ficl kind ficlInstructionNeg4 desc.
ficlInstructionNeg5 ( -- ) ficl kind ficlInstructionNeg5 desc.
ficlInstructionNeg6 ( -- ) ficl kind ficlInstructionNeg6 desc.
ficlInstructionNeg7 ( -- ) ficl kind ficlInstructionNeg7 desc.
ficlInstructionNeg8 ( -- ) ficl kind ficlInstructionNeg8 desc.
ficlInstructionNeg9 ( -- ) ficl kind ficlInstructionNeg9 desc.
file-position ( -- ) ficl kind file-position desc.
file-size ( -- ) ficl kind file-size desc.
file-status ( -- ) ficl kind file-status desc.
fill ( -- ) ficl kind fill desc.
find ( -- ) ficl kind find desc.
fliteral ( -- ) ficl kind fliteral desc.
float> ( -- ) ficl kind float> desc.
float>int ( -- ) ficl kind float>int desc.
flush-file ( -- ) ficl kind flush-file desc.
fm/mod ( -- ) ficl kind fm/mod desc.
fnegate ( -- ) ficl kind fnegate desc.
forget ( -- ) ficl kind forget desc.
forget-wid ( wid -- ) ficl primitive forget-wid ficl独自: 指定されたワードリストを反復処理し、その xt アドレスが HERE、つまり辞書のフィルポインタの値以上のすべての定義をアンリンクします。
forth ( -- ) ficl kind forth desc.
forth-wordlist ( -- ) ficl kind forth-wordlist desc.
fover ( -- ) ficl kind fover desc.
fpick ( -- ) ficl kind fpick desc.
free ( -- ) ficl kind free desc.
froll ( -- ) ficl kind froll desc.
frot ( -- ) ficl kind frot desc.
fsqrt ( -- ) ficl kind fsqrt desc.
fswap ( -- ) ficl kind fswap desc.
fvalue ( -- ) ficl kind fvalue desc.
get-current ( -- ) ficl kind get-current desc.
get-order ( -- ) ficl kind get-order desc.
hash ( -- ) ficl kind hash desc.
here ( -- ) ficl kind here desc.
hex ( -- ) ficl kind hex desc.
hidden ( -- wid ) ficl primitive hidden ficl独自: ficl が提供する単語の実装要因を格納するためのワードリストです。
hide ( -- current-wid-was ) ficl : hide hidden dup >search ficl-set-current ; hide ficl独自: 隠されたワードリストを検索順序にプッシュし、それを現在のコンパイルワードリストとして設定します(ficl-set-current を使用)。
hold ( -- ) ficl kind hold desc.
i ( -- ) ficl kind i desc.
i-f ( -- ) ficl kind i-f desc.
i/f ( -- ) ficl kind i/f desc.
if ( -- ) ficl kind if desc.
immediate ( -- ) ficl kind immediate desc.
include ( -- ) ficl kind include desc.
include-file ( -- ) ficl kind include-file desc.
included ( -- ) ficl kind included desc.
int>float ( -- ) ficl kind int>float desc.
interpret ( -- ) ficl kind interpret desc.
invert ( -- ) ficl kind invert desc.
j ( -- ) ficl kind j desc.
k ( -- ) ficl kind k desc.
last-word ( -- ) ficl kind last-word desc.
leave ( -- ) ficl kind leave desc.
literal ( -- ) ficl kind literal desc.
load ( -- ) ficl kind load desc.
local ( -- ) ficl kind local desc.
locals| ( -- ) ficl kind desc.
lookup ( -- ) ficl kind lookup desc.
loop ( -- ) ficl kind loop desc.
lshift ( -- ) ficl kind lshift desc.
m* ( -- ) ficl kind m* desc.
marker ( -- ) ficl kind marker desc.
max ( -- ) ficl kind max desc.
min ( -- ) ficl kind min desc.
mod ( -- ) ficl kind mod desc.
move ( -- ) ficl kind move desc.
nUser ( -- ) ficl kind nUser desc.
negate ( -- ) ficl kind negate desc.
nip ( -- ) ficl kind nip desc.
objectify ( -- ) ficl kind objectify desc.
of ( -- ) ficl kind of desc.
on-step ( -- ) ficl kind on-step desc.
only ( -- ) ficl kind only desc.
oo ( -- ) ficl kind oo desc.
oop ( -- ) ficl kind oop desc.
open-file ( -- ) ficl kind open-file desc.
or ( -- ) ficl kind or desc.
order ( -- ) ficl kind order desc.
over ( -- ) ficl kind over desc.
pad ( -- ) ficl kind pad desc.
parse ( -- ) ficl kind parse desc.
parse-order ( -- ) ficl primitive parse-order パースステップのリストを呼び出される順序で表示
parse-word ( -- ) ficl kind parse-word desc.
pick ( -- ) ficl kind pick desc.
postpone ( -- ) ficl kind postpone desc.
previous ( -- ) ficl kind previous desc.
pwd ( -- ) ficl kind pwd desc.
q! ( -- ) ficl kind q! desc.
q@ ( -- ) ficl kind q@ desc.
quit ( -- ) ficl kind quit desc.
r.s ( -- ) ficl kind r.s desc.
r/o ( -- ) ficl kind r/o desc.
r/w ( -- ) ficl kind r/w desc.
r> ( -- ) ficl kind r> desc.
r@ ( -- ) ficl kind r@ desc.
random ( -- ) ficl kind random desc.
read-file ( -- ) ficl kind read-file desc.
read-line ( -- ) ficl kind read-line desc.
recurse ( -- ) ficl kind recurse desc.
refill ( -- ) ficl kind refill desc.
rename-file ( -- ) ficl kind rename-file desc.
repeat ( -- ) ficl kind repeat desc.
reposition-file ( -- ) ficl kind reposition-file desc.
resize ( -- ) ficl kind resize desc.
resize-file ( -- ) ficl kind resize-file desc.
roll ( -- ) ficl kind roll desc.
rot ( -- ) ficl kind rot desc.
rshift ( -- ) ficl kind rshift desc.
s" ( -- ) ficl kind s" desc.
s>d ( -- ) ficl kind s>d desc.
save-current ( -- ) ficl kind save-current desc.
search-wordlist ( -- ) ficl kind search-wordlist desc.
search> ( -- wid ) ficl primitive search> ficl独自: search order から wid をポップします。
see ( -- ) ficl kind see desc.
see-xt ( -- ) ficl kind see-xt desc.
seed-random ( -- ) ficl kind seed-random desc.
set-current ( -- ) ficl kind set-current desc.
set-order ( -- ) ficl kind set-order desc.
sfind ( -- ) ficl kind sfind desc.
show-prefixes ( -- ) ficl : show-prefixes <prefixes> >search words search> drop ; show-prefixes すべてのプレフィックスのリストを表示。各プレフィックスは、トークンの先頭でその名前が見つかった場合に実行されるFiclワード。
sign ( -- ) ficl kind sign desc.
sliteral ( -- ) ficl kind sliteral desc.
sm/rem ( -- ) ficl kind sm/rem desc.
source ( -- ) ficl kind source desc.
source-id ( -- ) ficl kind source-id desc.
space ( -- ) ficl kind space desc.
spaces ( -- ) ficl kind spaces desc.
span ( -- ) ficl kind span desc.
spewhash ( -- ) ficl kind spewhash desc.
sprintf ( -- ) ficl kind sprintf desc.
start-prefixes ( -- ) ficl : start-prefixes get-current save-current ! <prefixes> set-current ; start-prefixes プレフィックス定義の開始を宣言し、Ficl仮想マシンに<prefixes>ワードリストにコンパイルするように指示する。
state ( -- ) ficl kind state desc.
step-break ( -- ) ficl kind step-break desc.
strcat ( -- ) ficl kind strcat desc.
strcpy ( -- ) ficl kind strcpy desc.
strdup ( -- ) ficl kind strdup desc.
strlen ( -- ) ficl kind strlen desc.
swap ( -- ) ficl kind swap desc.
system ( -- ) ficl kind system desc.
then ( -- ) ficl kind then desc.
throw ( -- ) ficl kind throw desc.
to ( -- ) ficl kind to desc.
true ( -- ) ficl kind true desc.
tuck ( -- ) ficl kind tuck desc.
type ( -- ) ficl kind type desc.
u. ( -- ) ficl kind u. desc.
u< ( -- ) ficl kind mnum desc.
um* ( -- ) ficl kind um* desc.
um/mod ( -- ) ficl kind um/mod desc.
unloop ( -- ) ficl kind unloop desc.
until ( -- ) ficl kind until desc.
user ( -- ) ficl kind user desc.
value ( -- ) ficl kind value desc.
variable ( -- ) ficl kind variable desc.
vocabulary ( -- ) ficl kind vocabulary desc.
w! ( -- ) ficl kind w! desc.
w/o ( -- ) ficl kind w/o desc.
w@ ( -- ) ficl kind w@ desc.
while ( -- ) ficl kind while desc.
wid-get-name ( wid -- c-addr u ) ficl primitive wid-get-name ficl独自: Ficl ワードリスト(2.05 以降)には、割り当てることができる名前のプロパティがあります。これは ORDER によって検索順序のワードリストの名前をリストするために使用されます。
wid-set-name ( c-addr wid -- ) ficl primitive wid-set-name ficl独自: Ficl ワードリスト(2.05 以降)には、割り当てることができる名前のプロパティがあります。この名前は、\0 で終了する文字列(C スタイル)と仮定されます。これは簡便に Ficl が単語名を格納する方法です。
wid-set-super ( wid -- ) ficl primitive wid-set-super ficl独自: Ficl ワードリストには、標準 Forth で指定されていない親ワードリストポインタがあります。Ficl は通常、ワードリストを作成するときにこのポインタを NULL に初期化しますので、通常は効果がありません。このワードは、スタックのトップに指定されたワードリストへの親ポインタを設定します。icl の search-wordlist の実装は、検索時にワードリストの親リンクを逆にたどります
within ( -- ) ficl kind within desc.
word ( -- ) ficl kind word desc.
wordlist ( -- ) ficl kind wordlist desc.
words ( -- ) ficl kind words desc.
write-file ( -- ) ficl kind write-file desc.
write-line ( -- ) ficl kind write-line desc.
x. ( -- ) ficl kind x. desc.
xor ( -- ) ficl kind xor desc.
{ ( -- ) ficl kind { desc.
{{ ( -- ) ficl kind {{}} desc.

サンプルコード集 編集

関連情報(書籍、Web サイトなど) 編集

脚註 編集

  1. ^ 1.0 1.1 ficl standards compliance