第8回（最終回） J3Wのアセンブラ
これまでJ3C言語を使ったプログラミングにと呼び、行の先頭部分にコロンを付けた名前をべているだけですね。「LOAD 」や「BLS 」とい関して解説してきましたが、最終回の今回はJ3W置いて、特定の場所（この場合 2 行目）に名前う命令（ニーモニック）さえ覚えてしまえば、のネイティブ言語である J3W アセンブリ言語を付けています。「OUTNUM R1」は J3C 言語の処理内容を日本語で箇条書きするのとあまりのプログラミングを簡単に解説します。

Number組み込み関数と同じで、R1の値を表示変わりません。

これまでにも、J3C言語のソースは、j3c コします。3 行目の「INC R1 」で R1 の値を 1 つマンドでコンパイル後、j3dasm でアセンブル増やし、4 行目の「CMP R1 10」は、され、j3w で実行されることは見てきました。

R1 の値を 10 と比較します。内部的コンパイル後に生成される J3W のアセンブリには「R1 − 10」を実行します。5 行言語とはいったいどんなものなのでしょうか。

■ J3C 言語と J3W のア
センブリ言語の比較【リスト 1】count1.j3c

目の「BLS label: 」は、直前の比較（演算）の結果が「小さい」ならclass main {int INIT() {volatile int i;

ば、ラベルの位置に分岐（この場合for (i=1; i<10; i=i+1) Number(i);Stop();2行目）します。R1の値が10以上のリスト1に示すコード count1.j3c は、これ場合は分岐しないで、6 行目のまで見てきた J3C 言語によるプログラムです。

「STPALL 」を実行して終了します。

実行すると、1 〜 9 までの数字を表示して終了どうですか？ 単に処理を順に並

リスト 3 をアセンブルすると生成される}
int RUN() {}int EVENT() {}}します。
この count1.j3c を j3c コマンドでコンパイルすると、count1.j3mというファイルが生成

j3w の内部構造の解説されます。count1.j3mは、テキストファイルで cat や less コマンドで内容を表示できます（ リ ス ト 2 ）。 こ れ を 見 る と 、 J 3 C 言 語 の■アセンブラ j3dasm

cScan::NextWord()が1単語ずつに分離してアセン

count1.j3cがコンパイルされて、count1.j3mのソースコードを2度読み込んで処理する2パスアセ

ブリソースを読み込みます。アセンブラは複数行にという J3W のアセンブリ言語のソースファインブラになっています。ソースコードを 1 度だけ読わたって処理する必要がなく、1行ごとに処理が完ルが生成されることが確認できます。

んで（1パス）、分岐命令の飛び先となるアドレスの結するため、ラベルがあればラベルをテーブルに登ラベルが前方にあってアドレスが分からない場合、飛録し、翻訳した命令と引数（オペランド）を cCode

び先アドレスを未設定のままアセンブルを続行し、後に登録、という作業を繰り返しています。命令の翻になってラベルのアドレスが確定した時点で元に戻っ

訳は 700行もある長大な switch 文1 つが担当していソースより短く、たった6行のプログラムで同てアドレスを設定する方法も可能です。この場合は、ます（素人にはお薦めできない ;-)）。最後にcCode

じ動作をします。リスト3の動作を言葉で書く

アドレスが未確定のまま残った命令の位置をすべてのバイナリを拡張子が j3d のテキストファイル（16と次のようになります。

覚えておいて、最後に未確定のアドレスを修正する進数）に出力してアセンブル終了となります。この必要があり、処理が煩雑になります。j3dasmでは、cCodeはj3wが仮想CPUのコード領域として使用し1パス目ではアドレスが未確定でも無視してアセンブているものと同じものです。

count1.j3cの動作をアセンブリ言語で直接プログラムしたのがリスト3です。J3C言語の1．変数に 1 を代入
2．値を表示ルを続け、ラベルが宣言されたアドレスを記録します。2パス目では、1パス目で分岐先のラベルのアド

3．変数に１を加算

レスがすべて確定しているため、アセンブラはすべ

4．変数が 10 より小さければ 2．に戻るてのラベルの参照が可能となります。1パス目は、ラ5．終了

