考虑下面文法,文法定义的是类-Pascal文法的变量说明语句和简单赋值语句,程序分为声明块和语句块,语句块使用的变量必须在声明块中先声明过。 P → DS D → var V;D|ε S → V:=e;S|ε V → x|y|z 该文法定义的句子的例子: var x; var y; x:=e; y:=e; 现在使用两个属性,name和dl,每当一个新的变量声明时,就把它的name属性附给它,name属性是综合属性。 如声明的变量为x,使用的产生式为V → x,计算name属性的语义描述则表示为: V → x {V.name='x'} 将所声明的变量都放到一个变量名字清单中(用语义函数addlist实现),用属性dl综合声明块中声明的所有变量。 D1 → var V; D2{D1.dl=addlist(V.name,D2.dl)} D1 →ε {D1.dl=null} 然后这个dl属性又作为继承属性传到后面的语句部分,每个语句用到的变量都要进行审查,看它是否在变量名字清单中(用语义函数check 实现)。下面给出语义描述,看看我们如何利用继承属性dl去保持变量清单以进行类型审查。 P → DS {S.dl=D.dl} D1 → var V; D2 {D1.dl=addlist(V.name,D2.dl)} |ε {D1.dl=null} S1 → V:=e; S2 {check(V.name,S1.dl); S2.dl=S1.dl} |ε V → x {V.name='x'} |y {V.name='y'} |z {V.name='z'} 例: var x; var y; x:=e; y:=e;是该文法定义的句子,图8.15和图8.16是这个句子的带有属性信息的语法树。其中图8.15只给出了左分支的属性信息。图8.16只给出了右分支的属性信息。从右分支很清楚地看到dl属性的传递情况 |