解析树和抽象语法树 (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)的解释。它们是相似的数据结构,但构造不同并用于不同的任务。
解析树
解析树通常在词法分析之后作为下一步生成(它将源代码转换为一系列可以被视为有意义的单元的标记,而不仅仅是一个字符序列)。
它们是树状数据结构,显示了输入终端字符串(源代码标记)是如何由相关语言的语法生成的。解析树的根是语法中最通用的符号——开始符号(例如,语句),内部节点表示开始符号扩展成的非终结符(可以包括开始符号本身),例如表达式、语句、术语、函数调用。叶子是语法的终端,在语言/输入字符串中作为标识符、关键字和常量出现的实际符号,例如for、9、if等
在解析的同时,编译器还会执行各种检查以确保语法的正确性——并且语法错误报告可以嵌入到解析器代码中。
它们可用于通过语法导向定义或翻译方案进行语法导向翻译,用于简单的任务,例如将中缀表达式转换为后缀表达式。
这是表达式 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语句的语法元素