ベルテーブルの作成だけが仕事になります。命令の長さが可変長であるため、実際にコードを生成して短い例ですからリスト3を詳しく見ていきましょう。1 行目の「LOAD R1 1 」では、R1 というレジスタ（変数のようなもの）に 1 を格納しています。2 行目の「label: 」は「ラベル」62

点 と し て ア セ ン ブ ル を 開 始 し ま す 。

J3W のアセンブラ（j3dasm）は、アセンブリ言語

J3W for Linux 入門講座

いますが、2 パス目で再生成しています。
j 3 d a s m の簡単な構造を図 A に示します。

cAssembler::assemble( ソースファイル名 ) を起

【図 A】j3dasm のクラス構造（水谷純）

count2.j3d は、8 桁までの16進数値が並んだには「プログラム」として実行する命令（と引

変数をLOADBP、STORBP命令を通してアクセスリスト4のテキストファイルです。これがいわ数）が並んでいます。コードメモリは複数のCPUします。

ゆる「マシン語」で、j3w はこれをメモリに数が共有して使います。

「フラグレジスタ」は演算の結果に従って分値として読み込んで実行します。

「スタックポインタ」は、データメモリのア岐するかどうかを決めるため、演算命令と分岐

count1.j3c と count2.j3s を実行してみるドレスを示しています（図 1 の下側の矢印）。

命令を内部的に使用します。演算結果が0かどと、どちらも一致することが確認できます（実PUSH 命令を実行すると、スタックポインタかうかを示すゼロフラグと演算結果が負であるこ行例 1、実行例 2）。

ら1が減算され、その位置のデータメモリに値とを示す符号フラグの 2bit を使っています。

を格納します。POP命令では、逆にスタックポ

RQ 〜 R6 レジスタまでの 14 個のレジスタは、■仮想 CPU

インタの示すデータメモリから値を取得した後にスタックポインタに1が加算されます。PUSH【リスト 3】count2.j3s

2001 年 10 月号で「J3C 言語は仮想 CPU で実命令とPOP命令を対応して使うことで、レジス行される」ということを説明しましたが、このタ内容の一時退避と復帰が簡単に実現できます。

仮想CPUの構造を詳しく見ていきましょう。図「ベースポインタ」は ENTER 、LEAVE 命令で内1は、J3Wの中心となるCPUのレジスタとデー部的に使用されます。コンパイラは引数と局所

LOAD
label: OUTNUM
INC
CMP
BLS
STPALL

タメモリです。
J3WのCPUは、同時に複数存在できますが、

R1 1
R1
R1
R1 10label:【図 1】J3W の CPU の構造

コードメモリ領域（プログラム領域）と共有メ【リスト 4】count2.j3d

モリ領域は、すべての CPU で共有されます。

40090000
198090000
8090000
19090000a25000002
63000000

J3C 言語のクラスのインスタンス 1 つにつき 1
つの CPU を使います。左側に数字が付いているレジスタがプログラムから直接読み書きできるレジスタです。
「プログラムカウンタ」は、CPU が実行する命令のコードメモリ中のアドレスを示しているレジスタです（図 1 の上側の矢印）。分岐命令は、このプログラムカウンタの値を書き換える【実行例 1】count1.j3c の実行例

ことで分岐を実現しています。
「コードメモリ」【リスト 2】count1.j3m

BRA

main:

main:
main_INIT:
main_RUN:

1
R4
R1
R1

1
R4-1#

R4 -1#
R1 R4
R4 10
R1 R4
main_INIT_4:
R1 0
main_INIT_5:
R1-1

R1 0
main_INIT_3:
main_INIT_2:
R4-1#

→

CALL
CALL
DELPRC
main_INIT:
ENTER
LOAD
LOAD
STORBP
main_INIT_0:
LOADBP
LOAD
LOAD
CMP
BLS
LOAD
BRA
main_INIT_4:
LOAD
main_INIT_5:
CMP
BEQ
BRA
main_INIT_1:
LOADBP→;+---------------------------------+;| This file was compiled by j3c.
;+---------------------------------+

