我最近阅读了整本龙书(只是为了好玩,我真的不打算实现一个真正的编译器),而且我的脑子里还悬着这个大问题.
实现编译器和解释器有什么不同?
对我来说,编译器由以下部分组成:
词法分析器
解析器(构建语法树)
生成中间代码(如3地址代码)
如果你愿意,可以做所有这些疯狂的事情:-)
从3地址代码生成"汇编"或"本机代码".
现在,显然,解释器也具有与编译器相同的词法分析器和解析器.
但那之后呢?
它是否"读取"语法树并直接执行它?(有点像指针指向树中的当前节点,执行是一个大树遍历加上调用堆栈的内存管理)(如果是这样,它是如何做到的?我希望执行比检查它是什么类型的节点的巨大switch语句更好
它会生成3个地址代码并解释它吗?(如果是这样,它是如何做到的?再次,我正在寻找比一英里长的开关声明更优雅的东西)
它是否生成真正的本机代码,将其加载到内存中并使其运行?(此时我猜它不再是解释器了,但更像是JIT编译器)
此外,"虚拟机"的概念在哪一点上切入?你在一种语言中使用虚拟机是什么?(要清楚我的无知程度,对我来说虚拟机是VMWare,我不知道VM的概念如何应用于编程语言/执行程序).
如你所见,我的问题非常广泛.我主要不仅要寻找使用哪种方法,而且主要是先了解大概念,然后详细了解它的工作原理.我想要丑陋的原始细节.显然,这更像是对要阅读的东西的追求,而不是期望你在这里回答所有这些细节.
谢谢!
丹尼尔
编辑:感谢您的答案到目前为止.我意识到我的头衔有误导性.我理解编译器和解释器之间的"功能"差异.
我正在寻找的是你如何实现解释器与编译器的区别.
我现在明白如何实现编译器,问题是解释器与此有何不同.
例如:VB6显然既是编译器又是解释器.我现在了解编译器部分.但是,我无法理解,当在IDE内部运行时,它可以让我在任意点停止程序,更改代码,并使用新代码继续执行.这只是一个很小的例子,它不是我正在寻找的答案.正如我在下面解释的那样,我想要理解的是在我有一个解析树之后会发生什么.编译器将以"目标"语言从中生成新代码.口译员做什么?
谢谢您的帮助!
编译器是将一种编程语言的程序翻译成另一种编程语言的程序的程序.就是这样 - 简单明了.
解释器将编程语言翻译成其语义含义.
x86芯片是x86机器语言的解释器.
Javac是java到java虚拟机的编译器.java,可执行应用程序,是jvm的解释器.
一些解释器共享一些编译元素,因为它们可能将一种语言翻译成另一种更易于解释的内部语言.
解释器通常(但并非总是)具有读取 - 评估 - 打印循环.
简答:
编译器将源代码转换为可执行格式以供稍后执行
解释器评估源代码以立即执行
如何实施这些方面还有很大的余地.解释器可以生成本机机器代码然后执行该代码,而虚拟机的编译器可以生成p代码而不是机器代码.像Forth这样的线程解释语言在字典中查找关键字并立即执行其关联的本机代码函数.
编译器通常可以更好地优化,因为他们有更多的时间来研究代码并生成一个文件供以后执行; 口译员有更少的时间进行优化,因为他们倾向于在第一眼看到"按原样"执行代码
在后台优化的解释器,也可以学习更好的方法来执行代码
摘要:差异真正归结为"为以后的执行准备代码"或"立即执行代码"
一个程序是你想完成的工作的描述.
一个编译器转换成一个高层次的描述为一个简单的描述.
一个解释器读取做什么的描述,做的工作.
一些解释器(例如Unix shell)一次读取一个小块的描述,并在它们看到时对每个块进行操作; 一些(例如Perl,Python)读取整个描述,在内部将其转换为更简单的形式,然后对其进行操作.
一些解释器(例如Java的JVM或Pentium 4芯片)只能理解一种非常简单的描述语言,这种语言对于人类直接使用而言过于繁琐,因此人们使用编译器将其高级描述转换为该语言.
编译器从不做这项工作.口译员总是做这项工作.