编译器

大家好,好久没看到喵了,是不是想我了。

这是本喵看到的一篇好文章,所以忍不住想要拿过来。

知乎上有一种说法是「编译器、图形学、操作系统是程序员的三大浪漫」。

先不管这个说法是对是错,我们假设一个程序员在国内互联网公司写代码,业余时间不看相关书籍。那么三年之后,他的这些知识会比在校时损耗多少?

很显然,损耗的比例肯定非常高,毕竟国内互联网公司日常开发工作中,程序员基本很少接触这三块知识。大部分程序员工作几年后对编译原理相关的概念只能生理上起反应,脑海里很难再串联起相关概念了。

编译原理的概念有让人看到就头痛的特质,学校里要死记硬背,考试过了巴不得赶紧全忘掉,相信不少同学现在看到下面概念还会觉得蛋疼:

非确定性有限自动机/确定性有限自动机

四元式序列

上下文无关文法/BNF

终结符/非终结符

LL(1)/LR(1)

特设语法制导转换

局部优化

其实本喵在学习这门课的时候也很烦脑,毕竟这是号称最难学的一门学科之一。本喵是在大四的时候学的这门课,经过半个学期死命的看书,也还是懵懵懂懂,不怎么明白。但好在考试的时候过了。

什么是编译器

广义的编译器可以指任意把一种语言代码转为另一种语言代码的程序

做编译器实际上都需要做什么

编译器是一整套工具链,从前端的词法分析、语法分析,到中间表示生成、检查、分析、优化,再到代码生成。

如果是编译器从业者,大部分时间在做中间这块;如果是业余爱好者,大部分时间在做前端和代码生成。

先确定源语言:

这是一门看起来像lisp的四则运算语言,四个双目运算符分别是「add」「sub」「mul」「div」。

多项四则运算可以这样写:

(mul(sub5(add12))4

再来确定目标语言:

同样是一门四则运算语言,但是看起来可读性更强,对应的四个双目运算符分别是「+」「-」「*」「/」。

上面源语言的例子编译完后应该是这样:

((5 -(1 +2))* 4)

最后确定我们写编译器要用的语言:

喵选择Haskell,有两个原因,一是写Haskell有大名鼎鼎的ParseC,写Parser非常方便;二是Haskell的代数数据类型的定义本身就是AST。

ParseC的全称是Parser组合子。Parser,抽象理解就是一个输入为字符串输出为类型T的值的函数。ParseC库实现了大量基础Parser和Parser组合子,Parser组合子可以将库自带的基础Parser和用户定义的Parser随意组合成新的更强大的Parser。

举个例子,你实现了一个Parser,功能是根据输入文本返回解析到的标识符名称。ParseC库实现了一个名叫many的parser组合子,跟你自己的Parser组合起来就产生了一个新的Parser:可以根据输入文本返回解析到的标识符名称list。

为什么要用ParseC呢?因为用ParseC定义Parser具有PEG(解析表达式文法,原理不细讲,不影响接下来学习)的所有好处,同时还不用再学习语言之外的知识(比如用flex和bison前要先学习这两者自己的「DSL」)。

当然,其他语言也有类似的库,比如c++有boost::spirit,Java/C#/F#/JS有Haskell的ParseC的工业级实现。这些语言跟Haskell的区别无非在于要写一些额外的逻辑把Parser的解析结果转成AST。

如果没有接触过Haskell的话也没关系,接下来的示例代码都非常declarative,非常self-descriptive,请放心食用。

接下来就开始写代码了,首先我们要定义AST的结构,目的是为了能用这个结构描述一切源语言表达式。

简单分析一下源语言,我们可以直接得出表达式这个概念的递归定义:一个表达式要么是一个字面值,要么是一个双目运算符和两个表达式的求值结果。

然后是字面值这个概念的递归定义:一个字面值要么是一个整型值,要么是一个浮点型值。

在Haskell里面这两个定义写成下面这样:

跟前面的文字定义对应一下:

表达式Exp,要么是一个字面值表达式ConstExp,由一个Val组成;要么是一个双目运算表达式BinOpExp,由一个操作符和两个Exp组成。

值Val,要么是一个整型值IntVal,由一个Integer组成;要么是一个浮点型值FloatVal,由一个Float组成。

接下来开始写Parser。流程是先为AST中的每个节点类型写一个parser,然后再把这些parser组合起来形成能parse出整棵AST的parser。

我们先给自己定个小目标,比如先实现一个int_parser。

p_int是能从文本中Parse出Integer的Parser定义。而p_int_val改造了p_int,定义了能从文本中Parse出IntVal的Parser。

然后我们把int和float的parser组合起来成为一个val_parser。

listplus可以简单理解为并,在具体实现上会做回溯。

同理,我们先分别实现ConstExp的parser和BinOpExp的parser,再把两者组合为exp_parser。

到目前为止,我们的parser部分就完工了。

对Haskell有兴趣的同学,可以安装下ghci,是haskell的REPL,然后加载刚才写好的Parser.hs,在命令行里试一下

可以看到输出结果。稍微排版下,输出结果变成了我们熟悉的树形结构,Op为「mul」的BinOpExp就是树的根节点。整个输出就是一棵AST。

有了这棵AST,我们就可以开始做后续的代码生成了。

CodeGenerator的主体是把Exp转换成目标语言代码的函数:

利用模式匹配这个语言特性实现多态既容易又优雅。

最后再套个壳,比如读源文件,写目标文件,整个编译器就大功告成了

好了,到了和大家说再见的时候了。如果有兴趣可以去:http://mp.weixin.qq.com/s?__biz=MzIwNDU2MTI4NQ==&mid=2247483679&idx=1&sn=8df4b40386fb6182051f4926ab043636#rd这个网址看看。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,457评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,837评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,696评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,183评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,057评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,105评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,520评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,211评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,482评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,574评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,353评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,213评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,576评论 3 298
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,897评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,489评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,683评论 2 335

推荐阅读更多精彩内容