LOAD
R2 R4
LOAD
R4 1
ADD
R2 R4
LOAD
R1 R2
STORBP R1 -1#
BRA
main_INIT_0:
main_INIT_2:
LOADBP R4 -1#
LOAD
R1 R4
OUTNUM
R1
BRA
main_INIT_1:
main_INIT_3:
STPALLLEAVE
RETURN
main_RUN:
RECEIV RL
CMP
RL 0
BEQ
main_RUN_BODY:
CALL
main_EVENT:
main_RUN_BODY:
ENTER
0
LEAVE
THROW
BRA
main_RUN:
main_EVENT:
ENTER
0
LEAVE
THROW
RETURN

jm:~$ j3c count1.j3c
J3C ver. 1.04 2001 Jun Mizutani
Source File : count1.j3c
Assembly File : count1.j3m
jm:~$ j3dasm count1.j3m
j3dasm ver. 1.42 2002 Jun Mizutani
Source File : count1.j3m
Object File : count1.j3d
PASS 1PASS 2Assemble 52 steps
jm:~$ j3w count1.j3d
J3W ver.6.44 2002 Jun Mizutani
Execute file : count1.j3d
123456789[finished]【実行例 2】count2.j3s の実行例

jm:~$ j3dasm count2.j3s
j3dasm ver. 1.42 2002 Jun Mizutani
Source File : count2.j3s
Object File : count2.j3d
PASS 1PASS 2Assemble 8 steps
jm:~$ j3w count2.j3d
J3W ver.6.44 2002 Jun Mizutani
Execute file : count2.j3d
123456789[finished]2002.4

Linux Japan63プログラムから直接アクセスできます。
「RQレウンタとして使用しますが、ループ命令外ではていて覚えにくいかもしれません。
「BRAnch」、ジスタ」
はプログラムで設定しますが、メッセー汎用レジスタとしても使用できます。J3C言語「Branch on Not Equal」、「Branch on LeSs」とジの送り先の CPU を識別するために使用しま

では、メッセージの保持に使用しています。

モトローラ系の CPU の分岐命令の命名法を採す。メッセージの送り先は、RQ の値をチェッ

RX、RY、RZ、RH、RP、RB の6個のレジスタクして決定されます。

は、XYZ座標値の設定や取得、ヘッド、ピッチ、「RL レジスタ」は、LOOP 命令の繰り返しのカバンクそれぞれの回転角度の設定や取得用とし用（特に理由はない）しています。

■ j3dasm の仕様て特定の命令で使用します。J3C言【表 1】J3W にのみ用意されている命令
説明INC

指定レジスタに 1 を加算

DEC

指定レジスタから 1 を減算

ADD

レジスタにレジスタ、メモリ、定数を加算
レジスタからレジスタ、メモリ、定数を減算

MUL

理解して実行できる数値列に翻訳（アセンブル）

令を使わない場合には、汎用レジスするプログラムを「アセンブラ」と呼びます。

タとしても使用できます。

j3w用のアセンブラであるj3dasmは、アセンブラとしての基本的な機能だけを実装しています。のレジスタには特別な機能はなく、アセンブリ言語のソースは図2の形式で記述しSUB

値の保持や演算用の汎用レジスタとます。行の先頭から空白を区切りとして、ラベレジスタにレジスタ、メモリ、定数を乗算して使用します。Cなどのプログラ

ル、命令、引数、セミコロンに続くコメントのDIV

レジスタをレジスタ、メモリ、定数で除算

ム言語のグローバル変数に相当する順に並べます。正式には、命令はニーモニック

13

SHL

レジスタをレジスタ、メモリ、定数で左シフト使い方をします。

（mnemonic）、引数はオペランド（operand）とSHR

レジスタにレジスタ、メモリ、定数で右シフト

ANDレジスタにレジスタ、メモリ、定数をビット積個︶

R1、R2、R3、R4、R5、R6 の 6 個ORことにします。

アセンブリ言語は「難しい」言語

ラベルはコロンで終わる文字列で最大 31 文

レジスタをビット反転

ではありません。x86などの一般的字、命令とレジスタ名は必ず英大文字で表記しレジスタをレジスタ、メモリ、定数と比較なCPUでも、OSを作るのでない限ます。行は、セミコロンか物理行末まで（1 行り、基本的に「演算」、「分岐」、「レ当たり最大255 文字まで）です。セミコロンがジスタの操作」という 3種類の命令あると、セミコロン以降から物理行末まで読みに入出力関連の命令を使うだけでプ飛ばします。ラベル名、定数名の英文字の大文

