编译原理是我最头疼的科目之一。先后学了3次,都没有真正理解(却还大言不惭地写了点“体会”),现在算是第4次学。计算机学到现在,最深的体会就是什么东西都只有自己动手做一遍,方才有真正的理解。现在,编译原理方面的实践还很少,所以理解也还很浅,只能
谈些自己的学习经历。
目前在看的教材是Compiler Design in C。这本书最大的优点是提供了完整的编译器代码,但是,是用C写的,而我C的基础很差,平时
工作中用的也是C#。不过,C程序写不来,看还看得懂一些。硬着头皮看下去,目前正在看词法分析的将NFA转成DFA的部分。
另外,利用现成的C#语法和Antlr工具,做了个简单的代码分析工具(统计每个类和方法里有几行代码,几行注释语句等),以及利用在方法的开始和结束处插入语句来检测性能的小工具。
还看了一部分Antlr本身的代码和它生成的编译器的代码,基本上是一头雾水。
Compiler Design in C这本书第一章提供了一个简单的编译器代码,我把它用C#改写了一下。也许以后碰到简单的应用也可以用得上。
由于该书出版较早,有些知识已经过时。比如,输入子系统,它用了一个分段读入数据的缓冲系统,这当然和当时的硬件条件有关。我看老版本的Antlr代码时,似乎也用了个类似的首尾相连的环型结构来做缓冲(因为Java无指针),但新版的代码里,干脆用个大数组,把字符一次性全部读入。
这个简单的编译器代码,parser在需要一个token时,才调用lexer读入一个token,而Antlr的代码里,在parser第一次调用lexer时,就把所有的token都提取出来了。也许这样的效率高些。
词法分析时,构建NFA,Compiler Design in C里似乎是从正则表达式直接去转的,而Antlr则是从抽象语法树去转的,也许这样更方便。
简单的词法分析,其实完全可以硬编码,手写。现在觉得,似乎NFA, DFA这些东西,主要是为了适合lex之类的自动工具,而实际工作中,复杂一些的情况,可能都是用工具来生成,而不会手工去实现NFA,DFA等。学这些东西,也许主要是为了“知其所以然”,以及学一些思想(比如DFA转换表似乎可在一些和状态有关的问题中得到应用),具体实现倒似乎不一定用得到。
以上是学习至此的一些记录。现在真正知道,学点东西,要付出相当的功夫才行。随着学习的进展,以后陆续再写点体会和感想。