ToDo:
Jasminというから、てっきりこのJasminでバイトコードアセンブラを直接実行できるようになったのかと思っていたら、違ったらしいorz。まぎらわしい。「こんな毎日」での紹介を見るに、どうやらX86っぽいアセンブラを実行できるインタプリタにエディタやデバッガなどを統合したものっぽい。
新しいスクリプト言語Xtalを作っている人の日記。言語の設計に関する話は、同じく俺言語を作っている身としてなかなか面白い。これからWatchしていくことにしょう。
しかし、ちゃんとタイトルの通りに開発日記になっている点は見習わなければいけないな。こっちなんか、タイトルが「Onion開発日記」なのに、Onionの開発について、最近ほとんど書いてないし。一応細々と開発してはいるんだけど、まず現在のバージョンのソースコードが汚過ぎるので、それをまずなんとかしなければという状態orz
もう1ヶ月半以上前の話で今更だが、9/16〜9/18に第39回情報科学若手の会というのがあったので、参加してきた。
内容や感想については今更書いても仕方無いので置いておくが、自分の発表スライドを公開していたのを思い出したので、せっかくなのでリンクを貼っておく。ちなみに内容は、変態言語(braif**kやwhitespaceなど、実用性皆無のネタ言語のこと)についての簡単な紹介と、文字列をbraif**kプログラムに変換する拙作のネタプログラムbbencodeとwhitespaceプログラムに変換するwwencodeの紹介。名前から見てわかる通り、竹迫さんのppencodeにインスパイアされて作ったもの。かなり手抜きコードで、日本語文字列を入力した場合、正しく動作しないとか問題があるが、その辺は容赦していただきたい。
注: Input Textに全角文字を入力しないでください。正しく動作しません。
注: Input Textに全角文字を入力しないでください。正しく動作しません。
かなり久しぶりに、開発日記らしいエントリ。今日は、実装自体は大して難しくないのだが、単に面倒くさいので後回しにしていた後置インクリメント/デクリメント演算子を追加した。これで、次のサンプルプログラムが動作するようになった。
Inc.on
list = ["A", "B", "C", "D", "E"];
for i = 0; i < list.size; i++ {
System::out.println(list[i]);
}
実行結果
>onion Inc.on A B C D E
Dec.on
list = ["A", "B", "C", "D", "E"];
for i = list.size - 1; i >= 0; i-- {
System::out.println(list[i]);
}
実行結果
>onion Dec.on E D C B A
ただ、リストの要素を最初から順番に取り出すだけならforeach文を使って次のようにかけるので、最初の例はサンプルとしてはあまり意味が無いが。
list = ["A", "B", "C", "D", "E"];
foreach s :String in list {
System::out.println(s);
}
後置インクリメント/デクリメント演算子を追加していて感じたのだが、やはり現在のコードのまま、機能拡張を続けるのはやばそうだ。
現在のOnionのコンパイラは、大体次のような構成になっているのだが、
入力 --構文解析--> 抽象構文木 --意味解析(型チェックなど)--> 中間言語 --コード生成--> クラスファイル
中間言語の構造をあまりよく考えずに作ったため、中途半端に高級で(式と文の区別やループ構造が存在)、中途半端に低級な(あるメソッド内のローカル変数は全てインデックスで一意に識別されるなど)部分が混在した変な中間言語になってしまった。そのため、抽象構文木から中間言語への変換を行う部分が、不必要に複雑になってしまった。これ以上の機能拡張を行う前に、まずはこの中間言語の構造を見直す必要がありそうだ。
現在、今週のシス情セミナーの資料をLaTexで作っている。今まではVimで.texファイルを編集して、シェルからコンパイル->プレビューみたいなことをやっていたのだが、今回は試しにEclipseのLaTexプラグインであるBlueNoteTexを使ってみた。いくつか機能不足な点はあるが(ex. プロジェクトごとに.texファイルのコンパイル用のコマンドを切り替えられない)、今回のような簡単な資料を作るなら、十分使えるレベルに達していると感じた。
Java News経由。
とりあえず最初はjavacと仮想マシンのソースコードだけらしいが、最終的には全てオープンソース化するらしい。
ところで、前から「Javaをオープンソース化」って言葉は何か変だと思っていたのだが、どうなんだろう。「SunのJava SE実装をオープンソース化」とかならわかるんだが、Javaは言語名あるいは実行環境の名前を表すものであって、それをオープンソース化というのは表現として変じゃないかなあ。
ちなみに、Java Newsから直接リンクが貼ってあったニュース記事で「Java SEをオープンソース化」のようにタイトルに書いてあったのはZDNet Japanの記事とCNET Japanの記事だけで、他は「Javaをオープンソース化」のように書いてあった。
いきなりだが、Java言語にはgotoが無い(gotoという予約語はあるが、使用されていない)。gotoが無い理由としては色々考えられるが、おそらくその用途のほとんどは、構造化例外やラベル付きbreak/continue文で十分、あるいはその方が良いと設計者が判断したからだろう。しかし、Javaでgotoのようなことをすることは、本当にできないのだろうか。というわけで、Javaでgotoをエミュレートする方法を考えてみる。
まず、gotoには大きく分けて前方(ソースコードの下方向)へのジャンプと後方(ソースコードの上方向)へのジャンプの二種類があるが、この内前方へのジャンプについては既にJava言語に同等の機能が存在している。
どういうことかというと、Java言語のラベル付きbreak文はループだけでなく、任意のブロックから脱出可能であるため、ジャンプ専用のブロックを作ってそこに適当なラベルをつければ、そのブロックの中からラベル付きbreak文でブロックの終了直後にジャンプすることができるのだ。例えば、
...
BLOCK:{
System.out.println("A");
System.out.println("B");
/* if(true)が無いと到達不能コードが存在するという
* コンパイルエラーが出るため、コンパイラを黙らせるため必要
*/
if(true) break BLOCK;
System.out.println("C");
}
...
上のようなコードを書いて実行すると、
A B
とだけ表示され、breakの下の部分は実行されていない事がわかる。これで、前方へのジャンプについては解決できたことになる。
一方、後方へのジャンプはちょっとややこしい。一見、上と同様にラベル付きcontinue文を使って、次のように書けば良いように思えるが、これはコンパイルエラーになってしまう。ラベル付きcontinue文はループの中でしか使えない仕様になっているためだ。
BLOCK:{
System.out.println("A");
System.out.println("B");
//コンパイルエラー。ループの外でcontinueを使っている
if(true) continue BLOCK;
System.out.println("C");
}
というわけで、ラベル付きcontinue文だけで後方へのジャンプをエミュレートするのは無理である。しかし、ここであきらめては面白く無いので、もう一工夫してみよう。ラベル付きcontinue文はループの中でしか使えないため、ループ(forやwhile文)で通常のブロックと同じ動作をするものが作れれば良い。そこで、次のようなループによって通常のブロックをエミュレートすることにする。
while(true){
...
break;//ループが
}
あとは、このwhile文にラベルをつければ、その中でラベル付きcontinue文を使えることになり、めでたく後方へのジャンプもできるようになる。
BLOCK:
while(true){
...
continue BLOCK;//goto BLOCK;
...
break;
}
ちなみに、この技法を使った次のようなコードのメソッドを持ったクラスをJDK1.5のjavacでコンパイルして
int i = 0;
BLOCK:
while(true){
System.out.println(i);
i++;
if(i < 10) continue BLOCK;
break;
}
逆アセンブルしてみたところ、次のようなバイトコードになった。このコードを見ると、whileの条件式の評価がjavacの最適化によって削除されていることがわかる。
0: iconst_0 1: istore_1 2: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 5: iload_1 6: invokevirtual #3; //Method java/io/PrintStream.println:(I)V 9: iinc 1, 1 12: iload_1 13: bipush 10 15: if_icmpge 21 18: goto 2 21: return
追記:
斎藤君からのコメント:
なんでwhile(true)のtrueは削除できるのに、if(true)のtrueは検知できないの? # by 処理系初心者
if(true)の場合も、ちゃんと条件判定を削除してくれます。 例えば、次のコード
BLOCK:{
System.out.println("A");
if(true) break BLOCK;
System.out.println("B");
System.out.println("C");
}
をSunのjavacでコンパイルして、逆アセンブルすると、次のようなコードになり、ifの条件式の判定とbreakのコードが削除されていることがわかります。
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3; //String A 5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/Str ing;)V 8: return
じゃあ何故最初の例でif(true)を入れているのかというと、これが無いと言語仕様のレベルでbreakより下が到達不能と判定されてしまい(JLSの14.21「Unreachable Statements」参照)、コンパイルエラーになってしまうためです。一方、if(true)を挿入すると、言語仕様のレベルでは到達不能コードにならないためコンパイルエラーにならないが、処理系は到達不能コードが存在することを判定できるため、最適化できるということです。
IKeJIが主催している学内限定?イベント「未来会議」第2回で発表してきた。最初はJavaCCか何かのチュートリアルでもやろうと思っていたのだが、当日までにネタがまとまらず、以前SWoPPの発表で使ったスライドを少し改変してOnionの紹介をすることにorz。次は事前に何かネタ考えておかなきゃ。
ちなみに第3回は12月下旬頃の予定。発表ネタ募集中なので、何か発表したい方はIKeJIか自分(i021216{at}coins.tsukuba.ac.jp)辺りに連絡していただければと思います。あと、今のところほぼ学内限定になってますが、学外の方でも発表していただけるという奇特な方がいれば大歓迎です。
_ こんな毎日・・・ [ああ、Jasmin紛らわしかったですね。すいません。 (私も最初間違えました、ははは…) ]
_ みずしま [わざわざありがとうございます。「こんな毎日・・・Script_on_Java」はいつもWatchさせてもらっています..]