ログラムが作成できます。ただ、複字、小文字は区別します。

BRA
BEQ

レジスタの符号反転
説明
無条件にジャンプ
演算結果が 0 か等しいならジャンプ

分岐命令︵個︶BNE

演算結果が非 0 か等しくないならジャンプ

BGR

より大きいならジャンプ

BGE

より大きいか等しいならジャンプ

BLS

より小さいならジャンプ

BLE
BMI
BPL

雑な式や繰り返し構造を実現する場

数値は 0 〜 9 で始まれば 10 進数、「0x」で始合でも、単純な命令を組み合わせる

まれば 16 進数を表します。文字定数は「'A'」必要があるため「面倒な」言語ではのようにシングルクォートで囲みます。文字列あります。

は「"String" 」のようにダブルクォートで囲

J3C言語には約 110の組み込み関みます。全角文字も可能です。
「#」
で終わる数より小さいか等しいならジャンプ数が用意されていて、それらはすべ

値はデータメモリのアドレスを示します。

演算結果が負ならジャンプて j3w の命令に 1 対 1 で対応してい行頭から、空白やタブを入れずに「% インク演算結果が 0 以上ならジャンプます（J3W付属の j3c2j3w.html 参

ルードファイル名 %」と記述すると、指定したLOOPRL レジスタの回数分の繰り返し照）。j3w には約 150 の命令がある

ファイル名のファイルがその位置でインクルーCALL副手続きの呼出しので、40の命令がJ3Cには用意されド（挿入）されます。このとき、パスを含めずRETURN 副手続きからのリターンていないことになります。J3Cに用にファイル名だけを指定すると、ソースファイ

命令

説明

意されていない命令は、表1に示す

ルと同じディレクトリのファイルが使用されま

PUSH

レジスタのプッシュような演算命令、分岐命令、レジスす。別のディレクトリのファイルを「%/home/POP

レジスタのポップ

タとスタックの操作命令です。

CLEARG 汎用レジスタの一括クリア
PUSHG
レジスタ転送命令 ︵個︶15

呼びますが、ここでは「命令」、「引数」と呼ぶ

CMP

命令

12

レジスタにレジスタ、メモリ、定数をビット和■仮想 CPU の命令

NOT

NEG

POPG

汎用レジスタのスタックへの一括プッシュ
汎用レジスタのスタックから一括ポップ

ENTER

スタックフレームの作成

LEAVE

スタックフレームの解放

CALLTB

共有メモリのテーブルで呼び出し

LOAD

レジスタに値を設定

LOADM

データメモリに値を設定

XLOAD

レジスタ相対でデータメモリの値を取得

jun/j3w/work/lib/library.j3i%」のように

J3C言語では、これらの命令は式絶対パスで指定することも、「 % . . / l i b /や文をもとに自動で生成されます。

library.j3i% 」のように相対パスで指定する

表1の命令は、ほとんど英単語そのこともできます。

ままか、それを省略したものになっインクルードファイルから、さらにファイルています。分岐命令は省略されすぎをインクルードする操作（「ネスト」または「入れ子」という）は、8 レ【図 2】j3dasm の行形式

ベルまで可能です。同じ名前のラベルが複数宣言されている場合はエラーにならず、参照した場合

LOADBP ローカル変数をレジスタにコピーには行番号の若いラベルSTOREが使用されます。

レジスタをデータメモリにコピー

XSTORE レジスタ相対指定でレジスタをデータメモリにコピー
STORBP レジスタをスタック上のローカル変数にコピー

64

アセンブリ言語で書かれたソースを、CPUがみ込み関数と同じです。それらの命演算命令︵命令語で、引数をレジスタ変数で渡す組

J3W for Linux 入門講座

命令に変換されない擬似命令として、定数に名前を付ける DEFINE 擬似命令があります。

ンブラを使うほうがむしろプログラムを短く開発環境は Windows から Linux 中心に変わり定数名には次の制限があります。

することができます。J3C言語のほうがプログました。Windows 版の開発（Delphi ver.2）もラムは読みやすくなりますが、メッセージをソースを Linux に持ち込んで、diff ／ patch を1．定数にラベルを定義することはできない

