9 章: 高水準言語
高水準言語 Jack から VM 言語への変換を行うにあたって、ここで Jack 言語 (Java の簡易版みたいなもの) の仕様を一通りみておく。
変数の種類とスコープ
変数には以下の 3 つのほか、サブルーチン宣言のときのパラメータリストなどがある。
- スタティック変数: あるクラスのすべてのオブジェクトで共有される変数。
static
で宣言。 - フィールド変数: あるオブジェクト内で共有される変数。
field
で宣言。これが C++ や Python でいうメンバ変数である。 - ローカル変数: サブルーチン内のみをスコープにもつ変数。
var
で宣言。
クラスとサブルーチン
- Jack のプログラムには Main という名前のクラスが含まれる必要がある (C++ で
int main
が必要なのと一緒だ)。 - 1 つのクラスには
main
という名前の function が定義されなくてはならない。 - サブルーチンには constructor, method, function の 3 種類がある。method はクラスから生成されたオブジェクトに対して動作し、C++ や Python などでのメンバ関数に該当する。一方、function はオブジェクトに依存せず動作するものであるっぽい。このあたりの話は Java をやっていればしっくりくる話なのかもしれないが、ほぼ全く書いたことがないので結構戸惑った。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
class Hoge {
// Hoge 型を返すコンストラクタ。new というのは慣例的な名前であり、C 言語の new とかとは異なる
constructor Hoge new()
method void fuga()
function int piyo() // function はクラスのメンバ関数を使わず、生成されたオブジェクトに依存しない
method void foo() {
// --- method の実行 ---
// 特に返り値のない関数を実行するときは do をつける
do fuga(); // method は同じクラス内で特に何もつけずに呼ぶことができる
// --- function の実行 ---
var int a; // 返り値がある場合、事前に返り値を格納する変数を宣言しておかなくてはならない
let a = Hoge.piyo(); // function を呼ぶときはクラス名を頭につけなくてはいけない
}
}
class Main {
function void main {
var Hoge obj;
// --- クラス外からの constructor の実行 ---
let obj = Hoge.new(); // クラス名.関数名とする
// --- クラス外からの method の実行 ---
do obj.fuga(); // オブジェクト依存なので、オブジェクト名.関数名
// --- クラス外からの function の実行 ---
var int a;
let a = Hoge.piyo(); // クラス名.関数名
}
}
課題
Jack に慣れるため、なんでもいいから書いてみようとの課題。試しに A - New Generation ABC を解いてみたのが以下のコードである。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Main {
function void main() {
var int s;
let s = Keyboard.readInt("");
if (s < 126) {
do Output.printInt(4);
} else {
if (s < 212) {
do Output.printInt(6);
} else {
do Output.printInt(8);
}
}
return;
}
}