写c语言编译器教程(教你做C语言编译器设计)
C语言是面向过程的,而C++是面向对象的
C和C 的区别:
C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制)。
C ,首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。 所以C与C 的最大区别在于它们的用于解决问题的思想方法不一样。之所以说C 比C更先进,是因为“ 设计这个概念已经被融入到C 之中 ”。
C与C 的最大区别:在于它们的用于解决问题的思想方法不一样。之所以说C 比C更先进,是因为“ 设计这个概念已经被融入到C 之中 ”,而就语言本身而言,在C中更多的是算法的概念。那么是不是C就不重要了,错!算法是程序设计的基础,好的设计如果没有好的算法,一样不行。而且,“C加上好的设计”也能写出非常好的东西。
前言
为什么要学编译事理
若是要我说计较机专业最重要的三门课,我会说是《数据构造》、《算法》和《编译事理》。在我看来,能不能理解“递归”像是轨范员的第一道门槛,而会不会写编译器则是第二道。
(固然,并不是说是没写过编译器就不是好轨范员,只能说它是一个相称大的挑战吧)
从前人们会说,进修了编译事理,你就能写出加倍高效的代码,但跟着计较机机能的晋升,代码是否高效显得就不那么重要了。那么为什么要进修编译事理呢?
缘故缘由只需一个:装B。
好吧,大概如今还想进修编译事理的人只可能是由于乐趣了。一方面想体味它的工作事理;另一方面希望挑战一下本身,看看本身能走多远。
理论很复杂,实现也很复杂?
我对编译器不息心存钦佩。所以当黉舍开《编译事理》的课程后,我是抱着满腔热情去上课的,可是两节课后我就抛却了。缘故缘由是太复杂了,听不懂。
一样平常编译事理的课程会说一些:
1、若何表示语法(BNF什么的)
2、词法分析,用什么有穷自念头和无限自念头
3、语法分析,递归降落法,什么 LL(k),LALR 分析。
4、中心代码的表示
5、代码的生成
6、代码优化
我信托绝大多数(98%)的门生顶多学到语法分析就竣事了。并且最重要的是,学了这么多也没用!仍旧辅佐不了我们进修编译器!这其中最首要的缘故缘由是《编译事理》试图教会我们的是若何机关“编译器生成器”,即机关一个工具,按照文法来生成编译器(如 lex/yacc)等等。
这些理论试图教会我们若何用通用的编制来主动处理问题,它们有很强的实际意义,只是对付一样平常的门生或轨范员来说,它们过于强大,内容过于复杂。若是你考试考试阅读 lex/yacc (或 flex/bison)的代码,就会创造太恐惧了。
然而若是你能跟我一样,真正来实现一个简单的编译器,那么你会创造,比起恐惧的《编译事理》,这点复杂度仍是不算什么的(由于良多若干好多理论根柢用不上)。
项目的初志
有一次在 Github 上看到了一个项目(那时很火的),名叫 c4,号称用 4 个函数来实现了一个小的 C 说话编译器。它最让我震动的是可以自举,即能本身编译本身。并且它用很少的代码就完成了一个功能相称完满的 C 说话编译器。
一样平常的编译器相干的教程要么就非常简单(照实现四则运算),要么就是借助了主动生成的工具(如 flex/bison)。而 c4 的代码美全是手工实现的,不消外部工具。可惜的是它的代码初志是代码最小化,所以写得很乱,很难明。所以本项目的首要目的:
这些是C/C 能做的
服务器开发工程师、人工智能、云计算工程师、信息安全(黑客反黑客)、大数据 、数据平台、嵌入式工程师、流媒体服务器、数据控解、图像处理、音频视频开发工程师、游戏服务器、分布式系统、游戏辅助等
1、实现一个功能完满的 C 说话编译器
2、经由过程教程来声名这个过程。
c4 大抵500 行。重写的代码历时一周,统共代码加解释1400行
声明:本项目中的代码逻辑绝大多数取自 c4 ,但确为本身重写。
预警
在写编译器的时辰会碰着两个首要问题:
1、费事,会有良多近似的代码,写起来很无聊。
2、难以调试,一方面没有很好的测试用例,另一方面必要比力生成的代码来调试(碰着的时辰就晓得了)。
所以我希望你有充足的耐心和时辰来进修,信托当你真正完成的时辰会像我一样,非常有造诣感。
虽然问题是编译器,但实际上我们构建的是 C 说话的诠释器,这意味着我们可以像运转剧本一样去运转 C 说话的源代码文件。这么做的理由有两点:
1、诠释器与编译器仅在代码生成阶段有区别,而其它方面如词法分析、语法分析是一样的。
2、诠释器必要我们实现本身的假造机与指令集,而这局部能辅佐我们体味计较机的工作事理。
编译器的构建流程
一样平常而言,编译器的编写分为 3 个轨范:
1、词法分析器,用于将字符串转化成内部的表示构造。
2、语法分析器,将词法分析获得的标识表记标帜流(token)生成一棵语法树。
3、方针代码的生成,将语法树转化成方针代码。
已经有良多工具能辅佐我们措置阶段1和2,如 flex 用于词法分析,bison 用于语法分析。只是它们的功能都过于强大,屏障了良多实现上的细节,对付进修构建编译器辅佐不大。所以我们要完全手写这些功能。
所以我们会按照下面的流程:
1、构建我们本身的假造机以及指令集。这后生成的方针代码便是我们的指令集。
2、构建我们的词法分析器
3、构建语法分析器
编译器的框架
我们的编译器首要网罗 4 个函数:
1、next() 用于词法分析,获取下一个标识表记标帜,它将主动忽略空白字符。
2、program() 语法分析的进口,分析整个 C 说话轨范。
3、expression(level) 用于解析一个表达式。
4、eval() 假造机的进口,用于诠释方针代码。
这里有一个零丁用于解析“表达式”的函数 expression 是由于表达式在语法分析中相对独立并且斗劲复杂,所以我们将它零丁作为一个模块(函数)。
由于我们的源代码看起来就像是:
#include
#include
#include
#include
int token; // current token
char *src, *old_src; // pointer to source code string;
int poolsize; // default size of text/data/stack
int line; // line number
void next() {
token = *src ;
return;
}
void expression(int level) {
// do nothing
}
void program() {
next(); // get next token
while (token > 0) {
printf("token is: %c\n", token);
next();
}
}
int eval() { // do nothing yet
return 0;
}
int main(int argc, char **argv)
{
int i, fd;
argc--;
argv ;
poolsize = 256 * 1024; // arbitrary size
line = 1;
if ((fd = open(*argv, 0)) < 0) {
printf("could not open(%s)\n", *argv);
return -1;
}
if (!(src = old_src = malloc(poolsize))) {
printf("could not malloc(%d) for source area\n", poolsize);
return -1;
}
// read the source file
if ((i = read(fd, src, poolsize-1)) <= 0) {
printf("read() returned %d\n", i);
return -1;
}
src[i] = 0; // add EOF character
close(fd);
program();
return eval();
}
C/C 永不过时的语言。上面的代码看上去挺复杂,但其实内容不多,就是读取一个源代码文件,逐个读取每个字符,并输出每个字符。这里重要的是注意每个函数的浸染,后面的文章中,我们将逐个填充每个函数的功能,终极构建起我们的编译器。
,免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com