之前听尤大说懂编译原理就能够随心所欲,因而简单地研究了一点(nai)点(nai)的编译原理,感受本身能够随心所欲了。。。前端
经典的《编译原理》一书当中,开篇大概讲解了关于编译原理的一些基本概念和编译器的基本结构:java
编译器: 一个编译器就是一个程序,它能够阅读某一种语言编写的程序,并把该程序翻译成为一个等价的、用另外一种语言(目标语言)编写的程序。 解释器,另外一种常见的语言处理器,它并不经过翻译的方式生成目标程序。从用户的角度看,解释器直接利用用户提供的输入执行源程序中指定的操做。node
词法分析(lexical analysis) 词法分析器读入源程序中的字符序列,将他们组织为具备词法含义的词素,生成并输出表明这些词素的 词法单元(token) 序列。编程
语法分析(syntax analysis) 语法分析或称解析(parsing)。语法分析器由词法分析器生成的各个词法单元建立树形的中间表示。该中间表示给出了词法分析产生的词法单元流的语法结构。一个经常使用的表示法是语法树 (syntax tree) , 树中的每一个内部结点表示一个运算,而该结点的子结点表示该运算的份量。性能优化
语义分析 (semantic anlaysis) 语义分析器使用语法树和符号表中的信息来检查源程序是否和语言定义的语义一致。 语义分析完成语法检查以及相关的自动类型转换。编程语言
中间代码生成ide
代码优化 机器无关的代码优化步骤试图改进中间代码,以便生成更好的目标代码。性能
代码生成 以源代码的中间表示形式为输入,并把他映射到目标语言。优化
虽然说,通常把上面的流程看做基本的编译原理,可是,大部分编程语言的编译器都和这个流程有些不一样。ui
这里参考了另一本书 -- 《WebKit 技术内幕》。
从 C/C++语言提及。编译器会将咱们编写的代码编译为本地代码(适合当前计算机运行的指令集)。
当须要执行程序时, CPU 能够直接执行这些本地代码,无需其余处理。
再来看看脚本语言 Python。通常地,当须要执行 Python 程序时,由解释器直接解释执行开发者写的代码。
接下来看看 Java。Java 首先是和 C++同样的编译阶段,不一样的是编译生成了字节码。字节码的特色是与平台无关,能够运行在不一样的操做系统上。 Java 的运行环境中,使用 Java 虚拟机加载字节码,而后:
这里说了一个 JIT 的概念,百度了一下,大体特色以下:
最后看看前端的主角 JavaScript。JavaScript 本是一个解释型脚本语言。由于早期是由解释器解释执行,即将源代码转为抽象语法树,而后在抽象语法树上解释执行。 在 JavaScript 引擎的发展中,为了提升性能,引入了 Java 虚拟机和 C++编译器中的众多技术。如今 JavaScript 引擎的执行过程大体是:
关于 V8 的身世和众多的黑科技咱们不去追究,反正一提到 V8 引擎,知道很牛逼就是了。 相对上面提到的典型的 JavaScript 引擎,V8 的编译采用了比较激进的方式,将抽象语法树经过 JIT 技术直接转换成本地代码。 这么作能够减小抽象语法树到字节码的转换时间,同时也带了一些问题:
对于这些问题,V8 也在解决:5.9 版本开始新增了一个 Ignition 字节码解释器。关于这个话题,下面引用一段话,更多细节能够看这里。
Ignition + TurboFan 的组合,就是字节码解释器 + JIT 编译器的黄金组合。这一黄金组合在不少 JS 引擎中都有所使用,例如微软的 Chakra,它首先解释执行字节码,而后观察执行状况,若是发现热点代码,那么后台的 JIT 就把字节码编译成高效代码,以后便只执行高效代码而再也不解释执行字节码。苹果公司的 SquirrelFish Extreme 也引入了 JIT。SpiderMonkey 更是如此,全部 JS 代码最初都是被解释器解释执行的,解释器同时收集执行信息,当它发现代码变热了以后,JaegerMonkey、IonMonkey 等 JIT 便登场,来编译生成高效的机器码。
《编译原理》 很经典,很好的一本书,翻译很精准。好比,词法分析的结果 token,书中翻译为词法单元,可是国内不少的博客会都翻译为令牌,这就很使人费解。
《WebKit 技术内幕》 仅仅看了 JavaScript 引擎一段,感受做者不太用心。有错别字,好比把整型写成了整形。最尴尬的是不少的语句不通。感受是直接怼的谷歌翻译的结果。最骚的是,这是国人原著而非翻译书籍。。。 后来百度了一下,听说这本书的内容是根据做者的我的博客整理的。