程序员的入门其实非常简单。
打开任何一个文本编辑器(例如vim),输入下面的C代码:
#include<stdio.h>
int main()
{
printf(“hello world\n”);
return 0;
}
保存为一个扩展名为.c的文件hello.c,
然后用gcc去编译它,命令为:
gcc hello.c
就可以生成一个可执行文件a.out,
运行它就可以让计算机打印出字符串hello world。
以上就是C语言入门教材的第一节内容,其他语言的第一节内容也大同小异。
但是,你要是多问一下为什么可以这样,就可能把教你C语言的人直接问住,这就是编译原理。
C语言的源程序是一个文本文件
要想把它们转化为01机器码,首先要根据空格、换行、加减乘除等符号把程序文本分割为一个个的单词,这一步就叫作词法分析。
词法分析之后的程序文本,与人眼看到的源程序是一样的。程序从一个各种单字符构成的一个大型字符串,变成了一个个的有意义的单词。
经过词法分析之后的程序,已经属于编译器的内部表示了,脱离了源程序选择的基础母语(英文、中文、或其他语言)。
接下来要做的是语法分析,这一步是基于编程语言的语法进行的,已经与编程语言的基础母语无关了。条件语句的关键字不管是叫if还是如果,到了这一步时都会被编译器给一个数字编号,例如15。
语法分析是编译器里最复杂的代码,它会处理各种复杂的程序逻辑,最终构建一颗抽象语法树(AST)。
像多个if只有一个else的情况下,else应该隶属于哪个if,就是语法分析时要处理的问题。
例如:
int a = 0;
if (1 == 1)
if (2 == 2)
a = 2;
else
a = 1;
上面的else属于最近的if,即第二个if,这种代码都是在语法分析时处理的。
当然也可以规定它属于最远的if,但这么搞会让程序员用起来很不舒服。在技术上可以实现,但在产品体验上非常不好。
语法分析完成之后,只要遍历语法树,就可以获得类似汇编语言的三地址码序列。它是具有复杂逻辑的源程序的线性化结果。源程序都是有反应人类思维的复杂逻辑结构的,最终要转化成01数字构成的线性表,才可以装入内存运行。内存,本质上也是一个高达几个G的线性表。
三地址码序列,就是这个转化的起点。
从这里开始,程序像汇编语言一样,依赖条件判断和跳转来表达复杂的循环结构。例如源代码中的for循环。
然后,把三地址码换成汇编码,再把汇编码换成机器码,就可以在电脑上运行了。
当然机器码也可以是运行在虚拟机上的,而不是直接运行在CPU上的,就像java那样。使用虚拟机可以更容易的跨平台。
汇编码和机器码是一一对应的,只是汇编更容易被人读懂,机器码是用于电脑的。
在三地址码转化到机器码时有一个非常难的问题,就是机器指令的选择和寄存器的分配。这是一个NP问题,在现有数学理论上只能求得近似解。
在编译原理的后端,实际上会涉及到很难的数学问题。优化的越好,涉及的数学越难。
总结:
文本文件=>词法分析(文本字符切成有意义的单词)=>语法分析[如少括号]+语义分析[如变量赋值类型不符合](单词if或如果都将是同一个数字编号,并带有逻辑意义的抽象语法树AST)=>遍历语法树(获得类似汇编语言的三地址码序列)=>三地址码换成汇编码=>汇编码换成01机器码(汇编码和机器码是一一对应的,只是汇编更容易被人读懂,机器码是用于电脑的)=>运行
相关:
网友评论