「Rubyのしくみ」(Ruby Under a Microscope)を読んだ
「Rubyのしくみ」(Ruby Under a Microscope)を読みました。
Rubyのしくみ -Ruby Under a Microscope-
- 作者: Pat Shaughnessy,島田浩二,角谷信太郎
- 出版社/メーカー: オーム社
- 発売日: 2014/11/29
- メディア: 単行本(ソフトカバー)
- この商品を含むブログ (4件) を見る
Rubyの内部における実行の流れを調べる
字句解析、構文解析、コンパイルが実際にどう行われているかを Rubyに添付されている、Rubyプログラムのパーサである Ripperクラス で調査することができます。その方法を説明します。
Ruby実行の流れは 1.8.xと1.9.xで大きく異なります。
1.9.xからYARV
(Yet Another Ruby Virtual Machine)が導入されました。
- v1.8.X
- v1.9.Xより上のバージョン
[Rubyコード] =字句解析=> [トークン列] =構文解析=> [AST] =コンパイル=> [YARV命令文] => YARVで実行される
ASTは構文解析木(Abstract syntax tree)の略です。 まずは字句解析からです。 Rubyのソースコードの読み込み処理です。
字句解析
require "ripper" require "pp" code = <<STR 10.times do |n| puts n end STR puts code pp Ripper.lex(code)
- 実行結果
[[[1, 0], :on_int, "10"], [[1, 2], :on_period, "."], [[1, 3], :on_ident, "times"], [[1, 7], :on_sp, " "], [[1, 8], :on_kw, "do"], [[1, 10], :on_sp, " "], [[1, 11], :on_op, "|"], [[1, 12], :on_ident, "n"], [[1, 13], :on_op, "|"], [[1, 14], :on_ignored_nl, "\n"], [[2, 0], :on_sp, " "], [[2, 2], :on_ident, "puts"], [[2, 6], :on_sp, " "], [[2, 7], :on_ident, "n"], [[2, 8], :on_nl, "\n"], [[3, 0], :on_kw, "end"], [[3, 3], :on_nl, "\n"]]
続いて、構文解析です。
構文解析
require "ripper" require "pp" code = <<STR 10.times do |n| puts n end STR puts code pp Ripper.sexp(code)
- 実行結果
[:program, [[:method_add_block, [:call, [:@int, "10", [1, 0]], :".", [:@ident, "times", [1, 3]]], [:do_block, [:block_var, [:params, [[:@ident, "n", [1, 12]]], nil, nil, nil, nil, nil, nil], false], [[:command, [:@ident, "puts", [2, 2]], [:args_add_block, [[:var_ref, [:@ident, "n", [2, 7]]]], false]]]]]]]
最後にYARV実行命令です。
コンパイル(YARV命令を表示)
code = <<END puts 2+2 END puts RubyVM::InstructionSequence.compile(code).disasm
- 実行結果
10.times do |n| puts n end == disasm: <RubyVM::InstructionSequence:<compiled>@<compiled>>========== 0000 trace 1 ( 1) 0002 putself 0003 putobject 2 0005 putobject 2 0007 opt_mult <callinfo!mid:*, argc:1, ARGS_SKIP> 0009 opt_send_simple <callinfo!mid:puts, argc:1, FCALL|ARGS_SKIP> 0011 leave