9.2 分析树和抽象语法树

语法分析不但要判断给定的句子是否符合语法结构,而且还要分析出该句子符合哪些结构,也就是说,要分析出这个句子是怎么从起始符号开始产生出来的,并根据产生过程生成语法树。如,对于 “我吃饭” 这句话,只有我们知道了 主语、谓语和宾语 分别对应的是那个词,我们才能真正理解这句话的含义。images/syntax_1.png图9.1 语法树示意图

以上一节表达式语法为例,给定一个句子 12 + 53 ,经过观察,发现此句子可以按以下方式被推导出来:

  1. Expr ==> Expr + Expr ==> number + Expr ==> number + number ==> 12 + 53

以上推导过程可以用分析树来表示:images/syntax_2.png图9.2 分析树示意图a

再看一个稍微长的句子: 12 + ( 53 - 7 ) ,其分析树如下:images/syntax_3.png图9.3 分析树示意图b

可以去掉此分析树中一些多余的节点,并进一步浓缩,得到抽象语法树:images/syntax_4.png图9.4 抽象语法树示意图a

对于这种树状结构,可以采用递归的方式加以分析,从而生成目标代码。

再看一个句子: 12 + 53 7 ,这时候问题来了,我们发现它可以由两种不同的方式推导出来:images/syntax_5.png*图9.5 抽象语法树示意图b

这就是语法的歧义性,所谓 歧义(ambiguity),就是指对于一个符合语法结构的句子,它可以由两种不同的方式被推导出来。如果一个语法中,任何一个句子的推导方式都是唯一的,那这个语法就被称为是 没有歧义 的。显然,程序语言必须是没有歧义的,对于上面的表达式,我们肯定希望它只能按后一种方式被推导。

消除歧义的方法之一是改写语法,将有歧义的产生式改写成无歧义的,这种改写非常困难,而且改写后的产生式往往和原产生式相差很大,可读性非常差。另一种方法就是引入 优先级 ,不需要改写语法,当推导过程中出现歧义的时候(也就是出现两种不同的推导方式的时候),利用符号的优先级来选择需要的推导方式,这种方法将在第 12 章中介绍。