2006-11-01から1ヶ月間の記事一覧
るびま わー!!リンクしていただいちゃいました。紹介に恥じないよう頑張ります!Rubyでは定数畳み込みが難しい、というのはなるほどでした。
今日は break, redo, next などループ制御構文 for やブロックつきメソッド呼び出し構文 rescue, ensure 例外処理 のコンパイル部分をよみました。これ全部一回でやるつもりはなかったんですが、読んでみると全部深く関係しててこんなことになってしまいまし…
ensure節のコードは、YARVでは複数箇所に複製される可能性があります。 begin の本体が正常終了する箇所 break などでensureを抜ける箇所 例外で終わる場合の例外ハンドラとして それぞれ、ensure節が終わったあとに実行するコードが違うので、ひとつにまと…
case NODE_RESBODY:{ NODE *resq = node; NODE *narg; LABEL *label_miss, *label_hit; while (resq) { ... resq = resq->nd_head; } break; 複数のrescue節がありうるので、一個一個順番にコンパイルしていきます。これは上にあるrescue節から順に命令列に…
rescueやelseがある場合は、メインの命令列は次のようにコンパイルされます。(コンパイルするコードは特別なところはないので省略) start: 本体 end: if(elseがあれば) pop; elseの中身 lcont: if(poped) pop例外ハンドラの登録はこんな感じ。 /* resgiste…
begin 〜 end 構文です。rescueやensureがつくと、構文解析の段階でいろいろとノードの種類が変わってきます。まとめると以下の通り。 begin AAA end # NODE_BEGIN(AAA) begin AAA ensure EEE end # NODE_ENSURE(AAA,EEE) begin AAA rescue .. BBB rescue ..…
どんどん行きましょう。retry。NODE_ITERのところで読んだように、retryは例外処理になります。常にthrowに変換しておしまい。 case NODE_RETRY:{ if (iseq->type == ISEQ_TYPE_BLOCK || iseq->type == ISEQ_TYPE_RESCUE) { ADD_INSN(ret, nd_line(node), pu…
ジャンプ先と飛ばす例外の種類が違うだけで、NODE_BREAKとまったくおんなじです。next!
break文のコンパイルでやるべきことのおさらいです。 ジャンプ脱出コードを生成するか、例外脱出コードを生成するか ジャンプ脱出の場合、ensureの扱い case NODE_BREAK:{ unsigned long level = 0; if (iseq->compile_data->redo_label != 0) { /* while/un…
ついでだからブロックについてもここで読んじゃいます。NODE_FORはRubyのこの形の式 for 変数s in 式 本体 end を表す構文木ノードで、意味的には 式.each { |変数s| 本体 } と同じです。NODE_ITERは、メソッド名がeachとは限りませんが↑の形のブロックつき…
case NODE_OPT_N: case NODE_WHILE: case NODE_UNTIL:{ LABEL *prev_start_label = iseq->compile_data->start_label; LABEL *prev_end_label = iseq->compile_data->end_label; LABEL *prev_redo_label = iseq->compile_data->redo_label; VALUE prev_loopv…
個々の break 文などのコンパイルは、いつも通り case NODE_BREAK で行われます。でも、その前に NODE_WHILE で while をコンパイルする時点で、あらかじめ準備しておかなくてはいけないことがいくつもあります。注意点を列挙してみました。 break, next, re…
第5回です。前回はwhileループのコンパイルを途中まで読んだところで終わりました。普通に何事もなくループが回るケースは、前回読んだ範囲でカバーできています。今回は、ループにからむ制御構造 break, next, redo を扱うためのコンパイル処理について見…
case〜when 式は条件が全部リテラルだとテーブルでジャンプするようになってる そこにRubyのArrayやHashオブジェクトが使われてて便利そうでした てな感じでした。うーむ。もっと読むスピードアップしようかな。。。
続いて、ループ構文です。 while 条件式 本体 end のような形のwhile式をコンパイルします。untilは、whileと終了条件の真偽が逆になったバージョンで、NODE_OPT_Nは、rubyコマンドを-nオプションで起動したときに自動で作られるループ構造 while gets スク…
さきほども述べたように[式0] (head) がないcase文がここで扱われます。「headがwhen式の条件部とマッチしていたら」という判定が、「when式の条件部のどれかがtrueだったら」にすべて変わるだけで、基本的な構造はまったく同じです。むしろだいぶ簡単です。…
次は、case文です。 case [式0] when 式1 then 本体1 when 式2 then 本体2 .. else .. end という形の式で、上から順にwhen節を調べていって、式n === 式0 が成り立つところの本体が実行されます。この部分をコンパイルするコードのちょうおおまかな流れは、…
こんにちわ。月曜日になってしまいましたが復活です。 今日からリビジョン 581 に更新して読んでいきます。先週に引き続き、 static int iseq_compile_each(yarv_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) { ... type = nd_type(node); swit…
風邪であたまが回らないので今日のYARV勉強会はお休み。。。(> 日曜日までに復活できたらそっちでやります。
Project Tamarin - Backnumbers: Steps to Phantasien の Project Tamarin の紹介を読みました。これも面白そうだなあ。あと、コード読みの流れがわかりやすくて。わたしも見習わなくては。
今日はこのへんで終わりにします。お疲れ様でした。次回は、飽きるまで延々とノードごとのコンパイル方法を眺めていこうかなと思っています。caseによる分岐や、イテレータを使ったループ、next/redoなどのループ制御が待ちかまえていて、だんだん複雑なゾー…
「if文の条件を判定して、trueならthen側、falseならelse側にジャンプ」というマシン語を生成する処理は、関数が別にわかれています。 COMPILE_( nd_cond ) スタックから値をpopして、偽ならelse_labelにジャンプする命令のようにすれば、その場で簡単にコー…
elseのないif文も構文解析の段階でif-then-else文にまとめられる、と書きました。実はあんまりちゃんと追ってないのですが、elseがなかった場合はnd_else==0の構文木が作られているようです。 実は、switch文に入るより前にこういうコードがありました。 if …
次はif-then-else文です。elseのないif文やunless文、三項演算子a?b:cも全部構文解析の段階でこのノードにまとめめられるので、コンパイラは1種類のif文だけ気にすれば済むわけです。コンパイルする処理はこうなっています。 case NODE_IF:{ DECL_ANCHOR(co…
お次は、NODE_BLOCK。RHG12章 の「幹」の説明を読んでみると、このノードは、文の並びをリストとしてつなぐためのノードです。細かいことは抜きにすると 7; 8; 9 という3つの文は NODE_BLOCK(nd_head: 文"7"を表すノード, nd_next: NODE_BLOCK(nd_head: 文"…
この先はしばらく、switch文の各caseを順番に見ていきます。どの順番で読むと良いか特に妙案もありませんし、上からひたすら読んでいくとしましょう。飽きたら途中で考え直します。まず最初の4つのケースは、コンパイルエラーだそうです。 case NODE_METHOD…
なぜ突然スタックマシンの話を始めたかというと、実は、iseq_compile_each の第四引数を理解するのに必要だったからなのです。 iseq_compile_each(..., int poped) ざっと見た感じ、poped=0 で呼び出されている場合の方が多いようでした。そこで、特殊な方の…
YARVの仮想マシンは、YARV Maniacs 【第 2 回】 で解説されているように、「スタックマシン」という計算モデルで作られています。スタックマシンというのは、一本のスタック(末尾へのpushとpopだけができる配列)を考えて、そこへデータを入れたり出したり…
第3回です。今日はいよいよコンパイル処理の本陣に切り込みます。 コンパイルの大元締め関数はただひとつ、iseq_compile_each @ compile.c です。 static int iseq_compile_each(yarv_iseq_t *iseq, LINK_ANCHOR *ret, NODE * node, int poped) { ... type …
なにかもう一つくらいテーマを増やしたいな。どうしよ。。。前から機会があればやりたいと思ってたのが、OSI承認ライセンス を1個1個しつこいくらいに詳しく読んで整理、比較すること。実用には(L)GPLとBSDとMITとMPLを知ってればよさそうですけど、他にあ…