写c语言编译器教程(教你做C语言编译器设计)

C语言是面向过程的,而C++是面向对象的

C和C 的区别:

C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制)。

C ,首要考虑的是如何构造一个对象模型,让这个模型能够契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。 所以C与C 的最大区别在于它们的用于解决问题的思想方法不一样。之所以说C 比C更先进,是因为“ 设计这个概念已经被融入到C 之中 ”。

C与C 的最大区别:在于它们的用于解决问题的思想方法不一样。之所以说C 比C更先进,是因为“ 设计这个概念已经被融入到C 之中 ”,而就语言本身而言,在C中更多的是算法的概念。那么是不是C就不重要了,错!算法是程序设计的基础,好的设计如果没有好的算法,一样不行。而且,“C加上好的设计”也能写出非常好的东西。

写c语言编译器教程(教你做C语言编译器设计)(1)

前言

为什么要学编译事理

若是要我说计较机专业最重要的三门课,我会说是《数据构造》、《算法》和《编译事理》。在我看来,能不能理解“递归”像是轨范员的第一道门槛,而会不会写编译器则是第二道。

(固然,并不是说是没写过编译器就不是好轨范员,只能说它是一个相称大的挑战吧)

从前人们会说,进修了编译事理,你就能写出加倍高效的代码,但跟着计较机机能的晋升,代码是否高效显得就不那么重要了。那么为什么要进修编译事理呢?

缘故缘由只需一个:装B。

好吧,大概如今还想进修编译事理的人只可能是由于乐趣了。一方面想体味它的工作事理;另一方面希望挑战一下本身,看看本身能走多远。

理论很复杂,实现也很复杂?

我对编译器不息心存钦佩。所以当黉舍开《编译事理》的课程后,我是抱着满腔热情去上课的,可是两节课后我就抛却了。缘故缘由是太复杂了,听不懂。

写c语言编译器教程(教你做C语言编译器设计)(2)

一样平常编译事理的课程会说一些:

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语言编译器设计)(3)

这些是C/C 能做的

服务器开发工程师、人工智能、云计算工程师、信息安全(黑客反黑客)、大数据 、数据平台、嵌入式工程师、流媒体服务器、数据控解、图像处理、音频视频开发工程师、游戏服务器、分布式系统、游戏辅助等

1、实现一个功能完满的 C 说话编译器

2、经由过程教程来声名这个过程。

c4 大抵500 行。重写的代码历时一周,统共代码加解释1400行

声明:本项目中的代码逻辑绝大多数取自 c4 ,但确为本身重写。

预警

在写编译器的时辰会碰着两个首要问题:

1、费事,会有良多近似的代码,写起来很无聊。

2、难以调试,一方面没有很好的测试用例,另一方面必要比力生成的代码来调试(碰着的时辰就晓得了)。

所以我希望你有充足的耐心和时辰来进修,信托当你真正完成的时辰会像我一样,非常有造诣感。

虽然问题是编译器,但实际上我们构建的是 C 说话的诠释器,这意味着我们可以像运转剧本一样去运转 C 说话的源代码文件。这么做的理由有两点:

1、诠释器与编译器仅在代码生成阶段有区别,而其它方面如词法分析、语法分析是一样的。

2、诠释器必要我们实现本身的假造机与指令集,而这局部能辅佐我们体味计较机的工作事理。

写c语言编译器教程(教你做C语言编译器设计)(4)

编译器的构建流程

一样平常而言,编译器的编写分为 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语言编译器设计)(5)

C/C 永不过时的语言。上面的代码看上去挺复杂,但其实内容不多,就是读取一个源代码文件,逐个读取每个字符,并输出每个字符。这里重要的是注意每个函数的浸染,后面的文章中,我们将逐个填充每个函数的功能,终极构建起我们的编译器。

,

免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com

    分享
    投诉
    首页