编译原理:代替LR的MP:2.遇到的问题

用指针加速

MP是multi-pass,多遍分析法,它是从“先乘除后加减”中得来的灵感。在实践中,发现C语言优先级有15级,如果将源代码处理15遍,每一遍都从头开始找,势必很慢。所以,有了用指针加速的想法。

例如,给所有乘除号的指针排列起来,所有加减号的指针排列在它下面。这是在词法分析那一遍完成的。然后,处理乘除法的那一遍,可以直接找到乘除号,处理加减法时,能够直接找到加减号。不用再从头开始找了,有提速效果。

树的结构

要想实现“用指针加速”的想法,需要用指针指向树上的节点,并且还能在树上移动。用C++的vector实现树状结构恐怕不行,它需要一个指针指向父节点,再来一个下标说明是第几个子节点。

希望只用一个指针描述节点,这么一来,要用C语言实现树状结构了。树上的每个节点,包括一个字符串,和4个指针,分别指向父节点(上)、兄弟节点(左右)、长子节点(下)。其中“长子”是个新的概念,是子节点中最左边的一个。

重叠的产生式

在实践中遇到了“重叠的”产生式,即两个产生式,有公共的部分,又不完全一样。如:

A->*E
B->E*E
或
E->id
E->id=E

星号E,表示C语言的指针操作,可星号同时也是乘号,并且,前者的优先级更高。如果先把所有*E归约为A,再遇到乘法时,看到的就是EA,这就错了。

第二个例子,先把id归约为E,然后发现id=id变成了E=E,这导致不能识别id=E。

用FIRST集和LAST集解决上述问题。比较*EE*E,左侧多出一个E,应该求LAST(E),当判断*E时,看到星号左边的符号属于LAST(E),则不做归约。LAST集的求法,在《编译原理》书中没有说,但是它和FIRST集差不多,对称的。

比较id和id=E,右侧多出=E,求FIRST(=E),结果是等于号。在尝试把id归约为E时,看一看右边是不是等于号,如果是,就不归约。

修正

解决上述产生式重叠问题的另一个方法,是“修正”。对于产生式A->*E,修改为Ax->*E,这么一来,在之后的某一遍中,遇到EAx就知道应该“修正”为E*E

Ax是一个新的文法符号,并且它的子节点正是星号和E。修正时,检查一下子节点,更安全。

突破

在这里插入图片描述
图中的语言是一串a,很简单,但是,它的文法产生式却如此复杂。有时,我觉得chomsky的四型文法是个陷阱,至少也是个坑,许多人都掉进去了。

在MP分析法中,使用函数来处理树状结构,而基于纯文法的语法分析,只使用“替换”。不管是推导还是归约,都是替换。用左边的替换右边的,或者用右边的替换左边的。用函数则更灵活。

图中的语言,用函数来识别,可以是这样:

/a+/ =~ s
n=strlen(s)
n=2^i, i=1,2,3...

如此说来,MP分析法超越了上下文无关文法,更强。

前进的动力

下图中,成功实现了一个源代码的分析,这给了我动力。在这里插入图片描述
一开始,是一个只有根节点,没有任何子节点的树,它的内容是源代码。

经过词法分析,出现了一棵略微复杂一点的树。

之后的一步步,形成了完整的语法树。

注意,这个例子中,总是针对根节点进行分析的。在添加了括号之后,用数数的方法进行括号的配对,这需要对某个子节点进行分析。引入递归的函数,可以完成括号的分析。
a(bcd(efg)h)ijk
括号配对的结果是
a(.)ijk
bcd(efg)h
把指针p指向点号,第二行做它的子节点。调用分析函数f(p)。由于在子节点中还有括号,所以会出现函数f的递归调用。

总结

MP分析法可以代替LR分析法,并且还能有所超越。这是一个有希望的研究方向。发明LR分析法的Knuth先生还健在,他看到MP分析法之后,会怎么想呢?

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值