http://hi.baidu.com/xosjfkixdgbqvyr/item/66658410b9773a14e2f986ee
最近在读 Ruby 的源码,我分析的是Ruby-lang上 的C-Ruby 1.8.7-p72的版本。
大致地浏览了Ruby的源码目录结构,用cloc统计了一下,算上扩展库里面的东东
,C-Ruby 1.8.7-p72 的代码量已经达到了15万行左右的规模,语言核心相关的
代码量大概也有5万行左右的规模。
工欲善其事,必先利其器,Ruby的源码量已经不算少了,想要有效地完成分析工
作,借助一些工具还是很有必要的。目前我准备了如下一些工具:
i. gdb
通过动态调试C-Ruby来分析其内部运行机理是非常直接的手段,其重要性自
不待言。
ii. ctags
iii. cscope
除了动态调试分析C-Ruby以外,对源码进行静态分析也是必不可少的,大量的
内部变量,内部函数,如果纯靠手工查找的话,可不是件轻松的事情,通过ctags和
cscope来协助快速定位到变量,函数的定义,以及确立变量,函数的引用点,可以
大大提高源码分析的效率。
iv. grep
在一些特别的场景下,使用ctags和cscope不能实现快速定位某个名字的任务,这
种场景下通过grep人肉查找还是很必要的。
v. Doxygen
虽然C-Ruby的代码实现中并没有遵循Doxygen的文档注释规范,但是通过Doxygen
还是能够从C-Ruby的源码中提取出一些有助于代码分析的东西,比如C-Ruby中大量的自
定义数据结构。
vi. SourceNavigator
简单来说,SourceNavigator就是Linux下一个类似于SourceInsight的工具。以前在
实验室接手虚拟BIOS的开发工具的时候,出于快速熟悉代码的需求,曾经使用过一段时间,
感觉还不错。SourceNavigator的开发曾经停滞过五年左右的时间,不过从今年的9月份
开始又开始有了更新。
C-Ruby的语法解析部分是基于Bison实现的,词法分析模块则没有使用Flex,而是手工
编写的。值得一提的是,Ruby的词法分析模块中,出于效率的考虑,引入了完美哈希生成
器gperf实现对Ruby语言的内部保留字的快速识别。
对于一个普通的Ruby脚本,C-Ruby的执行流程大致如下:
1)。 parser模块与词法模块协同工作,读入Ruby源文件中的内容,边parse源文件内容
边生成相对应的语法节点,最终在parse模块结束的时候会生成一个语法树结构
2)。 基于步骤1)中生成的语法树,对每个树结点进行解释执行。
为了获得对C-Ruby基本执行流程的更直观理解,我编写了一个简单的Ruby脚本test.rb,里
面只有 print "hello\n"这一行内容。
调用C-Ruby对test.rb进行解析执行,基本的执行流程如下:
main() // 主程序入口点
ruby_init() // Ruby解释器运行 相关的初始化
ruby_options() // 处理Ruby解释器的命令行选项,命令行指定执行的源文件也会被视
//为一个命令行选项,在ruby_options()中
//调用相应函数完成解析处理,生成语法树结构
ruby_process_options()
proc_options()
load_file()
rb_compile_file()
yycompile()
ruby_yyparse() // 此函数即为Bison生成的Parser入口函数,此函数会针对
//Ruby源文件,生成相应的语法树结构
ruby_run() // 对ruby_yyparse()生成的语法树进行解释执行
ruby_exec()
Init_stack() // 垃圾回收相关的初始化
ruby_exec_internal() // 从语法树的根结点开始解释执行语法树
eval_node() // 解释执行语法树结点
rb_eval()
rb_call() // test.rb中只包括一行语句 print "hello\n",在ruby_yyparse()中会针对 //print生成一个类型为
//NODE_FCALL的结点,在解释执行过程中,对NODE_FCALL的语法节点,
//会调用rb_call()执行相应动作
rb_get_method_body() // 获得print对应的动作函数实体
rb_call0() // 执行 print对应的实际动作,向标准输出打印hello字符串