编译语言的优点vs一旦构造就执行AST

imk*_*dal 7 compiler-construction interpreter machine-code abstract-syntax-tree

将程序编译为机器代码而不是简单地从源代码构造AST并在遍历树时执行操作有什么好处/缺点?

你有什么理由想要一个人做另一个吗?

Gen*_*ene 9

解释AST通常比运行相同的机器代码要慢得多.通常为20倍.

一个优点是AST生成速度更快,因此比大多数编译器生成代码所花费的时间更少.AST解释器也比编译器更简单,因为可以忽略整个代码生成阶段.

因此,如果您的程序没有进行繁重的计算,那么使用解释程序的程序就会更快.另一方面,如果您的代码在循环稀缺的环境中经常或连续运行,那么编译后会更好.

一些编程环境(例如许多lisps)包括用于开发代码的解释器,因为它支持快速调试周期,以及用于在开发完成时生成快速代码的编译器.其中一些系统允许自由混合解释和编译代码,这本身就很有趣.

编译为字节码是一个中间立场:编译比机器代码更快,但执行速度比AST快.尽管如此,现代字节码解释器通常在程序运行时"及时"编译为本机代码.这就是Sun的HotSpot JVM名称的来源.它将Java字节码中的"热点"编译为本机代码,以便在运行时加速程序.

回答评论中的问题

关于上面提到的因子20有一个问题.支持这个数字的引用很老,因为很少有现代语言系统使用纯AST解释器.(一个值得注意的例外是命令外壳,但其中大部分是很久以前开发的,速度基准测试并不常见.)它们太慢了.我的上下文是lisp解释器.我实施了一对.这里例如是一组Scheme基准.与AST解释器对应的列很容易挑选出来.如果有需求,我可以从ACM数字图书馆档案中发布更多和类似的内容.

另一个粗略的基准:Perl使用经过大量优化的AST解释器.要在我的机器上紧密循环添加1000万个浮动需要大约7秒钟.编译C(gcc -O1)大约需要1/20秒.

评论者提出了4个变量的加法作为例子.分析忘记了查找的成本.解释器和编译器之间的一个明确的分界线是符号的预先计算的地址或帧偏移.在一个"纯粹的"翻译中没有.因此,添加4个数字需要在运行时环境中进行4次查找,通常是哈希表 - 至少100条指令.在良好的编译代码中,在x86上添加4个整数需要2个指令,另外一个用于存储结果.

"纯粹的"AST插件和编译的机器代码之间有许多阴影.根据语言,可以将符号偏移编译到AST中.这有时被称为"快速链接".该技术通常可将速度提高一倍或更多.然后是"compile-to-bytecode and go"系统,如Python,PHP,Perl,Ruby 1.9+.它们的字节码实际上是线程代码(操作码会导致非常复杂的事情发生),因此它们比机器代码更接近AST.然后是我上面提到的JIT字节码解释器.

关键是20个纯AST解释器的因子是一个书挡而机器码是另一个.在中间有许多变体,每个变体都有优点和缺点.