编译原理是这学期的两门硬核课程之一,一直计划着把前面几章都过一遍,现在正好在学习语法分析,就顺便整理一下,就当复习了。
Introduction
首先还是来看目标,也就是我们希望做什么,最后的实验要求是要对于一个已经词法分析过的字串进行语法树的构建。语法树,我个人看来就是对数据的运算逻辑的一种比较高效地表示,语法树相当精确地揭示了一个语句的构造顺序。龙书中则是这样介绍的:“语法分析器构造出一棵语法分析树,并传递给编译器的其他部分进一步处理”。
常见的有两种,自顶向下和自底向上的方法。需要指出的是,输入总是从左到右,每次扫描一个符号。
设计文法
首先从自顶向下的文法入手,设计文法。
提取左公因子
我们在进行自顶向下的语法分析时会用到这项技术来提高效率。简单来说,对于左部相同的不同产生式来说,我们会有不同的选择,如
给出提取左公因子的算法:
对于A(
则我们可以替换:
比如刚才的式子就可以表示为:
消除左递归
如果文法中出现了类似
注意的是,递归是不可以消除的,即可以转化为别的形式的递归,但递归本身是存在的。
首先考虑
由此归纳可以得出:
原理类似,下面考虑复杂一点的情形。
类似地,可以看成上述的归纳过程,但是终结符号有了更多的选择而已。除此以外,基本相同。
消除二义性
比如对于含有
我们构造语法分析树:
是有两种选择的。其实很好理解,因为出现了两个if但是只有一个else,势必会在else和哪个if配对的问题上产生冲突。一般来说,我们会规定就近原则:即else和最近的if配对。其基本思想是在一个then和else之间出现的语句基本是已匹配的。这里的话并没有特别着重介绍,以后有空填。
自顶向下的语法分析
现在我们就可以进行自顶向下的语法分析了。回顾一下开头的话,语法分析可以看成是构造一棵语法分析树的过程。从根节点开始,进行深度优先遍历。我们一龙书上的例题举例:
对于这个文法构造分析树。这里的文法显然是消除了左递归的。书上的分析过程如下:
可以看出我们的一个难题是如何选择合适的产生式。使得可以和输入区匹配。一般来说,朴素的想法显然会想到回溯,但我们这里的想法显然避免了这样的方式。那该如何实现呢?
算法其实是有点妙的,也很难想到,但核心还是很朴素的,就是所谓的预测。这里我就从个人进行构造的情况来谈谈。我们为什么会产生回溯?是因为产生冲突。为什么产生冲突?是因为新读入的字符和我预想的对不上号。那么,如果我做了正确的预判,是不是就可以避免这样的问题呢?那就需要我们提前读入后面的输入符号。假如,我读入一个字符,可以根据当前的状态寻找合适的处理,问题自然解决了。
以上就是问题的朴素的想法。而这一想法的具体实现,则是通过维护一张“预测分析表”来实现的。具体的细节,会在下一篇整理。
2020年12月17日21点43分