【问题标题】:What's the use of abstract syntax trees?抽象语法树有什么用?
【发布时间】:2010-10-05 00:38:33
【问题描述】:

我正在自学为编程语言编写解释器,并且我已经阅读了抽象语法树。我知道它们是什么,但我看不到它们的用途。

为什么 AST 有用?

【问题讨论】:

  • 如果没有 AST,您打算如何对语言的语法进行建模?即在编写解析器/编译器/解释器/等时。

标签: terminology abstract-syntax-tree


【解决方案1】:

它们代表代码的逻辑/语法,这自然是一棵树而不是行列表,而不会陷入具体的语法问题,例如place your asterisk

然后可以从后端的 POV 以更一致和方便的方式操作逻辑,这可能(并且对于除 Lisps 之外的所有内容;)与我们编写具体语法的方式非常不同。

【讨论】:

  • 那么我为什么要使用 AST 而不是只制作诸如“IDENTIFIER blah ASTERISK NUMBER 4”之类的东西流并让 FSM 或其他东西下降并一次吃一个令牌?
  • @Rac:您描述的是原始文件和生成 AST 之间的一个步骤。即:原始 -> 令牌 -> AST。 BinaryOp(Multiply, Identifier("blah"), Integer(4)) 对于后端来说更方便。
  • @RacecaR 用于解析的 FSM 会吃掉流以产生 AST;您的代码生成和优化例程将使用 AST
  • 有具体的名称吗?我还可以想到解释器继续看到 if 语句的地方,以及字节码或任何你说的东西,如果某事是真的,解释器应该转发 8 个令牌,如果不是,转发 0 个令牌(或其他东西) . AST 如何处理这样的事情?也许给解释器应该走的下一条路径(下一个节点)?
  • Lexical analysis。 AST 将有一个节点用于具有两个子节点的条件:真和假。 AST 与字节码/asm 非常不同(它们是相同的东西,只是针对不同的机器),你有“跳转 X 指令”(不是令牌)。
【解决方案2】:

使用 AST 的主要好处是可以将解析和验证逻辑与实现部分分开。作为 AST 实现的解释器确实更容易理解和维护。如果您在解析一些奇怪的语法时遇到问题,请查看 AST 解析器,如果一段代码没有产生预期的结果,则请查看解释 AST 的代码。

另一个很大的优势是当你的语法需要“前瞻”时,例如如果您的语法允许在定义子例程之前使用它,那么在使用 AST 时验证子例程的存在是微不足道的——使用“动态”解析器要困难得多。

【讨论】:

  • 谢谢。我一直在研究使用 Java 构建解析器,它声称构建 AST 比简单语言的价值要麻烦得多。你是这个页面上唯一的评论,它甚至承认可以在不构建 AST 的情况下做一些有用的事情。
【解决方案3】:

您需要“语法树”来表示大多数编程语言的结构,以便对包含编程语言文本的文档进行分析或转换。 (你可以通过我的简历看到一些精彩的例子)。

这棵树是抽象的 (AST) 还是具体的 (CST) 取决于品味、便利性和工程汗水。术语 CST 专门用于描述使用语法解构源代码时的解析派生树;它通常包含许多具体语法的树元素,例如语句终止符分号。 AST 用于表示“比 CST 更简单的东西”,例如,省略分号树节点,因为它们不会对程序分析产生太大影响,因此编写处理 AST 的分析器比在科技委。理解这一点的更好方法是认识到 AST 通常与 CST 同构,也就是说,您应该能够从中重新生成 CST。如果您想转换源文本并重新生成它,那么 CST 通常是更好的选择,因为它从原始程序中丢失的信息更少(我的奇特示例使用了这种方法)。

我认为您会发现 abstract vs. concrete syntax trees 上的 SO 讨论非常有帮助。

【讨论】:

  • 这是该主题的最佳答案。这需要更多的支持。
【解决方案4】:

一般来说,您会将代码解析为某种形式的 AST,它可能或多或少是一个正式的模型。所以我认为 Kirk Woll 上面的评论所要表达的意思是,当你解析语言时,你经常使用解析器来创建某种类型的数据模型,即你正在阅读的原始内容,通常以树的方式组织.因此,根据该定义,除非您正在做一个非常简单的翻译,否则很难避免 AST。

我经常使用 ANTLR 来解析复杂的语言,在这种情况下,AST 的含义稍微更具体一些。 ANTLR 有一种方便的方法,可以使用非常简单的操作在解析器语法中生成 AST。然后,您为此 AST 编写一个更简单的解析器,您可以像您正在处理的语言的更简单版本一样对其进行操作。构建两个解析器的额外工作是否是净收益取决于语言复杂性以及解析后您打算用它做什么。

您可能想看的一本好书是 ANTLR 作者 Terrence Parr 的“语言实现模式”。他非常彻底地解决了这个话题。也就是说,在我开始使用 AST 之前,我并没有真正了解它们,因此(像往常一样)是理解它们的最佳方式。

【讨论】:

    【解决方案5】:

    这个问题迟到了,但我想我会补充一些东西。您实际上不必构建 AST。解析源代码时可以直接发出指令。在这种情况下,解析语法中隐含了 AST。对于简单的语言,尤其是动态类型的语言,这是一个非常好的策略。对于更复杂的语言或需要进一步分析源代码的地方,AST 可能非常有用。例如,如果你的语言是静态类型的,即你的变量是用固定类型声明的,那么 AST 可以用来检查你没有给变量分配错误的类型。例如,将字符串分配给声明为保存整数的变量将是错误的,这可以使用 AST 更方便地捕获。

    此外,正如其他人所提到的,AST 提供了语法分析和代码生成之间的清晰分离,并使代码更加模块化。

    【讨论】:

      猜你喜欢
      • 2010-12-25
      • 2011-08-23
      • 2011-12-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多