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

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

48832 次浏览

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

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

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

Parse 树更接近地表示源代码。

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

  • 环境状况
  • 如果凯斯
  • 别的案子

对于类 C 语言,Parse Tree 还需要包含“ if”关键字、括号和花括号的节点。

This is based on the 表达式计算器 grammar by Terrence Parr.

The grammar for this example:

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 中没有括号,因为关联可以从树结构派生。

AST

更详细的解释见 编译器和编译器生成器第23页
or 抽象语法树 on pg. 21 in 程序设计语言的语法和语义

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

解析树

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

它们是树状的数据结构,显示了如何通过有关语言的语法生成一个输入终端字符串(源代码标记)。解析树的根是语法的最一般符号-开始符号(例如,声明) ,内部节点表示开始符号扩展到的非终端符号(可以包括开始符号本身) ,例如 表情声明任期function call。叶子是语法的终端,实际的符号在语言/输入字符串中作为标识符、关键字和常量出现,例如 为了9如果等。

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

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

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

enter image description here

抽象语法树

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

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

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

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

下面是 AST 的图形表示:

enter image description here

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

接受帕斯卡的任务 年龄: = 42;

语法树看起来就像源代码。 [年龄][ : = ][42][ ; ]

抽象树应该是这样的 [ = ][年龄][42]

赋值变成一个有两个元素的节点,年龄和42。这个想法就是你可以执行这个任务。

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

维基百科说

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

Quora 上的一个答案是

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

结合上述两个定义,

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