编译原理概述

前言

为什么要学习编译原理? IT行业日新月异,新技术层出不穷,然而这些新技术所依赖的底层技术,如操作系统、计算机系统原理、数据结构与算法、网络、编译原理等依然没多大变化,只有掌握了这些基础技术,在面对新技术才能拨开新技术的迷雾一窥究竟。就好比应用层的知识就是拳法招式,而底层基础知识就好比战马步、练肌肉。所谓练拳不练功,到老一场空,而这些功法中编译原理就是基础之一。编译技术是计算机科学皇冠上的明珠之一,如比尔·盖茨早期最主要的成就,就是写了一个 Basic 的解释器,国外的巨头企业谷歌、微软、苹果这些技术巨头们的核心能力,都是拥有自己的语 言和生态。可见编译技术有多么重要。

编译原理与工作

许多程序员会说,在日常工作中不会去设计一门新的语言,编译原理离得很遥远,其实不然在实际工作中你经常会碰到需要编译技术的场景。比如java 如果你要深入理解和用好如hibernate、和spring(编译技术做 HQL 的解析,对注解的支持和字节码动态生成) 这类工具,以及这类型的工具,会需要编译技术。还有要参与编写一个基础设施类的软件,很多需要采用编译技术提供软件自带的语言功能、还有运维工程师分析日志文件等等高级别的需求,都要用到编译技术。除了丰富的应用场景,学习编译技术对于提升程序员的竞争力也很重要,学习编译原理能让你从前端的语法维度、代码优化的维度、与硬件结合的维度几个方面,加 深对计算机技术的理解,提升自己的竞争力。

编译原理前端技术

编译器前端技术,也就是通常说的词法分析、语法分析和语义分析。这里的“前端”指的是编译器对程序代码的分析和理解过程,主要跟语言的语法有关,跟目标机器无关。而与之对应的“后端”则是生成目标代码的过程,跟目标机器有 关。而它主要涉及自动机和形式语言方面的基础的计算理论。
在这里插入图片描述

词法分析

通常,编译器的第一项工作叫作词法分析。就像阅读文章一样,由一个个中文单词组成的,程序也一样只不过这不叫单词,而叫做“词法记号”,英文叫 Token。

语法分析

词法分析是识别一个个的单词,而语法分析就是在词法分析的基础上识别出程序的语法结构。这个结构是一个树状结构,是计算机容易理解和执行的。一个程序就是一 棵树,这棵树叫做抽象语法树(Abstract Syntax Tree,AST),语法分析是把程序的结构识别出来,并形成一棵便于由计算机处理的抽象语法树。可以用递归下降的算法来实现。

语义分析

语义分析是消除语义模糊,生成一些属性信息,让计算机能够依据这些信息生成目标代码。
前端技术编译过程跟实际工作息息相关。比如,词法分析就是你工作中使用正则表达式的过程。而语法分析在你解析文本文件、配置文件、模型定义文件,或者做自定义公式功能的时候都会用到。

无结构的代码文本,经过前端编译技术的处理以后,就变成了 Token、AST 和语义属性、符号表等结 构化的信息。

编译原理后端技术

编译器的前端技术它的重点,是让编译器能够读懂程序。此外我们需要继续把程序编译成机器能读懂的代码,并高效运行。编译器后端技术,也就是如何生成目标代码和对代码进行优化的过程。
主要面临的问题:

  • 了解计算机运行一个程序的原理(也就是运行期机制),只有这样,才知道如 何生成这样的程序。
  • 利用前端生成的 AST 和属性信息,将其正确翻译成目标代码。
  • 需要对程序做尽可能多的优化,比如让程序执行效率更高,占空间更少等等。

弄清程序的运行机制

现在给你一台计算机,你怎么生成一个可以运行的程序,然后还能让这个程序在计算机上正确和高效地运行?
在这里插入图片描述
程序运行的过程中,主要是跟两个硬件(CPU 和内存)以及一个软件(操作系统)打交道。两个硬件:
CPU,它能接受机器指令和数据,并进行计算。它里面有寄存器、高速缓存和运 算单元,充分利用寄存器和高速缓存会让系统的性能大大提升。
内存。我们要在内存里保存编译好的代码和数据,还要设计一套机制,让程序最 高效地利用这些内存。通常情况下,我们的程序要受某个操作系统的管理,所以也要符合操作系统的一些约定。编译器后端技术跟计算机体系结构的关系很密切。我们必须清楚地理解计算机程序是怎么运行的,有了这个基础,才能探讨如何编译生成这样的程序。

生成代码

编译器后端的最终结果,就是生成目标代码。如果目标是在计算机上直接运行,那这个目标代码指的是汇编代码 如c语言。而如果运行目标是 Java 虚拟机,那这个目 标代码就是指 JVM 的字节码。写汇编跟使用高级语言有很多不同,其中一点就是要关心 CPU 和内存这样具体的硬 件。如果每种语言,需要针对每种不同的硬件,都要生成不同的汇编代码。设计一门语言要 支持尽可能多的硬件平台,为了减少低后端工作量,提高软件复用度,就需要引入中间代码(Intermediate Representation,IR)的机制,我们可以把各种语言翻译成中间代码,再针对每一种目标架构,通过一个程序将中间代码翻译成相应的汇编代码。

代码分析和优化

直接翻译生成的代码不够简洁,多是考虑正确性,没有去兼顾优化,还有就是高级语言和编码习惯也会导致代码不够优化,不能发挥计算机性能所以我们一定要对代码做优化。一个语言的性能太差,就会影响它的使用和普及。
优化工作又分为“独立于机器的优化”和“依赖于机器的优化”两种。独立于机器的优化,是基于 IR 进行的。它可以通过对代码的分析,用更加高效的代码代替 原来的代码。依赖于机器的优化,则是依赖于硬件的特征。比如寄存器优化、充分利用高速缓存、提高程序并行性、流水线异步处理、指令选择、GPUAI方面优化。

总结:

前端关注的是正确反映了代码含义的静态结构,编译器的后端,要把高级语言翻译成计算机能够理解的目标语言。它跟前端相比,后端关注的是让代码良好运行的动态结构。还有就是编译技术新趋势 比如现在的人工智能编程、云计算领域编程的新模式等会不会有大的进步了