[[mrubyを読む]]
 
 #contents
 
 *はじめに [#ha2d1f6f]
 
 スクリプト解析は文字列を解析する関数とファイルを解析する関数がありますが、それらの違いは所詮、入力の違いなのでmrb_parse_string()をスクリプト解析のエントリポイントとして読み進めていきたいと思います。
 
 *mrb_parse_nstring(src/parse.y) [#k3c722a6]
 
 mrb_parse_string()は渡された文字列をstrlenしてmrb_parse_nstring()に渡しているだけなのでmrb_parse_nstring()を見てみましょう。
 
 #code(C){{
 parser_state*
 mrb_parse_nstring(mrb_state *mrb, const char *s, size_t len)
 {
   parser_state *p;
 
   p = mrb_parser_new(mrb);
   if (!p) return 0;
   p->s = s;
   p->send = s + len;
 
   mrb_parser_parse(p);
   return p;
 }
 }}
 
 スクリプト解析で鍵となるのはmrb_parser_state構造体のようです。mrb_parser_stateはinclude/compile.hに書かれています。なお、上記ではparser_stateになっていますが、parser_stateはmrb_parser_stateをtypedefしたものです。
 
 (もうちょい説明を書く)
 
 *解析してみる [#a48d3327]
 
 具体的にスクリプトをNODEに変換してみましょう。対象とするスクリプトは[[Ruby1.9のスクリプト解析>Ruby1.9/スクリプト解析を読む]]で変換してみたものと同じスクリプトを使います((余談ですが、2012/5/29時点でKernel#randが実装されていないため、スクリプトを実行するとNoMethodErrorになります:-P))。
 
  class MonteCarlo
    def pi(n)
      count = 0
      (1..n).each do
        x = rand
        y = rand
        if x * x + y * y <= 1
          count += 1
        end
      end
      (count.to_f / n) * 4
    end
  end
  
  n = 10000 * 10000
  pi = MonteCarlo.new.pi(n)
  puts "pi = #{pi}"
 
 bin/mrubyは--verboseオプションを付けるとNODEツリーがダンプされます((実行コードもダンプされますがそれは次で取り上げます))。上記のスクリプトを食わせると以下のNODEツリーが出力されました。
 
  $ ./mruby.exe -c --verbose ../../montecarlo.rb
  NODE_SCOPE:
    local variables:
      n
      pi
    NODE_BEGIN:
      NODE_CLASS:
        :MonteCarlo
        body:
          NODE_BEGIN:
            NODE_DEF:
              pi
              local variables:
                n
                              count
              mandatory args:
                NODE_ARG n
              NODE_BEGIN:
                NODE_ASGN:
                  lhs:
                    NODE_LVAR count
                  rhs:
                    NODE_INT 0 base 10
                NODE_CALL:
                  NODE_BEGIN:
                    NODE_DOT2:
                      NODE_INT 1 base 10
                      NODE_LVAR n
                  method='each' (170)
                  args:
                  block:
                    NODE_BLOCK:
                      body:
                        NODE_BEGIN:
                          NODE_ASGN:
                            lhs:
                              NODE_LVAR x
                            rhs:
                              NODE_CALL:
                                NODE_SELF
                                method='rand' (330)
                          NODE_ASGN:
                            lhs:
                              NODE_LVAR y
                            rhs:
                              NODE_CALL:
                                NODE_SELF
                                method='rand' (330)
                          NODE_IF:
                            cond:
                              NODE_CALL:
                                NODE_CALL:
                                  NODE_CALL:
                                    NODE_LVAR x
                                    method='*' (80)
                                    args:
                                      NODE_LVAR x
                                  method='+' (76)
                                  args:
                                    NODE_CALL:
                                      NODE_LVAR y
                                      method='*' (80)
                                      args:
                                        NODE_LVAR y
                                method='<=' (300)
                                args:
                                  NODE_INT 1 base 10
                            then:
                              NODE_BEGIN:
                                NODE_OP_ASGN:
                                  lhs:
                                    NODE_LVAR count
                                  op='+' (76)
                                  NODE_INT 1 base 10
                NODE_CALL:
                  NODE_BEGIN:
                    NODE_CALL:
                      NODE_CALL:
                        NODE_LVAR count
                        method='to_f' (109)
                      method='/' (148)
                      args:
                        NODE_LVAR n
                  method='*' (80)
                  args:
                    NODE_INT 4 base 10
      NODE_ASGN:
        lhs:
          NODE_LVAR n
        rhs:
          NODE_CALL:
            NODE_INT 10000 base 10
            method='*' (80)
            args:
              NODE_INT 10000 base 10
      NODE_ASGN:
        lhs:
          NODE_LVAR pi
        rhs:
          NODE_CALL:
            NODE_CALL:
              NODE_CONST MonteCarlo
              method='new' (6)
            method='pi' (326)
            args:
              NODE_LVAR n
      NODE_CALL:
        NODE_SELF
        method='puts' (286)
        args:
          NODE_DSTR
            NODE_STR "pi = " len 5
            NODE_BEGIN:
              NODE_LVAR pi
            NODE_STR "" len 0
 
 それではどういうルールを通ることでこのようなNODEツリーが構築されるのかを追っていくことにします。
 
 (執筆中)
 

トップ   新規 一覧 単語検索 最終更新   ヘルプ   最終更新のRSS