it-swarm.asia

抽象语法树和具体语法树有什么区别?

我一直在阅读有关解释器/编译器如何工作的一些内容,而我感到困惑的一个领域是AST和CST之间的区别。我的理解是解析器生成一个CST,将它交给语义分析器,将其转换为AST。但是,我的理解是语义分析器只是确保遵循规则。我真的不明白为什么它会实际做出任何改变,使其变得抽象而不是具体。

有没有关于语义分析器的东西,或者AST和CST之间的区别有点人为?

70
Jason Baker

具体语法树以完全解析的形式表示源文本。通常,它符合定义源语言的无上下文语法。

但是,具体的语法和树有很多东西是使源文本明确可解析所必需的,但却没有实际意义。例如,要实现运算符优先级,您的CFG通常具有多个级别的表达式组件(术语,因子等),运算符将它们连接到不同的级别(您添加术语以获取表达式,术语由可选乘以的因子组成)等)。但是,要实际解释或编译语言,您不需要这样做;您只需要具有运算符和操作数的Expression节点。抽象语法树是将具体语法树简化为实际需要表示程序含义的结果。该树具有更简单的定义,因此在后续执行阶段更容易处理。

您通常不需要实际构建具体的语法树。您的YACC(或Antlr,或Menhir,或任何......)语法中的动作例程可以直接构建抽象语法树,因此具体语法树仅作为表示源文本的解析结构的概念实体存在。

54
Michael Ekstrand

A 具体语法树 匹配语法规则所说的语法。 抽象语法树 的目的是“简单”表示“语法树”中必不可少的内容。

AST恕我直言中的实际值是 较小 而不是CST,因此处理时间较短。 (你可能会说,谁在乎?但是我使用的工具可以同时存在数千万个节点!)。

大多数支持构建语法树的解析器生成器坚持要求你个人指定它们是如何构建的,假设你的树节点比CST“更简单”(并且,它们通常是正确的,因为程序员很漂亮懒)。可以说,这意味着你必须编写更少的树访问者函数,这也是有价值的,因为它最大限度地减少了工程能量。当你有3500条规则(例如,对于COBOL)时,这很重要。而这种“简单”的过程导致了“小”的良好属性。

但是有这样的AST会产生一个不存在的问题:它与语法不匹配,现在你必须在心理上跟踪它们。当3500规则语法有1500个AST节点时,这很重要。如果语法发展(他们总是这样做!),现在你有两套巨大的东西要保持同步。

另一个解决方案是让解析器只为您构建CST节点并使用它们。构建语法时这是一个巨大的优势:没有必要发明1500个特殊的AST节点来模拟3500语法规则。试想一下树与语法同构。从语法工程师的角度来看,这是完全无脑的,这使他能够专注于正确理解语法,并将其扼杀在心中。可以说,您必须编写更多节点访问者规则,但这可以进行管理。稍后会详细介绍。

我们使用 DMS Software Reengineering Toolkit做什么 是根据(GLR)解析过程的结果自动构建CST。然后DMS出于空间效率的原因自动构建“压缩”CST,通过消除非携带终端(关键字,标点符号),语义无用的一元制作,以及形成列表的语法规则对列表:

    L = e ;
    L = L e ;
    L2 = e2 ;
    L2 = L2  ','  e2 ;

以及这些形式的各种变化。您可以根据语法规则和虚拟CST来考虑;该工具在压缩表示上运行。在您的大脑上轻松,在运行时更快/更小。

值得注意的是,以这种方式构建的压缩CST看起来很多AST,您可能已经手工设计了(参见示例结尾处的链接)。特别是,压缩的CST不携带任何只是具体语法的节点。有一些尴尬的小问题:例如,当表达式子文件中经典地找到的'('和')'的具体节点不在树中时,“括号节点” 确实 出现在压缩的CST中必须处理。真AST不会有这个。这似乎是一个相当小的代价,为了方便而不必指定AST构造,永远。并且树的文档始终可用且正确:语法文档。

我们如何避免“额外的访客”?我们并不完全,但是DMS提供了一个AST库来遍历AST并且透明地处理CST和AST之间的差异。 DMS还提供了一个“属性语法”评估器(AGE),它是一种传递在树上上下计算节点的值的方法; AGE处理所有树表示问题,因此工具工程师只担心直接在语法规则本身上有效地编写计算。最后,DMS还提供了“表面语法”模式,它允许语法中的代码片段用于查找特定类型的子树,而无需了解所涉及的大多数节点类型。

