Parsing 什么是ANTLR中的树解析器?我是被迫编写树解析器的吗?

Parsing 什么是ANTLR中的树解析器?我是被迫编写树解析器的吗?,parsing,programming-languages,antlr,grammar,Parsing,Programming Languages,Antlr,Grammar,我正在为ANTLR中的一小部分C编写一个lexer/parser,它将在Java环境中运行。我是语言语法界的新手,在许多ANTLR教程中,他们创建了一个AST抽象语法树,我是不是被迫创建了一个语法树?为什么?使用ANTLR创建AST被合并到语法中。您不必这样做,但对于更复杂的需求,它确实是一个很好的工具。这是一个可以使用的树上结构 基本上,在解析源代码时使用ANTLR,您有几个选项。您可以使用语法中的重写规则生成代码或AST。基本上是源代码的内存表示。从那里,你可以做很多事情 有很多事情要做。如

我正在为ANTLR中的一小部分C编写一个lexer/parser,它将在Java环境中运行。我是语言语法界的新手,在许多ANTLR教程中,他们创建了一个AST抽象语法树,我是不是被迫创建了一个语法树?为什么?

使用ANTLR创建AST被合并到语法中。您不必这样做,但对于更复杂的需求,它确实是一个很好的工具。这是一个可以使用的树上结构

基本上,在解析源代码时使用ANTLR,您有几个选项。您可以使用语法中的重写规则生成代码或AST。基本上是源代码的内存表示。从那里,你可以做很多事情


有很多事情要做。如果您还没有,我建议您获取。

我认为创建AST是可选的。对于后续处理(如解析程序的语义分析)非常有用

只有您可以决定是否需要创建一个。如果您的唯一目标是语法验证,那么您不需要生成语法验证。在(类似于ANTLR)中,有一个名为的实用程序,它允许生成AST。因此,我认为这在ANTLR中也是可选的。

我发现了创建ANTLR的Terence Parr写的关于jGuru的问题。我从链接的网站上复制了这个解释:

只有简单的、所谓的语法导向的翻译可以通过解析器中的操作来完成。这些类型的翻译只能吐出结构,这些结构是在解析时已经看到的信息的函数。树解析器允许您遍历一个中间表单并操纵该树,在几个翻译阶段将其逐渐变形为最终表单,可以轻松打印出来作为新的翻译

想象一下一个简单的翻译问题,您想打印出一个html页面,其标题是“There are n items”,其中n是您在输入流中找到的标识符的数量。ID必须打印在标题后面,如下所示:

<html>
<head>
<title>There are 3 items</title>
</head>
<body>
<ol>
<li>Dog</li>
<li>Cat</li>
<li>Velociraptor</li>
</body>
</html>
那么,通过语法中的简单动作,如何计算标题呢?如果不阅读整个输入,你就不能。现在我们知道我们需要一个中间形式。最好的通常是我发现的AST,因为它记录了输入结构。在本例中,它只是一个列表,但它表明了我的观点

好了,现在你知道了,除了简单的翻译,树是一件好事。给定AST,如何从中获得输出?想象一下简单的表达式树。一种方法是使树中的节点特定于类,如PlusNode、IntegerNode等。然后,您只需要求每个节点打印自己。对于输入,3+4您将有一个树:

+ | 3-4

和班级

class PlusNode extends CommonAST {
  public String toString() {
    AST left = getFirstChild();
    AST right = left.getNextSibling();
    return left + " + " + right;
  }
}

class IntNode extends CommonAST {
  public String toString() {
    return getText();
  }
}
给定表达式树,可以使用t.toString()将其翻译回文本。那么,这有什么问题?看起来效果不错,对吧?在这种情况下,它似乎工作得很好,因为它很简单,但我认为,即使对于这个简单的示例,树语法也更具可读性,并且是对PlusNode.toString()中编码内容的形式化描述

请注意,特定类(“异构AST”)方法实际上是在toString()中手工为#(+INT INT INT)编码一个完整的递归下降解析器。作为解析器生成器人员,这应该会让您感到畏缩

异构AST方法的主要缺点是不能方便地访问上下文信息。在递归下降解析器中,您的上下文很容易访问,因为它可以作为参数传入。通过查看语法,您还可以准确地知道哪个规则可以调用哪个其他规则(例如,此表达式是WHILE条件还是IF条件?)。上面的PlusNode类存在于一个分离的、孤立的世界中,它不知道谁将调用它的toString()方法。更糟糕的是,程序员无法通过读取它来判断将在哪个上下文中调用它

总之,向输入解析器中添加操作可以实现非常简单的翻译,其中:

  • 输出构造的顺序与输入顺序相同
  • 所有构造都可以从解析的信息生成,直到您需要吐出它们为止
  • 除此之外,您还需要一个中间形式——AST通常是最好的形式。使用语法描述AST的结构类似于使用语法解析输入文本。在特定领域的高级语言(如ANTLR)中的形式化描述比手工编码的解析器更好。树语法中的操作具有非常清晰的上下文,可以方便地访问从调用rlue传递的信息。使用树语法,操纵树进行多路径翻译的翻译也容易得多

    class PlusNode extends CommonAST {
      public String toString() {
        AST left = getFirstChild();
        AST right = left.getNextSibling();
        return left + " + " + right;
      }
    }
    
    class IntNode extends CommonAST {
      public String toString() {
        return getText();
      }
    }
    
    expr returns [String r]
    {
        String left=null, right=null;
    }
    
    : #("+" left=expr right=expr) {r=left + " + " + right;}
    | i:INT                       {r=i.getText();}
    ;