K.Sasada's Home Page

こめんとのついか

こめんとこめんと!

message

please set comment :).

_3(Mon)

明日は7時起きなんだが、眠れん。むー。初出勤なんだがなぁ。


眠れないので命令列をファイルに落とす方法を考えてみる。

今考えているのは命令列を Array/Hash などの、汎用的なデータ表現に変換、およびその逆変換をするインターフェースを作ることを考えている。

今考えているデータは、命令列を Hash で持つ。

print "Hello!\n"

#=>

{
  :type => :toplevel,
  :body => [
    [:putself],
    [:putstring, "Hello!\n"],
    [:send, :print, 1],
  ],
}

こんな感じ。で、YAML にするとこんな感じ。

--- 
:type: :toplevel
:body: 
- - :putself
- - :putstring
  - |
    Hello!

- - :send
  - :print
  - 1

なんで YAML にしているか、というと、YAML だと Perl とかから簡単に吐けるから、と、Audreyさんに言われたから。

しかし、シンボルから数値への変換とか、やっぱり遅そうな気はする。やっぱり、速度目的のシリアライズした pre-compile なデータは別の構造を作るしかないか?


最後は勝手に end つけりゃいいや、と思っていたが、やっぱり付けないと不便なことに気づいた。

実は、Ruby レベルで命令列を作るための API である yasm ライブラリというのを用意していて、上記は

iseq = yasm.toplevel{
  putself
  putstring "Hello!\n"
  send :print, 1
}

などと書けるライブラリを目指していたんだが、yield や super、end 命令は予約語なのでメソッドで素直に書けない。

最初は toplevel{|x| x.end } のように、ブロックパラメータへのメソッド呼び出しでいいから予約語でもいいかーと思っていたんだけど、やっぱりかっこよくない。

super は invokesuper にすればいいや、と思うんだが、yield と end の代替名が思いつかない。invokeyield って変だし。なんかないかな。end は return かなぁ。嫌だなあ普通で。yield は yieldvalue とかかなぁ。変だなぁ。


悩んでいることは、まだ色々ある。

上述した (a) 単純なデータと、(b) yasm、どちらをベースにするべきか、ということである。

(a) をベースにした場合、yasm は (a) を作る。

(b) をベースにした場合、(a) は yasm ライブラリを呼び出すような、別のプログラムを用意する。

どちらも一長一短がある。前者のほうが簡単かなあ。

つまり、yasm は (a) のジェネレータ、というかラッパになるって感じ。


(a') を作って、もっと低レベルのものを用意するか。

バイナリ <-> (a') <-> (a)

みたいな。


しかしさ、そんなバレバレな嘘なんか、わざわざ 4/1 につくわけないじゃーん。


捕捉早すぎだよママン。


もうちょっと読みやすいデータ構造を作ろうと思ってたんだけど、どうにも難しいな。

begin
  BODY
rescue
  RESCUE
end

#=>
{:body => [...],
 :rescue => [...],
}

とやるとカッコいいと思っていたんだけど、命令列からの変換が、ネストしたときに大変難しそうということがわかった。

ということで、ベタベタな情報になるようです。

{
:body => [
:labelA
  ...
:labelB
  ...
:labelC
],
:exception =>
  [[:rescue, :labelA, :labelB, :labelC, [...]]]
}

こんな感じ。


むぅ。適切な位置だけにラベルを付けるって難しいな。命令列をパースして、ジャンプ命令を全部抽出して、という、ワンパス増えることになる。それはなんか嫌だ。

でも、命令列にはグラフ情報がないからなぁ。

うーん、効率よくこれを実現するにはどうすればいいんだろう? いっそ、ラベルはなし、なんてのはどうだろう。


  class C
    def m
      p "C#m"
    end
  end
  C.new.m

こんなのを、

{:args=>[],
 :body=>
  [[:putnil],
   [:putnil],
   [:defineclass,
    :C,
    {:args=>[],
     :body=>
      [[:putnil],
       [:definemethod,
        :m,
        {:args=>[],
         :body=>
          [[:putself],
           [:putstring, "C#m"],
           [:send, :p, 1, nil, 4, nil],
           [:end]],
         :vars=>[],
         :type=>:method,
         :exception=>[]},
        0],
       [:putnil],
       [:end]],
     :vars=>[],
     :type=>:class,
     :exception=>[]},
    0],
   [:pop],
   [:getinlinecache, nil, 4],
   [:getconstant, :C],
   [:setinlinecache, -7],
   [:send, :new, 0, nil, 0, nil],
   [:send, :m, 0, nil, 0, nil],
   [:end]],
 :vars=>[],
 :type=>:toplevel,
 :exception=>[]}

こんなふうに変換できるようにした。

あとは、この逆変換だ。


しまったーーーーー。engーーーーー。


結局寝ないで出発。

_雪見酒(Mon Apr 03 23:45:13 JST 2006)

 がんばれー


好きにコメントを編集してください。ただし、あまり他の人のコメントを書き換えることは感心しません。



back

tton 記述が使えます。YukiWikiな記述してりゃ問題ありません。

「行頭に#code」 と、「行頭に#end」 で挟むと、その間の行は pre で囲まれます。プログラムのソースを書くときに使ってください。

例:

#code

(なんかプログラム書く)

#end

リンクは

[[なまえ|http://www.example.org]]

とか

[[http://www.example.org]]

で貼れます。

$Date: 2003/04/28 10:27:51 $