美文网首页
读书笔记:显微镜下的Ruby(一)

读书笔记:显微镜下的Ruby(一)

作者: Hegwin | 来源:发表于2017-08-08 18:29 被阅读0次
  1. Ruby代码的运行

在1.9及以后版本的Ruby中,原代码运行要经过好几个步骤:
分词:得到词条
解析:得到抽象语法树(AST)
编译:使用YARV从AST转化到字节码

  1. 关于分词
    可以使用Ripper查看Ruby分词的结果:
require 'ripper'

code = <<CODE
10.times do |n|
  puts n
end
CODE

p Ripper.lex(code)

#=>
[[[1, 0], :on_int, "10"],
 [[1, 2], :on_period, "."],
 [[1, 3], :on_ident, "times"],
 [[1, 8], :on_sp, " "],
 [[1, 9], :on_kw, "do"],
 [[1, 11], :on_sp, " "],
 [[1, 12], :on_op, "|"],
 [[1, 13], :on_ident, "n"],
 [[1, 14], :on_op, "|"],
 [[1, 15], :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"]]

  1. 关于解析
    Ruby使用Bison,在构建过程中创建解析器。
    LALR算法:向前查看反向最右推导
    解析后的结果是AST语法树,可以通过Ripper查看:
require 'ripper'
require 'pp'

code = <<CODE
2 + 2 * 3
CODE

pp Ripper.sexp(code)

#=>

[:program,
 [[:binary,
   [:@int, "2", [1, 0]],
   :+,
   [:binary, [:@int, "2", [1, 4]], :*, [:@int, "3", [1, 8]]]]]]
=> [:program, [[:binary, [:@int, "2", [1, 0]], :+, [:binary, [:@int, "2", [1, 4]], :*, [:@int, "3", [1, 8]]]]]]

  1. 关于编译
    RubyVM::InstructionSequence可以帮助显示Ruby编译后的YARV指令。
code = <<CODE
10.times do |n|
  puts n
end
CODE

puts RubyVM::InstructionSequence.compile(code).disasm

#=>

== disasm: #<ISeq:<compiled>@<compiled>>================================
== catch table
| catch type: break  st: 0002 ed: 0008 sp: 0000 cont: 0008
|------------------------------------------------------------------------
0000 trace            1                                               (   1)
0002 putobject        10
0004 send             <callinfo!mid:times, argc:0>, <callcache>, block in <compiled>
0008 leave            
== disasm: #<ISeq:block in <compiled>@<compiled>>=======================
== catch table
| catch type: redo   st: 0002 ed: 0010 sp: 0000 cont: 0002
| catch type: next   st: 0002 ed: 0010 sp: 0000 cont: 0010
|------------------------------------------------------------------------
local table (size: 2, argc: 1 [opts: 0, rest: -1, post: 0, block: -1, kw: -1@-1, kwrest: -1])
[ 2] n<Arg>     
0000 trace            256                                             (   1)
0002 trace            1                                               (   2)
0004 putself          
0005 getlocal_OP__WC__0 2
0007 opt_send_without_block <callinfo!mid:puts, argc:1, FCALL|ARGS_SIMPLE>, <callcache>
0010 trace            512                                             (   3)
0012 leave                                                            (   2)

这段代码里有个do...end块,所以在YARV指令里可以看到本地表(local table)的存在。

相关文章

网友评论

      本文标题:读书笔记:显微镜下的Ruby(一)

      本文链接:https://www.haomeiwen.com/subject/rccxrxtx.html