Retro 言語

作者: Charles Childers
バージョン: 10.3 (20091212)

セクション 1: Retro へようこそ

はじめに

Retro は Forth の小さな、ミニマリスト指向の方言です。

Retro 言語には、1998 年に x86 PC 用の 16 ビットスタンドアロン Forth として初めてリリースされて以来の長い歴史があります。その時から、Ngaro と呼ばれるポータブルな仮想マシン上で動く 32 ビット実装となった現在の形へ至るまで、実際の利用を通じて進化してきました (訳注: 仕様の複雑化による根底的な再構築を何度か経ている)。現在、Retro は主要 OS すべてで動かすことができ、また仮想マシンの JavaScript 実装により、現代的などのブラウザ上でも動かせます (訳注: Ver10 以降、明らかにポータビリティ最大化の方向へと舵が切られており、高速バイナリ版など、それに反するようなものは本家にはあまり期待できなくなっているように思われる (ちなみに FASM 記述の旧版は、Reva よりは遅いが Gforth よりは速い実装だった。現在の、主に C 記述版は、MinForth や Ficl よりちょっと速い程度である)。Ngaro は美しさすら感じるほどにシンプルな仮想マシンなので (GNU 式インデントの Java 版で 430 行しかない、C# 版丸写しのけっこう手抜きな実装だが)、高速版やプラットフォーム依存度の高い機能などは、本家を待つよりも自分で実装してしまった方が速いだろう (本家には意表を突いて Elisp 版があったりする)。なお、JavaScript 実装は Windows の Internet Explorer には未対応である)。

Retro のコードとドキュメントはオープンソースライセンスの元で配布されています (訳注: 以前はパブリックドメインだったが、Ver10 からは ISC (OpenBSD) ライセンスへ移行)。

このドキュメントは、Retro 言語自体のみをカバーします (訳注: この言語自体には、倍長整数、浮動小数点数、ファイル I/O と共有ライブラリ呼び出しの機能は「ない」。Reva や FreeForth を見れば前二者は Forth で作れるようだが、後二者は Ngaro の拡張 (入出力ポートや命令が追加しやすい構造になっている) を要すると思う)。仮想マシンとライブラリについては、別のドキュメントでカバーされます (訳注: 仮想マシンのドキュメントは上の方のリンクを参照。ライブラリのドキュメントは、このマニュアル現在の時点ではまだない)。

セクション 2: 使い始めるまで

入手

Retro は http://retroforth.org からダウンロードできます。

Retro 言語は、retroImage (単に "イメージ" とも) と呼ばれる単一のファイルに、メモリイメージのスナップショットとして保持されています (訳注: Ngaro 上の仮想メモリを表す int の配列を単純にファイル保存しただけのバイナリファイルなので、C の配列表現などに変換してリンクすれば、Ngaro の方をほんの少し書き換えるだけで単一の実行ファイルにすることもたやすい。現に、JavaScript 版ではこの方法論が使われている)。

普通は retroforth.org で配布されているイメージファイルで十分ですが、この基本セットをカスタマイズしたい場合は、ソースファイルから新たなイメージファイルをビルドできます。

新しいイメージファイルをビルドするには、自分の OS と CPU 用の Ngaro 仮想マシンが必要です。また、最新の Retro イメージファイル (retroImage) も必要となるでしょう。仮想マシンはパスが通る場所に置き、retroImage は現在の作業ディレクトリに入れておいてください。

最新の変更に追随したい開発者の方は Git を利用してください。常に最新のリポジトリは http://github.com/crcx/retro10 です。

ソースからビルドする (Unix 系ホストマシンの場合)

イメージを一からビルドしたい場合は、BSD、Linux や OS X などの Unix 系 OS で次のツールを使う必要があります (訳注: 30 行程度の非常にシンプルな Makefile なので、プログラムのビルドに手慣れた人なら、Ngaro さえ動けばどの環境でもビルドできるはずである)。

  • Make
  • Ngaro 仮想マシン

その上で Makefile を編集して、1 行目が用意した Ngaro 仮想マシンを指すように修正してから make を起動します。

make

これで、新しい retroImage が作成できるはずです。

Retro との対話

おおかたの Forth 処理系と異なり、Retro は行単位のバッファリングをしていません。入力を打ち込むそばから解析し (訳注: 英字の大小は区別される)、スペースキーを打った時点でワードを実行します。

ほかの Forth 処理系経験者はこの点で大いに困惑するようなので注意してください。デフォルトの Retro 処理系では、スペースだけが正しいワード区切りとして認識されることを忘れないようにしてください。

なおデフォルトではまた、CR、LF、およびタブもスペースを意味するものとして変換されます。この変換を抑制するには、次のように打ち込んでください。

whitespace off

元に戻すには、

whitespace on

Retro の終了

単に bye と打ち込んでスペースを打つだけです (訳注: 上で示される変換により、デフォルトではスペースの代わりに改行でも可)。

イメージ

Retro 言語はイメージファイルに保存されています。Retro の起動時に、仮想マシンは retroImage ファイルを探します (訳注: 起動時のオプションは Ngaro の実装によるが、標準的なものはコンソール版で --help するか、または vm/console/ngaro.c を読めば分かる。ここでは、単純なファイル名はイメージファイルと見なされ、--with ファイル名 でソースファイルが読み込める (複数可、後に指定された方からそれより前に指定されたものへと順に実行)、とだけ記しておく。なお、Ngaro の実装によっては、作成された retroImage の実行だけができるような、Java の JRE のような実行環境のみのものもある)。見つからない場合は、代わりに仮想マシンに組み込みの最小イメージを使用します (訳注: このマニュアル現在、どの仮想マシン実装も最小イメージは組み込んでおらず、従って見つからない場合はエラーメッセージとともに終了する)。

ワード save により、現在実行中の Retro セッションを retroImage に保存して、後で再ロードすることができます。そのセッションで作成したすべてのワードと変数が保存されるので、わざわざそれらをソースファイルから再ロードしたり打ち込みなおしたりしなくても作業を継続できます (訳注: デフォルトでは、Ngaro の仮想メモリすべてをそのまま保存するので、19MB を超えるサイズになるが、代わりにブロック内のデータなどもそのまま保存される。Ngaro の実装にもよるが、--shrink 指定で起動しておけば、定義を追加した辞書のみ (より正確には変数 heap の現在値まで) を保存することでサイズを縮小できる)。

また、Retro のベクタ機能を使って、既存のワードのほとんどを必要に応じて別の定義内容に差し替えられます。

セクション 3: 実装

概要

Retro は Forth 標準には準拠していません。むしろ、多くの部分で非常に異なってすらいます。このセクションでは、そのような異なる部分について説明するとともに、Retro 内部の動作についても示します。

数珠つなぎコードの仕組み

Retro では、Ngaro マシンコードをインライン化したサブルーチン式数珠つなぎコードによりワード同士が連結されます。この仕組みは簡潔であり、また必要なときにコンパイラで最適化できるので、2001 年以降 Retro はこの方式を採用しています。

Retro が生成するサブルーチン式数珠つなぎコードは、具体的には次のようなものです。

: foo 1 2 + . ;

は次の Ngaro コードにコンパイルされます (訳注: . はスタックトップを表示するワード (ここではそのアドレスを意味する))。

lit 1
lit 2
+
call .
;

Retro コンパイラでは、call/return のオーバーヘッドを避けるために、単純な命令を生成するような単純な演算はインライン化できます。その他の最適化ももちろん可能です。

インタプリタとコンパイラ

Retro におけるインタプリタのメインループは非常に単純です。

: listen  ( - )
  repeat ok 32 # accept search word? number? again ;

プロンプト (ok) を表示し、スペース (ASCII 32) が打ち込まれるまでの入力を受け付けます。辞書を検索して該当するワードを見つければ、word? でそのワードのクラスハンドラを呼び出します。該当するワードが見つからなければ、number? で数値への変換を試みます。これも失敗した場合はエラーを表示します。いずれの場合でも、重大なエラーが発生するか、またはユーザーが bye を呼び出すまで、このループが繰り返されます。

これとは別のコンパイル過程というものは存在しません。Retro での compiler は、ワードクラスに従ってワードの振る舞いを決定する際に参照される状態変数以外の何物でもありません。

ワードクラス

上でも触れたように、インタプリタのメインループ (listen) は、析出したワード (や数値などのデータ要素) の解釈をワードクラスというものに委ねます。

この仕組みは、標準 Forth には見られない、Retro の実装に固有のものです (訳注: Retro の影響下にあるミニマリスト系 Forth の特徴と言ってよい)。Helmar Wodtke によるこのワードクラス方式は、ワードにおける異なるタイプの振る舞いを特別なワード (クラスハンドラ) だけで処理できるようにしたもので、これによりインタプリタとコンパイラの仕組みが極めて簡潔なものとなりました。

すなわち、インタプリタのメインループが、ワードの種類や言語システムの状態を自ら考慮する必要がなくなったのです。

標準の Retro 言語には、4 つのクラスが定義されています (訳注: このバージョンでは、さらに .primitive というクラスも追加されている。単一の Ngaro 命令コードをそのまま呼び出しているだけのワードをインラインコンパイルするためのものである)。

名前 データスタック アドレススタック
.word a - -
インタプリタ時ならそのワードを呼び出す。コンパイル時ならそのワード呼び出しを現在の定義へ繰り込む。
.macro a - -
常にそのワードを呼び出す。普通、コンパイル時に自身のコードを作成するワードや、コンパイル時に普通のワードとは異なる動作をするワードをこのクラスにする (訳注: 普通、定義内でのみ使える)。
.compiler a - -
compiler が on ならそのワードを呼び出す。compiler が off の場合は何もしない。
.data a - -
インタプリタ時ならスタックにワード a のデータ領域のアドレスを積む。コンパイル時ならそのアドレスをリテラルとしてスタックに積むコードを現在の定義へ繰り込む。

これら 4 つのクラスに加えて、ユーザー定義のクラスも作成できます。例として、文字列を命名し表示するクラスを作成してみましょう。このクラスのワードは次のように振る舞います。

  • インタプリタ時ならその文字列を表示する
  • コンパイル時ならその文字列を表示するコードを現在の定義へ繰り込む

Retro の規約では、クラス名の最初の文字は . とすることになっています。この規約に従い、新しいクラスの名前は .string とします。

ヒント:
クラスが呼び出されるとき、対象となるワードまたは構造データのアドレスがスタックに積まれます。また、compiler という名前の変数にコンパイラの状態が保持されています (たいていのクラスでは、この値を調べる必要があるはずです)。

最初はとりあえず、クラス定義全体の構造を大まかに決めます。コンパイル時に自身のコードを生成する必要があるので、このクラスハンドラは大きく二つの部分から構成されることになります。

: .string  ( a—)
  compiler @ 0 =if ( インタプリタ時 ) ;; then ( コンパイル時 )
;

まずはインタプリタ時の動作から始めましょう。その場合、このクラスは単に文字列オブジェクトを表示するだけなので、type だけで済ませることができます。

: .string ( a — )
  compiler @ 0 =if type ;; then ( コンパイル時 ) ;

コンパイル時の動作はずっと複雑なものになります。該当する文字列のアドレスをワードの実行時にスタックに積むような Ngaro のマシンコードと、type 呼び出しとを現在コンパイルされている定義へ繰り込む必要があります。Ngaro の命令セットから、スタックに値を積む命令コードはコード値 1 であることがわかります。このコード値は、自分の次のメモリ位置にある要素を値としてスタックに積みます。従って、コンパイル時動作の最初の部分は次のようになります (訳注: 2 つめの , は、a , の意味)。

: .string ( a — )
  compiler @ 0 =if type ;; then 1 , , ;
ヒント:
メモリに値を直接配置するには , を使います。Retro のコンパイラ自身も、この操作を用いて最終的な Ngaro コードを生成します。

あともう一歩です。コンパイルされる定義へ type 呼び出しを繰り込むようにしなければなりません。これは、type のアドレスを compile に渡すようにすれば実現できます。

: .string ( a — )
  compiler @ 0 =if type ;; then 1 , , ['] type compile ;

こうして、新しいクラスハンドラが完成しました。ところで、この新しいクラスはどう使えばよいのでしょうか。

ヒント:
create により、辞書に新たなエントリ (訳注: この用語はワードにほぼ等しい) を作成できます。対応する辞書ヘッダー内の適切なフィールドにアクセスすることで、作成されたエントリにクラスを設定できます。d-> で始まるワードにより、辞書ヘッダー内のフィールドにアクセスできます。
: displayString: ( $"名前" — )
  create ['] .string reclass keepString last @ d->xt ! ;

この定義では、create によりその "名前" で新たなワードが作成され (訳注: この "名前" は、実行時に displayString: の次にあるワードがそれと見なされる)、そのクラスが .string に設定 (訳注: reclass の動作) されてから、対象文字列 $ (その文字列のアドレス) がこのワードの xt (訳注: xt は、ワードを実行する際のジャンプ先アドレスを意味する Forth 用語) に設定されます。keepString は、文字列が捨てられないようにするためのものです。last は、最後に作成された辞書エントリ (訳注: この場合は定義冒頭の create で作成されたもの) を指す変数です。ワード d->classd->xt、および d->name は辞書フィールドアクセサで、辞書の実装を問わずにそのフィールドへアクセスできるようにするものです。

では、新しいクラスをテストしてみましょう。

" hello, world!" displayString: hello
hello
: foo hello cr ;
foo

ベクタ

ベクタは、Retro におけるもう一つの重要概念です。

たいていの Forth 処理系では、動作を後から定義できるワードが作れるようになっています。Retro ではさらに進んで、: で定義されたどのワードでも再定義できるようにしました。この、再定義可能なワードのことを、ベクタと呼びます (訳注: 既にコンパイルされたそのワード呼び出しも、再定義された方を用いるようになる (動的スコープ)。ベクタでない単純な同名再定義では、既にコンパイルされたそのワード (名) 呼び出しは影響を受けない (静的スコープ))。

ベクタは is で再定義でき、また devector で本来の定義へ戻せます。例えば、

: foo 23 . ;
foo
: bar 99 . ;
' bar is foo
foo
devector foo
foo

isdevector には、ワード名を析出する代わりにワードのアドレスを取る姉妹ワードもあります。:is:devector がそれです。

I/O デバイス

Retro はポータブルな仮想マシン上で動いています。この仮想マシンは、アクセス可能な仮想 I/O デバイスもいくつか持っています。

  • キーボード
  • テキスト表示端末
  • グラフィック用キャンバス
  • マウス

なお、現時点でキャンバスとマウスが使用可能なのは javascript 実装だけです。

仮想 I/O デバイスへデータを送るときは、以下の説明に従ってスタックをセットし、それから out を使ってポートへ値を書き込みます。デバイスにもよりますが、read を使って値を読み込む前に、wait でデバイスが応答可能になるまで待つ必要があります。

ポート 送る値 スタック変化
0 0 -
I/O リクエストの発生をコンピュータへ伝える。普通はラッパーワードである wait を使うようにする
1 1 -
キーが押されるのを待つ。押されたキーの値を得るには、wait の後でこのポートから読み込む
2 1 c-
文字を表示する。その文字をスタックに積んでから wait を呼び出す
3 0 -
0 を送ると画面が強制更新される。wait は不要である
4 1 -
イメージを保存する
5 下記参照 -

環境問い合わせポート。各イメージはこれを使って仮想マシンがサポートする機器を調べる。

以下のいずれか 1 つを送り、wait してから結果を読み込む。

  • -1 : イメージ用メモリの可能な最大の大きさ
  • -2 : キャンバスが利用不可なら 0、可能なら -1
  • -3 : キャンバスの幅
  • -4 : キャンバスの高さ
  • -5 : スタックの現在の深さ
  • -6 : リターンスタックの現在の深さ
  • -7 : マウスが利用不可なら 0、可能なら -1
6 下記参照 下記参照

キャンバス表示用ドライバ。さまざまな操作が可能。

  • 1 : n- : 色の設定
  • 2 : xy- : ピクセルに色を置く
  • 3 : xyhw- : 四角い枠組み描き込み
  • 4 : xyhw- : 四角形塗り潰し
  • 5 : xyh- : 垂直線描き込み
  • 6 : xyw- : 水平線描き込み
  • 7 : xyw- : 丸い枠描き込み
  • 8 : xyw- : 円形塗り潰し
7 下記参照 下記参照

マウスデバイス。

  • 1 : -xy : マウスの x と y 座標を取得
  • 2 : -f : 主ボタンの上下状態を示すフラグを取得

セクション 4: ワード一覧

スタックコメントの読み方

Retro におけるスタックコメントは、実際のワードの代わりに短縮コードを用いたコンパクトなものになっています。短縮コードの一覧はこの節の最後にあります。

引数を 2 つ取って値を 1 つ返すワードの典型的なスタックコメントは次のものです。

( xy-z )

取る個数や返す個数が一定でないワードもありえます。そのようなワードのスタックコメントは、私たちは次のように記述しています。

( n-n || n- ) (訳注: n-n または n- の意味)

このほか、修飾子を 2 つ使っています。ワードの中には、コンパイル時と実行時とでスタックの使い方が異なるものもあります。これを表すため、コンパイル時なら C:、実行時なら R: をスタックコメントに接頭しています。

これらがない場合には、スタックコメントは実行時の変化を表しています。C: がスタックコメントにないワードは、コンパイル時にスタックを変更しないと見なせるからです。

スタックコメントで用いられている短縮コード:

x, y, z, n 一般的な数値
q, r 商 (Quotient), 余り (Remainder) (除算用)
" * 文字列を析出するワード (訳注: * は任意の文字列)
a アドレス
c ASCII 文字
$ 0 終端文字列 (訳注: の先頭アドレス)
f フラグ (訳注: 論理値を指す Forth 用語)
... 任意の個数のスタック要素

ワード一覧

名前 クラス データスタック アドレススタック
!+ .word na-a  
値をアドレスの場所へ保存し、次のアドレスを返す
! .primitive na-  
値 n をアドレス a の場所へ保存する
!if .macro C: -a R: nn-  
2 つの数値が等しいなら then など (コンパイル時に !if の a を受け取るワード) へ飛ぶ
" .word "-$  
" に遭遇するまでを析出し、文字列にして返す
#-blocks .data -a  
現在の総ブロック数を保持する (訳注: ブロックは、組み込みラインエディタの編集単位 (普通ほぼ 1 画面分) を指す Forth 用語である)
#mem .data -a  
イメージ用メモリの可能な最大の大きさを保持する。Retro イメージが普通取得できる範囲外にあるフレームバッファ用メモリを含む場合がある
' .word "-a  
ワード名を析出してそのワードのアドレスを返す。定義内では代わりに ['] を使うこと
( .macro "-  
) と遭遇するまで析出し、析出された文字列を捨てる。コメント記述に用いられる
テキスト出力用の Y 座標は保持される (フレームバッファ利用時のみ)
(block) .word -a  
現在のブロックのアドレスを返す
(ia) .word cl"-  
ia のデフォルト定義
(line) .word n-a  
現在のブロックの n 行目のアドレスを返す
(remap-keys) .word c-c  
不適切なキーレイアウトの適正化処理用ハンドラ。key により呼び出される
(v) .word    
v のデフォルト定義
* .primitive xy-z  
x に y を掛ける
+! .word na-  
アドレス a の内容値を n だけ増やす
++ .word a-  
アドレス a の内容値を 1 つだけ増やす
+ .primitive xy-z  
x と y を足す
, .word n-  
heap の空き領域先頭アドレスの場所に値 n を保存する (訳注: この結果として、here はこの次のアドレスを指すようになる)
-! .word na-  
アドレス a の内容値を n だけ減らす
---reveal--- .word    
混合名前空間内で、以降の定義の所属先をグローバル名前空間に切り替える
-- .word a-  
アドレス a の内容値を 1 つだけ減らす
- .primitive xy-z  
x から y を引く
-rot .word xyz-zxy  
二度 rot する (訳注: スタックコメントからわかるように、z を x の下へ移す)
. .word n-  
n を数値として表示する
." .macro "-  
" に遭遇するまでを析出し、文字列として表示する。コンパイル時は、その文字列を表示するコードを現在の定義へ繰り込む
.compiler .word a-  
定義内でのみ使用可能なワード用クラスハンドラ
.data .word n-  
データ要素用クラスハンドラ
.does .word a-  
does> 用クラスハンドラ
.macro .word a-  
マクロ用クラスハンドラ
.primitive .word a-  
Ngaro 命令コードに等しいいわゆるプリミティブワード用クラスハンドラ
.word .word a-  
通常ワード用クラスハンドラ
/ .word xy-q  
x を y で除算をして商 q を返す
/mod .primitive xy-rq  
x を y で割り、余り r と商 q を返す (訳注: 商がスタックトップに来る。余りは C や Java のそれで、Scheme での remainder の方)
0; .macro n- || n-n  
スタックトップの値が 0 なら、定義の実行を終了してスタックトップの要素 (訳注: その 0) を捨てる。さもなければ、スタックトップの要素を残し定義の実行も継続する。HerkForth 由来の軽量制御構造である
1+ .primitive x-y  
数値 x に 1 を足す
1- .primitive x-y  
数値 x から 1 を引く
2drop .word xy-  
スタックトップの要素 2 つを捨てる
2dup .word xy-xyxy  
スタックトップの要素 2 つを複製する
: .word "-  
クラス .word として新しいワードを作成し、compiler を on にする
:devector .word a-  
ワードの本来の定義を復元する。.data クラスの要素には使わないこと
:is .word aa-  
ワード (訳注: スタックトップの a) の定義を、別ワード (訳注: もうひとつの a) 呼び出しへと変更する。.data クラスの要素には使わないこと
;; .macro    
現在の定義を完結せずに、その定義からの脱出ポイントを繰り込む (訳注: C や Java における、関数・メソッド途中の return の類いの動作)
; .macro    
現在の定義を完結して compiler を off にする
;then .macro C: a-  
;; then と同じ
< .word nn-f  
2 つの n が等しいか、または最初の n が次の n より小さいなら -1、さもなければ 0 を返す (訳注: Retro の < は <= の意味であることに注意)
<< .primitive xy-z  
x を左 (訳注: より大きい桁方向) へ y ビット分シフトする
<> .word nn-f  
2 つの n が等しくなければ -1、さもなければ 0 を返す
<if .macro C: -a R: nn-  
< if と同じ (訳注: <if の方が高速。ほかの合成形も同様)
<list> .data -a  
ローカル名前空間管理用の内部配列
= .word nn-f  
2 つの n が等しいなら -1、さもなければ 0 を返す
=if .macro C: -a R: nn-  
= if と同じ
> .word nn-f  
2 つの n が等しいか、または最初の n が次の n より大きいなら -1、さもなければ 0 を返す (訳注: Retro の > は >= の意味であることに注意)
>> .primitive xy-z  
x を右 (訳注: より小さい桁方向) へ y ビット分シフトする (訳注: 符号ビットをコピーする算術右シフト。ただし C 版は C 処理系依存)
>if .macro C: -a R: nn-  
> if と同じ
>number .word $-n  
文字列を数値へ変換する
@+ .word a-an  
次のアドレスと、元のアドレスにある値のコピーとをスタックに積む
@ .primitive a-n  
アドレスにある値のコピーをスタックに積む
['] .macro C: "- R: -a  
ワード名を析出し、そのワードのアドレスをスタックに積むコードを現在の定義へ繰り込む
[ .macro    
現在の定義を完結せずに compiler を off にする
] .word    
compiler を on にする
` .macro "-  

以下の置換を行う (訳注: 析出したワードをそれ自身のクラスハンドラへ渡すコードを繰り込む)。

` ワード名  =  ['] ワード名 compile
` ワード名  =  ['] ワード名 execute (訳注: マクロの場合 )
` 数値    =  数値 literal,
accept .word c-  
文字 c に遭遇するまで入力を受け付ける。結果は tib に保存される
again .macro C: a-  
無条件ループの終点。最後の repeat へ戻る
allot .word n-  
n 要素分のデータ領域を確保する
and .primitive xy-z  
ビット単位 AND
base .data -a  
現在の基数を保持する (訳注: 入力や文字列の数値変換はこの基数に従う)
binary .word    
基数を二進に変更する
blk .data -a  
現在のブロック番号を保持する
block .word -a  
現在のブロックのアドレスを返す
boot .word    
ユーザー定義の起動コード用フック (訳注: ベクタ化して用いる)
bye .word    
Retro を終了する
clear .word    
画面をクリアする
compare .word $$-f  
2 つの文字列が等しいなら -1、さもなければ 0 を返す
compile-only .word    
最後に定義されたワードのクラスを .compiler にする
compile .word a-  
ワード a 呼び出しコードを現在の定義へ繰り込む
compiler .data -a  
コンパイラ状態を保持する。0 なら off、-1 なら on である
constant .word n"-  
値 n の定数を作成する
copy .word aan-  
コピー元 (訳注: 最初の a) からコピー先 (訳注: 次の a) へ n 要素分コピーする
cr .word    
改行文字を emit する
create .word "-  
クラス .data として新しい辞書ヘッダーを作成し、その xt を (訳注: 析出される名前の直後の) here の値にする (訳注: 要するに、その here の位置に名前をつける)
d->class .word a-a  
指定された辞書ヘッダーのクラスフィールドを返す
d->name .word a-a  
指定された辞書ヘッダーの名前フィールドを返す
d->xt .word a-a  
指定された辞書ヘッダーの (訳注: 自身の xt を保持する) アドレスフィールドを返す
d .word n-  
現在のブロックの n 行目を削除する
decimal .word    
基数を十進に変更する
depth .word -n  
スタックの現在の要素数を返す
devector .word "-  
ワード名を析出し、その名前のワードの本来の定義を復元する。.data クラスの要素には使わないこと
does> .does    
variable などの定義用ワードをユーザー定義する場合に、それで定義されたワードの実行時の動作をこれ以降に記述する。これより前の記述は、定義時の動作になる
drop .primitive xy-x  
スタックのトップ要素を捨てる
dup .primitive x-xx  
スタックトップの要素を複製する
e .word    
現在のブロックを実行する
emit .word c-  
画面に ASCII コードを出力する (訳注: 画面が標準出力に等しいかどうかは Ngaro の実装による)
eval .word $n-  
文字列の先頭 n 文字分を Retro コードと見なして実行する
execute .word a-  
アドレスが指すワードを呼び出す
FALSE .word -f  
0 を返す
fb .data -a  
キャンバス機器の存在を示すフラグを保持する
fh .data -a  
キャンバスの高さを保持する
fill .word ann-  
アドレス、値、個数を取り、アドレスから個数要素分のメモリを値で埋める
find .word $-af  
文字列をワード名とするワードを辞書から検索する。f が -1 なら、a はそのワードのヘッダーアドレスである
for .macro C: -a R: n-  
単純な回数指定ループを開始する。回数は実行時にスタックから取る
forget .word "-  
ワード名を析出し、そのワードを含めて以降に定義されたすべてのワードをメモリ上から削除する
fw .data -a  
キャンバスの幅を保持する
getLength .word $-n  
文字列の長さを返す
heap .data -a  
ヒープのトップアドレスを保持する。普通は、here を使ってこの値を取得する (訳注: heap は変数、here はワードであることに注意)
here .word -a  
heap の空き領域先頭アドレスを返す
hex .word    
基数を十六進に変更する (訳注: 小文字の a から f は十六進数表現と見なされないことに注意)
i .word n"-  
ブロックの n 行目 0 桁目にテキストを挿入する
ia .word cl"-  
ブロックの l 行目 c 桁目にテキストを挿入する
if .macro C: -a R: f-  
条件分岐の開始点。フラグが 0 なら then などへ飛ぶ
immediate .word    
最後に定義されたワードのクラスを .macro にする
in .primitive x-y  
スタックトップの要素が示す I/O ポートから値を 1 つ読み込みスタックトップに積む
is .word a"-  
名前を析出し、その名前のワードの定義を指定アドレス呼び出しへと変更する。.data クラスの要素には使わないこと
isNumber? .word $-f  
文字列が数値に変換可能なら -1、さもなければ 0 を返す
keepString .word $-$  
文字列を永久保存領域へ移動してそのアドレスを返す (訳注: 呼び出しごとに別の領域を確保する)
key .word -c  
キーボードから入力された ASCII コードを読み込む (訳注: キーボードが標準入力に等しいかどうかは Ngaro の実装による)
last .data -a  
最後の辞書ヘッダーのアドレスを保持する
later .word    
定義内の以降の記述は、その定義を呼び出した定義の実行が終了した後に実行される
line-ending .data -a  
i と ia における入力終了文字を保持する。デフォルトは LF
listen .word    
インタプリタのメインループ
literal, .word n-  
数値をスタックに積むコードを現在の定義へ繰り込む
mod .word xy-r  
x を y で除算をして余り r を返す (訳注: 余りは C や Java のそれで、Scheme での remainder の方)
n .word    
次のブロックへ進む
neg .word x-y  
x の符号を反転する
new .word    
すべてのブロックを削除する
next .macro C: a-  
単純な回数指定ループの終点。回数から 1 を引く。0 なら、現在の定義における次のワードへと実行を移す。さもなければ、最後の for へ戻る
nip .word xy-y  
スタックトップの下の要素を捨てる
not .word x-y  
論理 NOT (訳注: 全ビット反転)
notfound .word    
ワードが辞書内に発見できず、数値変換も失敗した場合に呼び出される (訳注: ベクタ化してユーザー定義の失敗時処理を組み込むためのもの)
octal .word    
基数を八進に変更する
off .word a-  
変数を 0 に設定する
offset .data -a  
ブロック用領域のアドレスを保持する
ok .word    
"ok" プロンプトを表示する
on .word a-  
変数を -1 に設定する
or .primitive xy-z  
ビット単位 OR
out .primitive xy-  
I/O ポート y へ値 x を 1 つ書き込む
over .word xy-xyx  
スタックトップの下の要素を複製する
p .word    
1 つ前のブロックに戻る
pop .macro R: -n R: n-
値をリターンスタックからデータスタックへ移す
pow .word bp-n  
b の p 乗を返す
push .macro R: n- R: -n
値をデータスタックからリターンスタックへ移す
r .macro -n  
リターンスタックトップのコピーを返す
reclass: .word a"-  
名前を析出し、その名前のワードのクラスを a にする
reclass .word a-  
最後に定義されたワードのクラスを a にする
redraw .word    
update が on なら画面を強制更新する。I/O 操作のパフォーマンス改善のために処理系内部で使用される
repeat .macro C: -a  
無条件ループの開始点
reset .word ...-  
スタックの全要素を捨てる
rot .word xyz-yzx  
スタックトップの要素 3 つを回す (訳注: スタックコメントからわかるように、x をスタックトップへ移す)
s" .macro C: "- R: -$  
" に遭遇するまでを析出する。析出された文字列を keepString を呼び出して永久保存領域へ移動し、その文字列のアドレスをスタックに積むコードを現在の定義へ繰り込む
s .word n-  
新しいブロックを選択する
save .word    
イメージをファイルとして保存する。仮想マシンが未対応の場合は何もしない
see .word "-  
ワードを Ngaro アセンブラ表記へと逆コンパイルする。ワード名を析出し、その名前の定義の終点検出を試みる。辞書内における次のワードの辞書ヘッダーも表示される可能性がある
set-blocks .word n-  
ブロック数を n に設定してから "new" を呼び出す
stub .word    
ベクタ化を用いた前方宣言用に、定義のないワード (正確には、nop nop だけを定義とするワード) を作成する
swap .primitive xy-yx  
スタックトップの要素 2 つを入れ替える
tempString .word $-$  
文字列を tib から一時保存領域へ移動してそのアドレスを返す (訳注: tempString は同じ領域を再利用するので、呼び出すごとに前の文字列は上書きされる)
then .macro C: a-  
条件分岐の終点
tib .data -a  
テキスト入力バッファ
TRUE .word -f  
-1 を返す
tuck .word xy-yxy  
スタックトップの要素をトップ下の要素の下へ複製する
type .word $-  
画面に文字列を表示する
update .data -a  
redraw が使用、パフォーマンス改善のための出力キャッシングを制御する。画面更新要素がないときは 0、あるときは -1 に設定される
v .word    
現在のブロックを表示する
variable: .word n"-  
初期値 n の変数を作成する
variable .word "-  
初期値 0 の変数を作成する
wait .word    
I/O イベントを待つ。普通 out の後に用いられる
which .data -a  
最後に検索された辞書ヘッダーのアドレスを保持する
whitespace .data -a  
CR、LF、およびタブをスペース文字と見なすかどうかを示すフラグ変数
with-class .word aa-  
アドレス (訳注: 最初の a) を、指定したクラスハンドラ (訳注: 次の、スタックトップの a) で呼び出す。統計トラッキングやデバッグでは、この一時変更は無視される可能性がある
within .word xul-f  
u<=x<=l なら -1、さもなければ 0 を返す (訳注: Forth の一般的な within とは異なることに注意)
words .word    
辞書内のすべてのワードを一覧表示する
x .word    
現在のブロックを削除する
xor .primitive xy-z  
ビット単位 XOR
{ .word    
ローカル名前空間を開始する (訳注: 4 レベルまで入れ子可能。この空間内の定義は、グローバル名前空間からは検索できなくなるが、辞書エントリ自体は残っている。一回限りの使い捨てなローカル名前空間の場合は、forget を使えばそのような辞書エントリ領域も再利用できる。なお、ANS Forth のいわゆるローカルとはまったくの別物である)
{{ .word    
混合名前空間を開始する (訳注: ---reveal--- と組み合わせていわゆるクロージャが作れるが、代わりに 1 レベルのみで入れ子にはできない)
} .word    
ローカル名前空間を閉じる
}} .word    
混合名前空間を閉じる