【问题标题】:How Do I Build an Abstract Syntax Tree with JJTree?如何使用 JJTree 构建抽象语法树?
【发布时间】:2018-11-16 20:58:20
【问题描述】:

在构建 AST 并将子级添加到树时,有什么区别:

void NonTerminal #Nonterminal: { Token t;}
{
    t = <MULTIPLY> OtherNonTerminal() {jjtThis.value = t.image;} #Multiply
}

和:

void NonTerminal : { Token t;}
{
    t = <MULTIPLY> OtherNonTerminal() {jjtThis.value = t.image;} #Multiply(2)
}

注意:

<MULTIPLY : "*">

是否有任何重大差异?两者的工作方式是否相同?

还有另一种为这个生产规则构建树的方法:

void NonTerminal() : { Token t; }
{
    t = <MULTIPLY> OtherNonTerminal() { jjtThis.value = t.image; } #Mult(2)
|   t = <DIVIDE> OtherNonTerminal() { jjtThis.value = t.image; } #Div(2)
|   {}
}

像这样:

void NonTerminal() #Nonterminal(2) : { Token t; }
{
    (t = <MULTIPLY> OtherNonTerminal() | t = <DIVIDE> OtherNonTerminal() | {}) {jjtThis.value = t.image;}
}

【问题讨论】:

  • “NODE_DEFAULT_VOID”选项是否设置为true?
  • 是的,它设置为真。 @TheodoreNorvell

标签: java parsing compiler-construction abstract-syntax-tree javacc


【解决方案1】:

第一种情况

void NonTerminal #Nonterminal: { Token t;}
{
    t = <MULTIPLY>
    OtherNonTerminal() {jjtThis.value = t.image;}
    #Multiply
}

Multiply 节点将在其节点范围内将所有推入堆栈的节点作为子节点,不包括在范围结束之前弹出的任何节点。在这种情况下,这意味着在解析OtherNonTerminal 期间所有节点都被推送而不是弹出。

在第二个例子中

void NonTerminal #void : { Token t;}
{
    t = <MULTIPLY>
    OtherNonTerminal() {jjtThis.value = t.image;} 
    #Multiply(2)
}

Multiply 节点将从堆栈中获取两个顶部节点作为其子节点。

所以可能有区别。

另一个区别是第二个示例没有指定与Nonterminal关联的节点。

在第一种情况下,这棵树将被推送

        Nonterminal
             |
          Multiply
              |
All nodes pushed (but not popped) during the parsing of OtherNonterminal

在第二种情况下,OtherNonterminal 的解析会做它的事情(弹出和推送节点),然后会弹出两个节点并推送这棵树

     Multiply
      |     |
  A child  Another child

第二个问题。区别

void NonTerminal() #void : { Token t; }
{
    t = <MULTIPLY>
    OtherNonTerminal()
    { jjtThis.value = t.image; }
    #Mult(2)
|
    t = <DIVIDE>
    OtherNonTerminal()
    { jjtThis.value = t.image; }
    #Div(2)
|
    {}
}

和

void NonTerminal() #Nonterminal(2) : {
    Token t; }
{
    ( t = <MULTIPLY> OtherNonTerminal()
    | t = <DIVIDE> OtherNonTerminal()
    | {}
    )
    {jjtThis.value = t.image;}
}

是空序列匹配时第一个不建节点。

在下一个令牌不是* 或/ 的情况下考虑第二种方式。你会得到

      Nonterminal
      /        \
  Some node    Some other node
  don't want   you don't want

我真的很惊讶第二个编译器竟然通过了 Java 编译器,因为对 t 的引用可能是一个未初始化的变量。

【讨论】:

  • 是#Multiply(2) 表示乘法运算需要两个值(节点),例如x * y 并且是#Multiply 指定可以将任意数量的节点推送到树上?
  • 是的,'#Multiply' 表示子节点的数量取决于自节点范围开始以来推送但未弹出的节点数量。
  • 我添加到答案中。为了将来参考,一旦问题得到解答,实质性地改变或添加问题可能不是一个好主意。最好提出一个新问题。
  • "两者的工作方式相同,但树的构建方式不同?"对于相同的输入,您会得到不同的树;所以我不会说它们“工作方式相同”。
  • 我并不是说您“必须”使用一种方法或另一种方法。我只是说您建议的各种方法会产生不同的结果。我的建议是找出你想要的每个输入的树,并相应地设计你的语法和 JJTree 注释。确定节点对于为左关联二元运算符构建适当的树非常有用。有关处理二元运算符的一些建议,请参阅我在 stackoverflow.com/questions/26846777/… 的回答。
【解决方案2】:

这个问题的答案是肯定的。

JVACC 或 JJTREE 语法在不同的步骤中做编译过程。

  1. 词法分析,其中收集单个字符并尝试使用 TOKEN、SPECIAL_TOKEN、MORE 和 SKIP 部分中提供的正则表达式构建标记。 每次成功的词法分析后,都会生成一个标记。
  2. 语法分析,其中这些标记将排列在一棵称为语法树的树中,其中包含终端节点和非终端节点,并提供production rules。 收集词法分析生成的每个 Token,语法分析尝试从中验证语法。

    非终端节点:表示其他生产规则。

    TERMINAL节点:表示令牌或数据节点。

这就是区别,

  1. 语法验证成功后,我们需要一个有用的表单来使用它。 更有用的表示是树表示,我们已经生成了作为语法分析的一部分的语法树,可以对其进行修改以从中获取有用的树,这就是 JJTree 出现重命名和创建有用的树结构使用的地方生产规则中的#NODE_NAME 语法。

编辑评论如下

Multiply(2) 表示只有两个孩子,如果你的操作是 A*B,这是有意义的, 如果您正在执行 A*B*C 并使用#Multiply(2),那么树将像

          Multiply
        /          \
  Multiply           C
    /  \
  A     B

如果您正在执行 A*B*C 并使用#Multiply,那么树将像

   Multiply    Multiply      Multiply
      |            |             | 
      A            B             C

基本上#Multiply 和#Multiply(2) 之间的区别是Multiply(2) 将等待两个令牌生成节点,如果发现只有一个抛出异常并且#Multiply 将在生产规则时生成节点匹配成功。

【讨论】:

  • 那么您的意思是 AST 是以不同的方式构建的?但是他们会以同样的方式工作吗?乘法运算需要两个孩子,那么#Multipy 还能工作吗?如果我不添加两个子节点会发生什么,例如#乘法(2)? @sarathkumar
  • #Multiply(2) 表示只有两个孩子,如果您的操作是 AB,如果您正在执行 ABC 并使用 #Multiply(2 ) 如果您正在执行 AB*C,那么树将类似于 Multiply Multiply C A B 并且使用#Multiply 然后树将类似于 Multiply Multiply Multiply A B C
  • 如上相应地编辑了答案谢谢。 @webchatowner
  • 所以基本上,两种方法都是正确的,AST 只是构建方式不同? @sarathkumar
  • 非常感谢! @sarathkumar
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-22
  • 1970-01-01
  • 2011-09-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多