--->考虑下面的语法:
S->SaS|bB
B->AcB| ε
A->dAd| ε
对于上面给出的语法,编写语法定向的定义 打印正在解析的字符串,并为字符串'bddcab'构建带注释的解析树。
解决方案:
现在改写语法,我们有:
S->S1aS2
S->bB
B->AcB1
B-> ε
A->dA1d
A-> ε
( The numbers 1 and 2 following the non-terminal actually denote subscripts. And the subscripts in above grammar denote instances of the non-terminal.)
以上语法和语义规则。
Productions Semantic Rules
S->S1aS2 S.val=S1.val+a.lexval + S2.val { print S.val }
S->bB S.val=b.lexval + B.val { Print S.val}
B->AcB1 B.val=A.val+c.lexval + B1.val
B-> ε
A->dA1d A.val=d.lexval + A1.val + d.lexval
A-> ε
** The '+' operator is merely for concatenation.
这个解决方案好吗?我觉得它可能不准确。
这里是带注释的解析树。
答案 0 :(得分:1)
我认为S规则中的那些打印操作会适得其反,因为S可能会多次出现。
S可以生成SaS。但是每个S都可以生成SaS。
基本上,如果您将打印表示构建为语义属性,则只有在完全评估后才能在语法之外进行打印,确保它只发生一次。
这可以通过引入伪开始符号X来显示.S仅减少到X一次,因此打印只发生一次,从顶级val
拉出最终S
。
X -> S { print S.val } // print the top-level S's val, just once.
另一种方法是进行真正的语法指导打印,从而在解析减少发生时发生打印的副作用。例如。右手符号中类似Yacc的嵌入规则:
S -> S1 a { print a.lexeme } S2 { /* other semantic rules go here */ }
在识别终端的每个规则中,请在识别终端后立即打印终端。所以在这里,我们知道S1的减少导致所有终端被打印(通过语法上的类似规则)。然后我们识别a
并打印它,然后识别并减少S2,从而打印所有终端。您可能会发现这与树的顺序遍历非常类似。