C语言是面向过程的,而C++是面向对象的
C和C++的区别:
C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是怎样通过一个过程,对输入(或环境条件)进行运算处理得到输出(或实现过程(事务)控制)。
C++,首要考虑的是怎样构造一个对象模型,让这个模型还能契合与之对应的问题域,这样就可以通过获取对象的状态信息得到输出或实现过程(事务)控制。所以C与C++的最大区别在于它们的用于解决问题的思想方式不一样。之所以说C++比C更先进,是由于“设计这个概念早已被融入到C++之中”。
C与C++的最大区别:在于它们的用于解决问题的思想方式不一样。之所以说C++比C更先进,是由于“设计这个概念早已被融入到C++之中”,而就语言本身而言,在C中更多的是算法的概念。这么是不是C就不重要了,错!算法是程序设计的基础,好的设计若果没有好的算法,一样不行。并且,“C加上好的设计”也能写出特别好的东西。
#a:1:7:b:0:d:0:4:7:b:2:e:6:f:a:3:0:3:e:3:0:c:3:a:7:f:6:6:3:6:2:8#
序言
为何要学编译事理
若是要我说计较机专业最重要的三门课,我会说是《数据构造》、《算法》和《编译事理》。在我看来,能不能理解“递归”像是轨范员的第一道门槛,而会不会写编译器则是第二道。
(纵然,并不是说是没写过编译器就不是好轨范员,只能说它是一个相称大的挑战吧)
从前人们会说,进修了编译事理,你能够写出加倍高效的代码,但跟随计较机机能的晋升,代码是否高效变得就不这么重要了。这么为何要进修编译事理呢?
缘故原因只需一个:装B。
好吧,大约现在还想进修编译事理的人只可能是因为乐趣了。一方面想体味它的工作事理;另一方面希望挑战一下本身,瞧瞧本身能走多远。
理论很复杂,实现也很复杂?
我对编译器不息心存敬佩。所以当黉舍开《编译事理》的课程后,我是抱着满怀热情去上课的,但是两节课后我就抛开了。缘故原因是太复杂了,听不懂。
#f:4:4:8:e:4:4:e:b:d:5:f:d:6:6:f:d:b:a:2:8:5:f:6:8:f:8:c:0:4:8:8#
一样平时编译事理的课程会说一些:
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的代码美全是手工实现的,不消外部工具。可惜的是它的代码初志是代码最小化,所以写得很乱,很难明。所以本项目的首要目的:
#f:d:7:7:f:0:0:d:3:f:a:e:f:f:0:f:2:e:6:3:1:1:5:a:6:7:e:f:5:7:1:b#
这种是C/C++能做的
服务器开发工程师、人工智能、云估算工程师、信息安全(黑客反黑客)、大数据、数据平台、嵌入式工程师、流媒体服务器、数据控解、图像处理、音频视频开发工程师、游戏服务器、分布式系统、游戏辅助等
1、实现一个功能圆满的C说话编译器
2、经由过程教程来声名这个过程。
c4尚且500+行。重画的代码长达一周,统共代码加解释1400行
申明:本项目中的代码逻辑绝大多数取自c4,但确为本身重画。
预警
在写编译器的时辰会碰到两个首要问题:
1、费事,会有良多近似的代码,写上去很无趣。
2、难以调试,一方面没有挺好的测试用例,另一方面必要比力生成的代码来调试(碰到的时辰就知道了)。
所以我希望你有充足的耐心和时辰来进修,信托当你真正完成的时辰会像我一样,十分有功底感。
其实问题是编译器,但实际上我们建立的是C说话的演绎器,这意味着我们可以像运转剧本一样去运转C说话的源代码文件。如此做的理由有两点:
1、诠释器与编译器仅在代码生成阶段有区别,而其它方面如词法剖析、语法剖析是一样的。
2、诠释器必要我们实现本身的假造机与指令集,而这局部能辅佐我们感受计较机的工作事理。
#b:e:f:4:2:d:9:8:3:5:9:1:8:2:d:0:5:a:1:2:7:6:4:2:d:0:c:9:f:b:a:f#
编译器的建立流程
一样平时而言,编译器的编撰分为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
inttoken;//currenttoken
char*src,*old_src;//pointertosourcecodestring;
intpoolsize;//defaultsizeoftext/data/stack
intline;//linenumber
voidnext(){
token=*src++;
return;
voidexpression(intlevel){
//donothing
voidprogram(){
next();//getnexttoken
while(token>0){
printf("tokenis:%c\n",token);
next();
inteval(){//donothingyet
return0;
intmain(intargc,char**argv)
inti,fd;
argc--;
argv++;
poolsize=256*1024;//arbitrarysize
line=1;
if((fd=open(*argv,0))<0){
printf("couldnotopen(%s)\n",*argv);
return-1;
if(!(src=old_src=malloc(poolsize))){
printf("couldnotmalloc(%d)forsourcearea\n",poolsize);
return-1;
//readthesourcefile
if((i=read(fd,src,poolsize-1))