要确定您是否有正确的答案,理想情况下您必须与某种标准进行比较。这对于计算机语言来说很难。
比较 AST 会很困难,因为没有这样的标准。每个构建 AST 的解析器都会构建一个 AST,其结构是由编写解析器的人设计的。
这意味着如果你构建了一个生成 AST 的解析器,并且你得到了其他人的生成 AST 的解析器,你会发现你选择的 AST 节点与另一个 AST 不匹配。现在你必须建立一个从你的 AST 到另一个的映射(你怎么知道这个映射是有效的?)。您可以尝试让您的解析器从另一个解析器生成 AST,但您会发现您生成的 AST 受您使用的解析技术的影响。
我公司生产的 Java 前端也有类似的问题(如果您想了解更多信息,请参阅 bio)。我们满足于测试答案是自洽的,然后我们对大段代码进行大量长期的体验测试。
我们的解决方案是:
- (构建一个解析器,使用我们可以获得的最强解析技术(GLR)。这意味着我们可以识别某些其他解析技术(LL、LR、...)不容易识别的结构,从而生成其他解析器可以使用的 AST 节点很难生成。请参阅下面的评论以获取这很重要的示例。即便如此,我们生成 AST 节点的方式完全避免了我们必须按照大多数其他解析技术的要求手动编码 AST 节点构造;这往往会产生一些与手工编码的 AST 不同)。
- 解析大量 Java 代码(生成 AST)以确保我们没有解析错误。[JDK 是一个很好的大小示例,很容易获得]
- 我们的工具可以采用 AST 并重新生成(漂亮打印)源代码,并带有注释,但布局可能有所不同。我们验证已解析然后漂亮打印的代码也可以解析。我们重新 prettyprint 解析的漂亮打印版本;这应该与漂亮打印的版本相同,因为我们总是产生相同的布局。这个测试很好地表明我们的 AST 设计和实现不会丢失任何源代码
- 构建符号表,解析名称的含义,并根据我们的前端验证合法的 Java 程序类型检查。这并没有告诉你任何关于 AST 本质的信息,只是它足够好(实际上,它已经足够好了!)因为类型检查任务非常复杂(去检查你当地的 Java 标准),它也很漂亮脆弱的。如果你没有把所有的东西都做好,当应用于大量代码时,类型检查很可能会失败。同样,JDK 对此进行了很好的测试。注意:没有名称和类型解析的 Java 解析器在实践中不是很有用
- 根据上述结果生成包含超链接源代码的 JavaDoc 之类的交叉引用。这意味着很容易手动检查位代码以查看名称解析(因此是 AST 构造)是否正常。
- 接受结果,将前端应用于各种程序分析和代码转换。我们发现偶尔出现的问题并修复它。
很难做到这一点。你必须接近并持续保持测试压力,特别是因为 Java 语言不断发展。(我们在 Java 8,而 Java 9 正受到威胁)。底线:构建这样的解析器并检查其健全性需要大量工作。
我们希望有一套独立的测试,但我们还没有在野外看到过。如果存在这些测试(我假设 Oracle 和 IBM 拥有它们),我希望它们真的不会直接测试解析和名称解析,而是测试一些代码编译和运行是否产生已知结果。由于我们没有构建编译器,因此如果我们拥有它们,我们将无法运行此类测试。我们将能够进行名称解析和类型一致性检查,这将很有帮助。
[我们实际上为许多语言前端这样做。你认为 Java 很难,用 C++ 试试这个]