Parsing 抽象语法树和具体语法树之间的区别是什么?

Parsing 抽象语法树和具体语法树之间的区别是什么?,parsing,terminology,abstract-syntax-tree,semantic-analysis,concrete-syntax-tree,Parsing,Terminology,Abstract Syntax Tree,Semantic Analysis,Concrete Syntax Tree,我一直在读一些关于解释器/编译器如何工作的文章,其中一个让我感到困惑的领域是AST和CST之间的区别。我的理解是,解析器生成一个CST,将其交给语义分析器,语义分析器将其转换为AST。然而,我的理解是语义分析器只是确保遵循规则。我真的不明白为什么它会做出任何改变,让它变得抽象而不是具体 语义分析器是否有我遗漏的地方,或者AST和CST之间的区别是否有些人为的?可能会有所帮助 在我看来,AST“丢弃”了很多对语义没有帮助的中间语法/结构信息。例如,你不在乎3是一个原子是一个项是一个因子是一个。。。

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

语义分析器是否有我遗漏的地方,或者AST和CST之间的区别是否有些人为的?

可能会有所帮助


在我看来,AST“丢弃”了很多对语义没有帮助的中间语法/结构信息。例如,你不在乎3是一个原子是一个项是一个因子是一个。。。。在实现求幂表达式或其他任何东西时,您只需要注意它是
3

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

  • 表达式列表可以是:表达式
  • 表达式列表可以是:表达式、表达式列表
按照字面意思,这两条规则为程序中出现的任何表达式列表提供一个梳形


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

具体的语法树以解析的形式精确地表示源文本。一般来说,它符合定义源语言的上下文无关语法

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


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

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

注:有趣的是,当你实现一个重构引擎时,你的AST将再次包含所有的具体信息,但你将继续将其称为AST,因为这已经成为该领域的标准术语(因此可以说它很久以前就失去了它的原始含义)具体的语法树与语法规则所说的语法相匹配。抽象语法树的目的是对“语法树”中的基本内容进行“简单”表示

AST IMHO中的一个实际值是,它比CST小,因此处理时间更短。(你可能会说,谁在乎呢?但我用我们现有的工具工作 数千万个节点同时运行!)

大多数支持构建语法树的解析器生成器都坚持认为,在假设树节点比CST“更简单”的情况下(在这一点上,它们通常是正确的,因为程序员非常懒惰),您必须亲自指定如何构建语法树。可以说,这意味着您必须编写更少的树访问者函数,这也很有价值,因为它可以最大限度地减少工程能耗。当您有3500条规则(例如COBOL)时,这很重要。这种“简单”的特性导致了“小”的良好特性

但是拥有这样的AST会产生一个不存在的问题:它与语法不匹配,现在你必须在心里跟踪它们。当3500规则语法有1500个AST节点时,这非常重要。如果语法发生了变化(他们总是这样!),那么现在你有两套庞大的东西需要保持同步

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

我们使用的是根据(GLR)解析过程的结果自动构建CST。DMS然后出于空间效率的原因,通过消除非带值终端(关键字、点号)、语义上无用的一元结果,并为列表l中的语法规则对形成可直接索引的列表,自动构造“压缩”CST
    L = e ;
    L = L e ;
    L2 = e2 ;
    L2 = L2  ','  e2 ;
term: atom (('*' | '/') term )*
term: mul_rule | div_rule
mul_rule: atom ('*' term)*
div_rule: atom ('/' term)*
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)