解析树和抽象语法树 (AST) 有啥区别?

Posted

技术标签:

【中文标题】解析树和抽象语法树 (AST) 有啥区别?【英文标题】:What's the difference between parse trees and abstract syntax trees (ASTs)?解析树和抽象语法树 (AST) 有什么区别? 【发布时间】:2011-06-28 22:20:45 【问题描述】:

它们是由编译过程的不同阶段生成的吗?还是它们只是同一事物的不同名称?

【问题讨论】:

解析树是您的语法及其工件的结果(您可以为同一种语言编写无穷多的语法),AST 将解析树简化为最接近该语言。同一种语言的几种语法会给出不同的解析树,但应该产生相同的 AST。 (也可以将不同的脚本(同一个语法的不同解析树)缩减为同一个AST) 【参考方案1】:

这是基于 Terrence Parr 的 Expression Evaluator 语法。

本例的语法:

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)

解析树

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

AST

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

更详尽的解释见Compilers and Compiler Generators pg。 23 或@ 987654323@ pg。 21 在Syntax and Semantics of Programming Languages

【讨论】:

如何从解析树中导出 AST?将解析树简化为 AST 的方法是什么? 没有特定的算法可以从解析树中导出 AST。 AST 中的内容更多是个人喜好,但必须包含足够的信息才能完成任务。我通过在语法中使用 ANTLR ! operator 从 AST 中排除了括号,因为它们不是必需的,但默认情况下 ANTLR 会包含它们。我认为解析树为您提供了无论您是否需要它的一切,而 AST 为您提供了最低限度。请记住,您会经常穿越树木,因此大小很重要。 你的意思是像 CST(具体语法树)和 AST(抽象语法树)? 嵌入在解析器或解析器生成器的语法文件中的语义动作/规则是语义分析和创建 AST 的常用方式,而解析树很少被用户代码构建或使用,除了也许是为了验证解析器的正确性。 感兴趣的:Abstract semantic graph【参考方案2】:

这是在编译器构造的上下文中对解析树(具体语法树,CST)和抽象语法树(AST)的解释。它们是相似的数据结构,但构造不同并用于不同的任务。

解析树

解析树通常在词法分析之后作为下一步生成(它将源代码转换为一系列可以被视为有意义的单元的标记,而不仅仅是一个字符序列)。

它们是树状数据结构,显示了输入终端字符串(源代码标记)是如何由相关语言的语法生成的。解析树的根是语法中最通用的符号——开始符号(例如,语句),内部节点表示开始符号扩展成的非终结符(可以包括开始符号本身),例如表达式语句术语函数调用。叶子是语法的终端,在语言/输入字符串中作为标识符、关键字和常量出现的实际符号,例如for9if

在解析的同时,编译器还会执行各种检查以确保语法的正确性——并且语法错误报告可以嵌入到解析器代码中。

它们可用于通过语法导向定义或翻译方案进行语法导向翻译,用于简单的任务,例如将中缀表达式转换为后缀表达式。

这是表达式 9 - 5 + 2 的解析树的图形表示(注意树中终端的位置以及表达式字符串中的实际符号):

抽象语法树

AST 表示某些代码的语法结构。诸如表达式、流控制语句等编程结构的树 - 分组为运算符(内部节点)和操作数(叶子)。例如,表达式i + 9 的语法树将运算符+ 作为根,变量i 作为运算符的左孩子,将数字9 作为右孩子。

这里的区别在于非终结符和终结符不起作用,因为 AST 不处理语法和字符串生成,而是编程构造,因此它们表示这些构造之间的关系,而不是它们的生成方式通过语法。

请注意,运算符本身是给定语言的编程结构,不必是实际的计算运算符(如+ 是):for 循环也将以这种方式处理。例如,您可以有一个语法树,如for [ expr, expr, expr, stmnt ](表示为内联),其中for 是一个运算符,方括号内的元素是它的子项(表示C 的for语法) - 也由运算符等组成。

AST 通常也由编译器在语法分析(解析)阶段生成,稍后用于语义分析、中间表示、代码生成等。

这是 AST 的图形表示:

【讨论】:

我希望您的回答被接受。它更详细,解释也更好。 @Salil 谢谢!:) 我也在我的博客上写过这些东西:flowing.systems/tag/mcd 有第一次定义解析树的作者吗?【参考方案3】:

据我了解,AST 更侧重于源代码组件之间的抽象关系,而解析树侧重于语言使用的语法的实际实现,包括挑剔的细节。它们绝对不一样,因为“解析树”的另一个术语是“具体语法树”。

我发现这个page 试图解决这个确切的问题。

【讨论】:

【参考方案4】:

AST 从概念上描述源代码,它不需要包含解析某些源代码所需的所有语法元素(大括号、关键字、括号等)。

解析树更紧密地表示源代码。

在 AST 中,IF 语句的节点可能只包含三个子节点:

条件 如果情况 其他情况

对于类 C 语言,解析树需要包含“if”关键字、括号、花括号的节点。

【讨论】:

【参考方案5】:

Martin Fowler 的DSL book 很好地解释了这一点。 AST 仅包含将用于进一步处理的所有“有用”元素,而解析树包含您解析的原始文档中的所有工件(空格、括号等)

【讨论】:

【参考方案6】:

做帕斯卡作业 年龄:= 42;

语法树看起来就像源代码一样。下面我在节点周围加上括号。 [年龄][:=][42][;]

抽象树看起来像这样 [=][年龄][42]

赋值变成一个有2个元素的节点,Age和42。想法是你可以执行赋值。

还要注意 pascal 语法消失了。因此,可能有不止一种语言生成相同的 AST。这对于跨语言脚本引擎很有用。

【讨论】:

【参考方案7】:

***说

解析树具体反映了输入语言的语法,使其不同于计算机编程中使用的抽象语法树。

知乎上的回答说

解析树是用于匹配某些输入文本的规则(和标记)的记录,而语法树记录输入的结构并且对产生它的语法不敏感。

结合以上两个定义,

Abstract Syntax Tree 从逻辑上描述解析树。它不需要包含解析某些源代码所需的所有语法结构(空格、大括号、关键字、括号等)。这就是为什么Parse Tree 也称为Concrete Syntax Tree 而AST 称为Syntax Tree 的原因。因此,语法分析器的输出实际上是语法树。

【讨论】:

【参考方案8】:

在解析树内部节点是非终端的,叶子是终端的。 在语法树中,内部节点是操作符,叶子是操作数。

【讨论】:

以上是关于解析树和抽象语法树 (AST) 有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章

抽象语法树和打印

符号表和抽象语法树是啥关系?两者在编译器设计中是不是必需

JavaScript的工作原理:解析抽象语法树(AST)+ 提升编译速度5个技巧

jsqlparser:基于抽象语法树(AST)遍历SQL语句的语法元素

理解Babel是如何编译JS代码的及理解抽象语法树(AST)

AST 抽象语法树