其中一个答案观察到,如果要构建可以重新生成源的工具,则AST必须与CST匹配。这不太对,但如果你有CST节点,重新生成源要容易得多。 DMS自动生成大部分的prettyprinter 因为它可以同时访问: - }

底线:ASTs适用于小型,包括物理和概念。来自CST的自动AST构造提供了两者,并且可以避免跟踪两个不同集合的问题。

编辑2015年3月: 以这种方式建立的CST与“AST”的示例链接

28
Ira Baxter

此博客文章 可能会有所帮助。

在我看来,AST“抛弃了”许多不会对语义做出贡献的中间语法/结构信息。例如,你不关心3是一个原子是一个术语是一个因素是......当你实现指数表达式时,你只关心它是3

20
Jonathan Feinberg

这是基于 表达评估器 Terrence Parr的语法。

这个例子的语法:

grammar Expr002;

options 
{
    output=AST;
    ASTLabelType=CommonTree; // type of $stat.tree ref etc...
}

prog    :   ( stat )+ ;

stat    :   expr NEWLINE        -> expr
        |   ID '=' expr NEWLINE -> ^('=' ID expr)
        |   NEWLINE             ->
        ;

expr    :   multExpr (( '+'^ | '-'^ ) multExpr)*
        ; 

multExpr
        :   atom ('*'^ atom)*
        ; 

atom    :   INT 
        |   ID
        |   '('! expr ')'!
        ;

ID      : ('a'..'z' | 'A'..'Z' )+ ;
INT     : '0'..'9'+ ;
NEWLINE : '\r'? '\n' ;
WS      : ( ' ' | '\t' )+ { skip(); } ;

输入

x=1
y=2
3*(x+y)

解析树

解析树是输入的具体表示。解析树保留输入的所有信息。空框表示空格,即行尾。

Parse Tree

AST

AST是输入的抽象表示。请注意,AST中不存在parens,因为关联可以从树结构中派生。

AST

编辑

有关更详细的说明,请参阅 编译器和编译器生成器 pg。 23

17
Guy Coder

具体语法树 遵循语言语法规则。在语法中,“表达式列表”通常用两个规则定义

  • expression_list可以是:expression
  • expression_list可以是:expression,expression_list

按照字面意思,这两个规则为程序中出现的任何表达式列表提供梳形。

抽象语法树 采用便于进一步操作的形式。它以对理解程序含义的人有意义的方式表示事物,而不仅仅是它们的编写方式。上面的表达式列表(可以是函数的参数列表)可以方便地表示为表达式的向量,因为静态分析最好使表达式的总数明确可用并且能够通过其访问每个表达式指数。

9
Pascal Cuoq

简单地说,AST只包含代码的语义,Parse tree/CST还包含有关代码编写方式的信息。

1
mym

这是一个没有区别的差异。

AST通常被解释为通过丢弃词法内容来近似编程语言表达的语义的方法。例如,在上下文无关语法中,您可以编写以下EBNF规则

term: atom (('*' | '/') term )*

而在AST的情况下你只使用 mul_rule 和 div_rule 它表达了正确的算术运算。

首先不能在语法中引入这些规则吗?当然。您可以通过将上述紧凑和abstract规则分解为用于模仿上述AST节点的更多具体规则来重写上述规则:

term: mul_rule | div_rule
mul_rule: atom ('*' term)*
div_rule: atom ('/' term)*

现在,当你考虑自上而下的解析然后第二个 term 引入了FIRST/FIRST之间的冲突 mul_rule 和 div_rule LL(1)解析器无法处理的东西。第一个规则形式是第二个规则形式的第二个规则形式,它有效地消除了结构。你必须在这里使用LL(1)支付一些奖金。

所以AST是一种特殊的补充,用于修复语法和解析器的缺陷。 CST - > AST转换是一个重构动作。当语法树中存储额外的逗号或冒号时,没有人会烦恼。相反,一些作者将它们改装成AST,因为他们喜欢使用AST进行重构而不是同时维护各种树或编写额外的推理引擎。程序员很懒惰是有充分理由的。实际上,他们通过ASTs中的词法分析存储了甚至行和列信息,以便进行错误报告。非常抽象。

1
Kay Schluehr

具体语法树包含所有信息,如多余的括号,空格和注释,抽象语法树从这些信息中抽象出来。

注意: 很有趣,当你实现一个重构引擎时,AST将再次包含所有具体信息,但你会继续将它称为AST,因为它已成为该领域的标准术语(因此人们可以说它早已失去其原始含义)。

1
akuhn