第A章 Oolong について
A.1 Oolong とは
Oolong は JVM (Java Virtual Machine) のコードをターゲットとするアセンブリー言語である。Oolong については、以下の書籍で紹介されている。
Joshua Engel: “Programming for the Java Virtual Machine”
ADDISON-WESLEY, ISBN 0-201-30972-6, 1999
JVM は、仮想 CPU（つまりソフトウェア上でエミュレートされる CPU）の一種である。JVM の命令セットは本質的な部分は Intel x86 や MIPS などの現実のCPU と似ている。しかし、レジスターベースではなく、スタックベースなので、レジスター割り付けの必要がなく、現実の CPU を対象とするよりはコード生成が容易である。
このため、本演習では、作成するコンパイラーのターゲットとして、Intel x86などの現実の CPU の機械語ではなく、この Oolong（すなわち JVM のアセンブリー言語）を使用する。
JVM はもともと Java というプログラミング言語のコンパイラーのターゲットとして設計された仮想機械である。Java 言語自体は、C 言語によく似た制御構造を持つ“高水準”プログラミング言語であり、Java とアセンブリー言語である
Oolong とは、まったくの別物である。（C 言語と Intel x86 のアセンブリー言語が全く異なるのと同じことである。） 実際、JVM をターゲットとする Java 言語以外のプログラミング言語のコンパイラーも、数多く存在する。

A.2 Oolong の実行方法
Oolong の処理系（アセンブラー）自体も JVM 上で実装されているので、Oolong を実行するためには、まず JVM（JRE という Java の実行環境）とoolong.jar というファイルを入手する必要がある。
Oolong ソースファイル の拡張子は .j である。Filename.j という名前の Oolong
ファイルをアセンブルする時のコマンドは次のようになる。
java -jar oolong.jar Filename.joolong.jar を別のフォルダーに置いている場合は、上記の oolong.jar の部分
は oolong.jar のフルパスを記述する。このコマンドで、 Filename.class というファイルが生成される。このファイルの中身は、仮想機械用のコードなので、直接実行することはできない。実行するには、次のように java コマンドを用いる。
java Filename
この時は、最後に拡張子の .class をつけないことに注意する。

A.3 Oolong のファイル構造

Oolong について p.1

