いざ書くとなると特に書くこと無いなぁ…
奈良に都って結構不便なんじゃないだろうか。 ちょっと移動するのにも山登ったりしそうだし。
ラーメンの店色々行ってみるんだけど、 どうも、どの店も僕と合わない…と、思ってたんだけど、 これってただ単に僕がラーメン嫌いなだけなんじゃないだろうか。
--
光学式マウスだ。
今使ってんのは光学式マウスなのである。 この光学式マウスっていうのは、 最初のうちはいいんだけど、慣れてくるとその使いにくさがなんとなくわかってくる。
普通のマウスっていうのは、何も悩まなくても、 適当にマウスパッド使ってりゃそれなりにスムーズに動いた。 けど、光学式マウスは違う。光学式マウスはマウスパッドの上だとむしろ 使えないことも結構ある。
まあ、光学式マウスを使うときは、色々材質に気を使わないといけない。 で、光学式に適した物っていうのはだいたいざらざらしてる感じで、 手触りがよくない。もう二度と光学式は買わないようにしようと思う。
--
あーわかんないなぁ…
前のローカル変数の話の続きだ。
{ a = 40; var a; ... }
こういう場合の挙動をどうするか、だ。 諸事情により構文解析時に宣言されてない変数を弾くことはできないとしてほしい。 まあ、アレだ。ブロックを値として運んだりして、それを評価したらブロックが実行されるの。 んで、その中で束縛されてない変数を評価した値は そのブロックを評価した環境に影響されるとか。そんな感じで。
前説明した実装だと、宣言した位置に関係無くローカル変数はローカル変数に なってしまう感じだ。だから、最初の 変数a は次に宣言されてる a と同じになってしまうわけだ。 Rubyだと変数の宣言は無くて、変数の頭($,@)で区別してるからなんとでもなってるんだけど、 接頭辞はできれば使いたくないような(Cっぽくなくなる)。
いくつか案があって、宣言する位置はシカトして評価するとか、スピードを捨ててローカル変数も全部 ハッシュにして、宣言するたびに領域作って、領域が無い場合にエラーにするとか、 とりあえずローカル変数として扱って、ローカル変数テーブルに生死を表すビットを付けておいて、 var文を処理する時に生きてるフラグ立てるとか、 Cみたいに先頭じゃないと宣言できないとか、いっそlet文でやるとか。
JavaScriptの場合だと、
function x() { { var b = 50; } print("b="+b); }
これで、"b=50"らしい。ブロックローカル変数の概念は無いような。 というか、JavaScriptは宣言無くてもいいのか…うーむ、困ったなぁ…どうしようか…
面倒だから全部ハッシュテーブルでやることにする。以上。
static tree eval_context_block( tree block ) { tree ns = nl_namespace_create(); push_namespace( ns ); eval_block( block ); pop_namespace( ns ); }
こんな感じで可能。
--
var x = 80000; namespace nanika { var x = 50; nldef func() { x = 10000; nl::std::print("nanika::x=",x,"\n"); } } nanika::func(); nl::std::print( "x=", x, "\n" ); /* 実行結果 nanika::x=10000 x=80000 */
とりあえず、GCCのtreeを中間表現に使うインタプリタでこのくらいまで動いた。 あとは、JavaScriptっぽいOOな機能とかクロージャとか。 それとコンパイラの部分。
恐ろしくハッシュをチェーンしまくるし、ブロックに入る度にハッシュテーブル作るし、 それがゴミとして残るし実行速度は遅い。 まあ、仕方無いか。速度はそれほど必要ではないだろうし。 あと、GCが面倒。ちゃんとプロテクトかけないといけない。
ひょっとしたら需要があるかもしれないので昨日の GCCのtreeを中間表現に使うインタプリタっていうのを置いときます。 GCCのRTLに変換される前のtreeを弄るプログラムをインタプリタで動かして コンパイル時のコード生成をやりたいとかそういう話。 ただ、RTLへの変換は全然わからなくなって、一度挫折してるので、今度もできるかどうかは謎。
3.4.0で動作確認。3.3.2とかではコンパイルできないのを確認。 gcc-3.4.0/gcc/内に展開して、./configure --enable-languages=asdf。で、make zxc1 とかで動くのではないかと。あんまり確認してないけど。 まあ、今のところはプログラミングに使えないと思うけど、GCCのtreeをどうやって弄るかの参考くらいには 使えると思います。
--
明日からまたインターネットに繋がらなくなるので、とりあえず動いたところまで書いておく。
はやくインターネットに繋がるようにしたほうがいいなぁ…
512の日
アレだ。アレ。とうとうHTTPアップローダを使ってしまうわけだ。 会社のネットワークは私用に使ってはいけないんです。本当は。
とりあえず、そこそこ動くSDL-XIMパッチを 上げておく必要があったので、まあ、仕方が無いということで。許してください。
やっぱADSLとか繋げられる環境にしよう…
--
nl::std::print( "hogehoge\n" ); using nl::std; print("hogehoge2\n");
usingが使える。
namespace A {} namespace C { var nanika = 100; } namespace B { using C; using A; } namespace A { using B; } A::nanika = 100; nl::std::print( C::nanika ); /* => 100 */
usingがループはしないようにチェックはしてる。 ちょっと汚い方法だけど。あと多分遅い。
namespace A { var nanika = 100; } A.value = "val\n"; nl::std::print( A.value ); /* => "val" */ nl::std::print( A.nanika ); /* => 100 */ A["nanika"] = 101; nl::std::print( A.nanika ); /* => 101 */
というか、名前空間はオブジェクトだし、連想配列だ。 このあたり区別しようかと思ったけど、やってること一緒だったので、まあいいか、って感じで。
var obj = nl::std::new_object(); /* 実際は空の名前空間作ってるだけ */ obj.foo = 100; /* => OK. fooは勝手に定義される */ obj::bar = 100; /* => ERROR. barは定義されない */
で、心持ちドットによるアクセスとコロンによるアクセスを区別するようにした。 まあ、この辺は気分の問題だろうか(僕の)。
using nl::std; namespace Nanika { var x = 100; nldef func( ) { print( int_val, "\n" ); /* this.int_valになる */ print( x ); } } var obj = new_object(); obj.f = Nanika.func; obj.int_val = 1024; obj.f(); /* => 1024 \n 100 */
ローカル変数は全部ハッシュテーブルでなんとかしてるから、こういうのは難しくなかった。
このくらい動いたら十分だと思う。 そろそろコンパイラ部分…ってこれ言うの3回目くらいのような気がする。
あとは例外処理とかだろうか。面倒なんだよなぁ…多分。 とりあえず、エラーしたら exit するのをなんとかしないといけない…そのうち。 あと、アロケートした物のプロテクトをなんとかしないといけない。
nldef do_gc() { nl::std::gc(); } "aaaa" + do_gc();
運悪くGCが動いたら文字列"aaaa"は回収されちゃう。あと、あんまり関係無いけど、 gcc内で使われている、ggc_alloc_stirngは名前に騙されてはいけない。 実際はリークする。
while ( 1 ) { ggc_alloc_string( "naninani", -1 ); ggc_collect(); }
そのうちメモリが無くなって落ちる。いや、識別子とか文字列定数はハッシュテーブルに入ってるとかで、 解放する必要が無いっていうのはなんとなくわかるんだけど、その関数の名前はどうかと思う。
とりあえず、変数を表現するのがVAR_DECLっていうのが わかって嬉しいので、GCCメモでも置いておきます。
あんまり詳しく調べたわけではないし、ゆっくり推敲しながら書いたわけでもないので、 あんまり信用しないほうがいいかと。
間違ってる部分とか、判明した部分とかがあったら適当に修正していく予定。
GCCのソースの中にLANGUAGESっていうファイルがあって、
Right now there is no documentation for the GCC tree -> rtl interfaces (or more generally the interfaces for adding new languages). /* * 訳(多分): * * 今はtreeからrtlへ変換するインターフェース * (というか、新しい言語を書くためのインターフェース) * について書いたドキュメントはあらへんよ。 */
とかって書いてあって、まあ、そんな感じらしい。やっぱソース読むしかないのか。
defun int nanika( int a ) { }
これが
.file "test.asdf" .text .type nanika, @function nanika: pushl %ebp movl %esp, %ebp leave ret .size nanika, .-nanika .section .note.GNU-stack,"",@progbits .ident "GCC: (GNU) 3.4.0 20040416 (prerelease)"
こうなる。
まあ、型とか引数とかセコい方法でごまかしまくってるんだけど、 それでも、あとはその辺修正していくだけなんじゃないかなぁ…と、思う。 やってみないとわからんけど。
それと、関数の前にdefunキーワードが入るのが非常に嫌なんだけど、 入れないとどうしようもない。そのへんの話はまた後日。
パーサーを汚くすればいけるんだけど…