文章目录
学习编译原理能让你从前端的语法维度、代码优化的维度、与硬件结合的维度几个方面,加深对计算机技术的理解,提升自己的竞争力。
编译器的前端技术
“前端”指的是编译器对程序代码的分析和理解过程。它通常只跟语言的语法有关,跟目标机器无关。“后端”则是生成目标代码的过程,跟目标机器有关。
词法分析
词法分析是把程序分割成一个个 Token 的过程,可以通过构造有限自动机来实现。
下面这段代码,如果我们要读懂它,首先要怎么做呢?
#include
int main(int argc, char* argv[]){
int age = 45;
if (age >= 17+8+20) {
printf("Hello old man!\n");
}
else{
printf("Hello young man!\n");
}
return 0;
}
如何写一个程序来识别 Token 呢?
这些规则可以通过手写程序来实现,也可以用词法分析器的生成工具来生成,比如 Lex(或其 GNU 版本,Flex)。这些生成工具是基于一些规则来工作的,这些规则用“正则文法”表达,符合正则文法的表达式称为“正则表达式”。生成工具可以读入正则表达式,生成一种叫“有限自动机”的算法,来完成具体的词法分析工作。
词法分析器也是一样,它分析整个程序的字符串,当遇到不同的字符时,会驱使它迁移到不同的状态。例如,词法分析程序在扫描 age 的时候,处于“标识符”状态,等它遇到一个 > 符号,就切换到“比较操作符”的状态。词法分析过程,就是这样一个个状态迁移的过程。
语法分析
语法分析是把程序的结构识别出来,并形成一棵便于由计算机处理的抽象语法树。可以用递归下降的算法来实现。
程序也有定义良好的语法结构,它的语法分析过程,就是构造这么一棵树。一个程序就是一棵树,这棵树叫做抽象语法树(Abstract Syntax Tree,AST)。树的每个节点(子树)是一个语法单元,这个单元的构成规则就叫“语法”。每个节点还可以有下级节点。
var a = 42;
var b = 5;
function addA(d) {
return a + d;
}
var c = addA(2) + b;
下图是这段JavaScript 语言编写的代码的 AST
怎样写程序构造AST呢?
递归下降算法是一种自顶向下的算法,与之对应的,还有自底向上的算法。这个算法会先将最下面的叶子节点识别出来,然后再组装上一级节点。有点儿像搭积木,我们总是先构造出小的单元,然后再组装成更大的单元。
语义分析
语义分析是消除语义模糊,生成一些属性信息,让计算机能够依据这些信息生成目标代码。
语义分析基本上就是做这样的事情,也就是根据语义规则进行分析判断。语义分析工作的某些成果,会作为属性标注在抽象语法树上,比如在 age 这个标识符节点和 45 这个字面量节点上,都会标识它的数据类型是 int 型的。在这个树上还可以标记很多属性,有些属性是在之前的两个阶段就被标注上了,比如所处的源代码行号,这一行的第几个字符。这样,在编译程序报错的时候,就可以比较清楚地了解出错的位置。
DSL 其实是 Domain Specific Language 的缩写,中文翻译为领域特定语言;
你知道的越多,你不知道的越多。
有道无术,术尚可求,有术无道,止于术。
如有其它问题,欢迎大家留言,我们一起讨论,一起学习,一起进步
暂无评论内容