本演習で使用する Oolong ファイルは、すべて次のような雛型に従う。そして、Statements の部分を必要に応じて書き換える。Oolong の文法では、改行は意味を持っているので、この例のとおりに改行を入れる必要がある。
.super java/lang/Object.method public static main([Ljava/lang/String;)V
Statements.end method
なお、クラス名はソースファイル名の拡張子（.j）を除いた部分と同じ名前になる。

A.4 Oolong の命令文（Statements）
Statements は命令文（Statement）の並びである。Oolong では、必ず 1 行に 1つの命令文を書く。本演習では、次のような命令文を使用する。浮動小数点数関係など、ここで紹介していないその他の Oolong（すなわち JVM）の命令文については、Oracle 社の Web ページ（http://docs.oracle.com/javase/specs/jvms/se10/html/index.html）
や Jasmin ⦅Jasmin は Oolong の基になった JVM アセンブラーである。 Jasminと Oolong の文法はほぼ同一であるが、Jasmin で必要ないくつかの宣言を、Oolong では省略することが可能である。⦆の Web ページ（http://jasmin.sourceforge.net/guide.html）で知ることができる。
JVM はスタックベースの仮想機械である。つまり、Oolong のほとんどの命令文は（レジスターではなく）スタックに置かれているデータをパラメーターとして動作する。以下では、スタック操作関係、分岐関係、整数演算関係、変数操作関係、その他にわけて Oolong の命令文を紹介する。以下の説明中で、a はスタックの先頭の要素、b はスタックの 2 番目の要素を表す。「増減」はスタック中の要素数の変化を表す。
スタック操作関係命令
ldc Int

増減1

ldc String
duppopswap
nop

1
1-100

説明
整数定数をスタックにプッシュする。
(load constant)
文字列定数をスタックにプッシュする。
スタックの先頭の要素 a を複製する。(duplicate)
スタックの先頭の要素 a を取り除く。
スタックの先頭の 2 要素 a, b を入れ換える。
何もしない。(no operation)

分岐関係
JVM は goto などの無条件分岐命令と、条件付きの分岐命令を持っている。
JVM のコード中では、オフセットを指定することによりジャンプするが、Oolong のソースコードでは Label で分岐先を指定することができる。 Label 名には、アルファベットからはじまり、空白文字を含まない任意の文字列を使用することができる。

Oolong について p.2

命令増減説明Label :–goto Label
if_icmpeq
Label0goto 文など分岐命令の分岐先ラベルを設定する。
Label に無条件に分岐する。

-2

a, b をスタックから取り除き（以下同様）、b == a ならば、 Label に分岐する。
(if integer compare equal)

if_icmpne
Label-2

if_icmpge
Label-2

if_icmpgt
Label-2

if_icmple
Label-2

if_icmplt
Label-2

ifeq Label
ifne Label
return-1-1–

b != a ならば、 Label に分岐する。
(if integer compare not equal)
b >= a ならば、 Label に分岐する。
(if integer compare greater than or equal)b > a ならば、 Label に分岐する。
(if integer compare greater than)b <= a ならば、 Label に分岐する。
(if integer compare less than or equal)b < a ならば、 Label に分岐する。
(if integer compare less than)a == 0 ならば、 Label に分岐する。
a != 0 ならば、 Label に分岐する。
メソッドから値を返さずに return する。
注: 1.3 節で紹介した雛型でも、メソッドの最後で必ず return する必要がある。

整数演算関係
ここでは整数に関する算術演算の命令のみを紹介する。

iadd

増
減-1

isub
imul
idiv-1-1-1

irem-1

命令

説明
b + a、加算（スタックから a, b を取り除き、b + a をスタックに積む。以下同様。）（integer add）
b - a、減算（integer subtract）
b * a、乗算（integer multiply）
b / a、（整数としての）除算（integer divide）
b % a、（整数としての）剰余（integerremain）

変数操作関係
JVM では、変数は番号で参照され、利用できる番号は 0 ～ 65535 まである。ちなみに、3 節の雛型の場合は、このうち 0 番の変数はメソッドの引数として使用済みである。
命令
iload Int
istore Int

増減
1-1

説明
Int 番目の変数の値をスタックにプッシュする。
スタックから a をポップし、その値をInt 番目の変数に格納する。

Oolong について p.3

その他
整数や文字列を画面に出力するために必要な命令を紹介する。スタックの先頭（a）に出力したいデータ、スタックの 2 番目（b）に出力ストリームが入っている状態で、出力のための命令を呼び出す。
命令
増減
説明
getstatic java/lang/System/out Ljava/io/PrintStream;
1 標準出力ストリームをスタックにプッシュする
invokevirtual
java/io/PrintStream/println(Ljava/lang/String;)V-2 出力ストリーム b に a（文字列）を出力する。
invokevirtual java/io/PrintStream/println(I)V-2 出力ストリーム b に a（整数）を出力する。
invokevirtual java/io/PrintStream/println(C)V-2 出力ストリーム b に a（文字）を出力する。

A.5 Oolong のプログラム例
まず、“Hello World!” と出力する Oolong のコードを紹介する。
ファイル名: Hello.j
1 .super java/lang/Object
2 .method public static main([Ljava/lang/String;)V3
getstatic java/lang/System/out Ljava/io/PrintStream;4
ldc "Hello World!"
5
invokevirtual
java/io/PrintStream/println(Ljava/lang/String;)V
6return; 最後にreturnが必要
7 .end method
なお、Oolong はセミコロン「;」から行末までがコメントになる。
次は、繰返しを用いて “Hello World!” を 10 回出力するプログラムである。
ファイル名: ManyHello.j
1 .super java/lang/Object
2 .method public static main([Ljava/lang/String;)V
3
ldc 0
4
istore 1; 変数1に 0を代入する
56loop:; ここからループ
7
iload 18
ldc 109
if_icmpge exit; 変数1が 10以上なら exit
へ
10
getstatic java/lang/System/out
Ljava/io/PrintStream;11
ldc "Hello World!"
12
invokevirtual
java/io/PrintStream/println(Ljava/lang/String;)V
13
iload 114ldc 1
15
iadd
16
istore 1; 変数1に 1を足す
17
goto loop; loopへジャンプ
18
19
exit:
20
return; 最後にreturnが必要

Oolong について p.4

21 .end method
ちなみに、これらは、それぞれ次のような Java のプログラムのコンパイル結果に相当する。この中で System.out.println は C 言語の puts に相当する出力メソッドである。
ファイル名: Hello.java
1 public class Hello {2public static void main(String[] args) {3
System.out.println("Hello World");
4
return;5}
6 }ファイル名: ManyHello.java
1 public class ManyHello {2public static void main(String[] args) {3int i = 0
4while (true) {5if (i >= 10) break;
6System.out.println("Hello World");7
i = i + 1;
8}
9return;10}
11 }Oolong について p.5