細かく処理する必要がある場合ではアセンブ使ってます。私の Web サイトで J3W の Win-2．定数名にはニーモニックと同じ名前を使リ言語のほうが楽な場合もあります。J3W にdows 版と Linux 版のページのアクセス比は 2：は、アセンブリと J3C の両方で書かれた多く1 程度となっていて、OS の普及の比率から見用しない
3．定数は使用前（ソースコード中の位置）に必ず定義する必要がある
4．定数の再定義はできないのプログラムサンプルが付属しています。アてLinuxユーザーの健闘が目立ちます。Vector

センブリ言語のマニュアルも付属しているの（記事末の Resource［1］参照）からのダウンで参考にしてください。

ロード数は 20：1 ですが……。

■終わりにンアップは私のサイト（［2］）でお知らせしま

5．定数名は最大 31bytes

今回でJ3Wの紹介を終了しますが、バージョ

次に、DEFINE 擬似命を使った有効な定数宣言の例を示します。

DEFINE DataMemory 1234#
DEFINE Constant123
DEFINE HexConst
0x100
DEFINE Character 'A'
実際の使用例はj3w_script以下のディレクトリに用意していますので、参考にしてください。

■プログラミング
例によって、三角形を表示するプログラムを作ってみます（リスト 5）。このプログラムでは、J3C言語と同様に「視点となる物体」と「三角形となる物体」の2つが必要となります。プ
ログラムの先頭部分で、DEFINE 擬似命令で定数に名前を付けけていますが、この部分では命令は生成されません。回転速度や三角形の大きさをここで変更できるようにしています。プログラムの実行は最初の命令（「Start:」ラベルの位置）から始まり、すぐに三角形用の CPUを生成します。その後、空の物体を生成して、位置、背景色の設定後、グラフィックウィンドウを開いてプログラムが終了するまで待ちます。
三角形用のCPUは、GENPRC 命令で指定されているように、「Triangle:」の位置から実行を始めます。頂点と面を登録した後に位置を設定し、1 分間回転して終了します。
J3W の仮想 CPUは、三次元グラフィックス専用の命令を多く持っているため、計算や条件分岐をあまり使わないプログラムは、アセ【画面 1】triangle.j3s の実行結果す。興味のある方は、たまに見に来てください。
J3Wは、MS-DOS版を最初に公開してから6年、J3C 言語の追加から 3 年が経過しました。

【リスト 5】triangle.j3s

DEFINE Size 700
DEFINE Size2 -700
DEFINE Time 30000
DEFINE Angle 28800
Start:GENPRCGENOBJCLEARALOAD
SETPOSSETEYEBCOLOR
GRAPHMWAIT
DELOBJ
DELPRC
Triangle:
GENOBJDEFPNT
DEFPNT
DEFPNT
DEFPNT
DEFPNT
DEFPNTLOAD
DEFPLNLOAD
DEFPLN
CLEARA
SETPOSROTHROTP
DELOBJSTPALL

Triangle: 500 0RX

-2000

0x000

; 三角形のサイズ; 三角形のサイズ; 30 秒間; 10 回転; CPU を生成して TRIANGLE から実行開始; 視点用物体の生成; RX 〜 RB を 0 クリア; 位置の指定 20m 後方; 位置と角度を視点に設定; この物体が視点を持つ; 背景色を黒に設定; グラフィックウインドウを開く; メッセージ受信を待つ（何もしない）; オブジェクトの削除; プロセスの削除

6 2; オブジェクトの生成 6 頂点 2 面0 0Size ; 頂点 0 三角形の頂点座標を登録
0 Size Size2 ; 頂点 10 Size2 Size2 ; 頂点 20 0Size ; 頂点 3 頂点 0 と同じ
0 Size Size2 ; 頂点 4 頂点 1 と同じ
0 Size2 Size2 ; 頂点 5 頂点 2 と同じ
R1 13; 面の色指定
R1 3 0 1 2; 面の定義
R1 14; 面の色指定
R1 3 5 4 3; 面の定義
; RX 〜 RB のゼロクリア; 初期位置と角度の設定
Time Angle; ヘッド回転
Time Angle; ピッチ回転; 物体の削除; 全プロセス終了［1］ Vector
http://www.vector.co.jp/［2］ Jun's Homepage
http://www.nk.rim.or.jp/~jun/2002.4

