语法定向定义用于打印解析字符串的语法

时间:2012-03-31 06:41:27

标签: syntax context-free-grammar parse-tree

--->考虑下面的语法:

  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.

这个解决方案好吗?我觉得它可能不准确。

这里是带注释的解析树。enter image description here

1 个答案:

答案 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,从而打印所有终端。您可能会发现这与树的顺序遍历非常类似。