我正在为将在Java环境中运行的ANTLR中的一小部分C编写词法分析器/解析器。我是语言语法世界的新手,在许多ANTLR教程中,他们创建了一个AST - 抽象语法树,我被迫创建一个,为什么?
答案 0 :(得分:7)
使用ANTLR创建AST已纳入语法。您不必这样做,但它是一个非常好的工具,可以满足更复杂的要求。这是您可以使用的tutorial树构造。
基本上,使用ANTLR解析源时,您有几个选项。您可以使用语法中的重写规则生成代码或AST。 AST基本上是源的内存表示。从那里,你可以做很多事情。
ANTLR有很多东西。如果您还没有,我建议您the book。
答案 1 :(得分:3)
我找到了由创建ANTLR的Terence Parr撰写的关于jGuru的问题的this answer。我从链接here的网站上复制了此解释:
只有简单的,所谓的语法指导翻译才能通过解析器中的操作完成。这些类型的翻译只能吐出构造,这些构造是在解析中的那一点上已经看到的信息的函数。树解析器允许您走一个中间形式并操纵该树,逐渐将其在几个翻译阶段变形为最终形式,可以轻松打印出来作为新翻译。
想象一个简单的翻译问题,你想要打印出一个标题为“有n个项目”的html页面,其中n是你在输入流中找到的标识符数。必须在标题之后打印ID,如下所示:
<html>
<head>
<title>There are 3 items</title>
</head>
<body>
<ol>
<li>Dog</li>
<li>Cat</li>
<li>Velociraptor</li>
</body>
</html>
来自输入
Dog
Cat
Velociraptor
因此,通过语法中的简单操作,您如何计算标题?你不能没有阅读整个输入。好的,现在我们知道我们需要一个中间形式。最好的通常是我发现的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()中编码的精确描述的形式化描述。
expr returns [String r]
{
String left=null, right=null;
}
: #("+" left=expr right=expr) {r=left + " + " + right;}
| i:INT {r=i.getText();}
;
请注意,特定类(“异构AST”)方法实际上是通过hand in toString()为#(+ INT INT)编码完整的递归下降解析器。作为解析器生成器的人,这会让你感到畏缩。 ;)
异构AST方法的主要缺点是它无法方便地访问上下文信息。在递归下降解析器中,您可以轻松访问上下文,因为它可以作为参数传入。您还可以通过查看语法来准确地知道哪个规则可以调用哪个其他规则(例如,此表达式是WHILE条件还是IF条件?)。上面的PlusNode类存在于一个独立的,孤立的世界中,它不知道谁会调用它的toString()方法。更糟糕的是,程序员无法通过阅读来调用它将在哪个上下文中调用。
总之,向输入解析器添加操作适用于非常简单的翻译,其中包括:
除此之外,你需要一个中间形式 - 通常AST是最好的形式。使用语法来描述AST的结构类似于使用语法来解析输入文本。特定于域的高级语言(如ANTLR)中的形式化描述优于手动编码解析器。树语法中的动作具有非常清晰的上下文,可以方便地访问从调用线索传递的信息。使用树语法操纵树进行多遍转换的翻译也更容易。
答案 2 :(得分:1)
我认为 AST 的创建是可选的。 Abstract Syntax Tree对于后续处理非常有用,例如解析程序的语义分析。
只有您可以决定是否需要创建一个。如果您的唯一目标是语法验证,那么您不需要生成一个。在javacc(类似于ANTLR)中,有一个名为JJTree的实用程序,它允许生成AST。所以我想这在ANTLR中也是可选的。