编译原理—语法分析

来源:互联网 发布:java流媒体服务器 编辑:程序博客网 时间:2024/04/30 11:27

PS 多年前写的了,放在草稿箱里… 现在发出来了

上周完成了编译实验课程的语法分析部分,周末玩去了,今天稍稍整理一下。
首先我们是采用语法制导翻译来做的编译,书上对于语法制导翻译的解释是,将静态检查和中间代码生成结合到语法分析中进行的技术。大概就是指把词法分析、语义分析都结合到语法分析中来,一切都围绕着语法分析展开吧。
所以,完整的语法分析程序,应该是将词法分析的输出作为输入,在进行每一次归约时进行语义分析,产生中间代码。当语法分析结束时,语义分析也结束了。
由于进度等原因,这次写的语法分析还只是单纯的语法分析,没有加入任何的语义分析成分。
整个代码的核心部分就是分析表的构建。恩,该语法采用的是LR1分析法,需要构建LR1分析表。
首先需要解决的问题就是符号(包括终结符和非终结符)到数字(对应分析表纵坐标,需要从0~符号个数-1)的转换。这个简单,做了个hash,难得用了回内散列,因为数组开的大,应该是没有什么冲突。对应的,又建了个从数字到符号的映射,这个就是建了个结构体数组,最开始的时候觉得用处不是那么大,只是想方便以后根据数字查对应的字符来着,但是后来的时候往结构体里加入了该符号的所有产生式编号,给后面求LR1项目闭包、FIRST集带来了极大的方便。可谓无心插柳的神来之笔 - - 。
接下来就是对产生式的数字话,这个比较简单啦。构建了一个结构体数组,利用前面的结果,把字符形式的、复合的(即A->B | C |D 的形式)产生式转换数字的、单一的结构体项目。

{ int dotPos ; int productionOrder ; int expectedSymbol ; int exSymNum ; } ;

只在里面记录产生式的序号,然后可以在根据序号到产生式数组中线性访问,感觉这么以来整个程序就关联起来了,所谓的低耦合?虽然很好,不过老实说,到后期编码的时候太容易搞混了。。。。
接着就是求闭包了,求闭包之前当然得先得求FIRST集啦,这个用递归写的,老实说,写得很吃力 - -,感觉是不太会能用栈改写这个递归了。写这个FIRST集还遇到个问题,就是产生式的左递归问题:无穷递归。当时测试的时候就是崩溃啊,唉,当时那个难受。后来跟踪,终于恍然大悟啊。果然求FIRST集不能处理左递归的。但是好奇的是《编译控制台》这款神奇强大的软件可以正常处理,着让我很是惊异,也深感差距。不知到他是用了其他算法,还是限制了递归的层次,当发现递归数过大时及时跳出。具体原理不知,就只剩下膜拜了。接着搞CLOURE , 总的来说还算顺利,基本就是队列的思想,依次将产生式dotPos处的符号求空闭包,就是当该符号是非终结符时,将该非终结符的每个产生式(这个可以通过查符号列表里的产生式编号迅速求得)构建成一个LR1项目(包括产生式序号、展望符),加入到cloure中(放入队位,即数组尾部),然后数组头指针往后移动一位。加入的时候当然要去重啦。去重效率就相当低了,实在是烦写hash了,就只能枚举了 - - 。
求得CLOURE,然后就可以建立起LR1项目集族了。我也是用的一个结构体数组来做 - -。首先求拓展文法的CLOURE,然后就是和求CLOURE一样的方法,求得CLOURE里每个LR1项目的后继项目,然后将该后继项目构建成LR1项目,求得CLOURE,加入到队列(数组,当然又得去重),最后项目集族就ok了。

0 0