Linux Japan65

J3C は、3D アニメーションキット J3W のコンパイラです。
J3C は、Java風の文法を持つオブジェクト指向言語として設計されています。J3Cの構文リファレンスを掲載します。

■構文規則（syntactic rule）■構文図式の基本形

コンピュータ言語の文法は、構文規則によって決定されます。
構文は、左から右へ、上から下へ矢印をたどって読んでいきます。

a は b である

b は「B」である

構文図式の基本形は次のようになっています。
「連続」、「選択」、「繰り返し」を組み合わせて文法を記述します。

連続

選択

a の後に b が続く

a か b のどちらかを選択する

繰り返し

繰り返し

a の 0 回以上の繰り返し

a の 1 回以上の繰り返し。b は区切りの役割を持つ

構文規則の左側にある名前のことを、「非終端記号（nonterminalsymbol）」と呼びます。また、class や for などの予約語、＝や＋などの記号で表される単語そのもののことを「終端記号（terminalsymbol）」と呼びます。終端記号と非終端記号は、構文図では次のように表します。

終端記号

非終端記号

（terminal symbol）（nonterminal symbol）

囲みの中には予約語または記号が入ります

囲みの中には、他で定義しているものが入ります任意
a か何もなし

構文規則を順次適用していくと、 すべての非終端記号は終端記号に行き着きます。

式

単純式

式は C、C++、JAVA に比べると演算子の種類が少ないですが、実四則演算の加減算を行います。演算子「|」はビット OR です。

用上は充分な種類を持っています。演算子の優先順位は、Pascalとほぼ同じです。

演算子の優先順位は、通常の四則演算（加減乗除）と同様、乗除は加減算より先に評価されます。優先順位は以下の順序で低くなります。
単純式Aと単純式Bは、表に示すような大小関係によって返り値が変化します。
優先順位
高低1

演算子-式

*/&3+-

|4>

>=

<==

J3W for Linux 入門講座

A より B が小さい

A より B が等しいか大きい

A >= B

A より B が等しいか小さい A より B が大きい

A<B

A より B が大きい

A <= B

A より B が等しいか大きい A より B が小さい

A より B が等しいか小さい!=※優先順位が最も高い「-」は、「A = -A;」のよ
うに、符合を逆転する「単項マイナス」です。

66

偽（0）の条件

A>B

()

2

返値
真（非 0）の条件

A == BA と B が等しい

A と B が等しくない

A != BA と B が等しくない

A と B が等しい

項

変数

四則演算の乗除算を行います。演算子「&」はビット AND です。

変数には、変数名だけで使う「単純変数」と変数名に［式］を伴う「配列変数」があります。変数の型は 32 ビットの符号付整数のみです。

因子

定数

因子は、変数、関数、数値のように、値を持定数の値を参照します。配列の要素を指定することもできますが、配列の添え字は定つ式の最小の構成要素です。数値は 10 進数、数式の必要があります。配列定数の添え字に変数を使用することはできません。ライ

16 進数、キャラクタで記述できます。

ブラリで宣言された定数はどのクラスからでもグローバルに参照できます。

定数式
定数式はコンパイル時に値が決定できる必要があります。従って、実行時に値が変化する可能性のあるメソッドや変数を使用することはできません。変数のうちfinal宣
言された変数（定数）は、実行時に値が変化しないため使用できます。new と child
組み込み関数で、宣言済みのクラス名を置くことができます。

レジスタ変数RX、RY、RZ、RH、RP、RBレジスタ変数は、組み込み関数のうち30種類程度の関数の呼び出し時の設定または返り値の取得に用いられます。また、クラスインスタンス生成時の RX、RY、RZ、RH、RP、RBレジスタ変数の値は生成されたインスタンスに引き継がれます。

このJ3C構文リファレンスは、2002年2月号から3回にわたって掲載しています。これまでの掲載分は、第 1 回は diagram1.pdf、第 2 回は diagram2.pdf として、今月号の本誌付録 CD-ROM に収録しています。併せてご覧ください。

――お詫びと訂正――
3 月号掲載の構文図（PDF ファイルは diagram2.pdf）の「ライブラリ呼び出し」の図中に誤りがございました。次の図が正しいものです。お詫びして訂正いたします。

2002.4

Linux Japan67