web-dev-qa-db-ja.com

抽象構文ツリーと具象構文ツリーの違いは何ですか?

私はインタープリター/コンパイラーがどのように機能するかについて少し読んでいますが、混乱している1つの領域は、ASTとCSTの違いです。私の理解はパーサーがCSTは、それをASTに変換するセマンティックアナライザーに渡しますが、私の理解では、セマンティックアナライザーは単にルールに従うことを保証するだけであるということです。コンクリート。

セマンティックアナライザーに欠けているものはありますか、またはASTとCSTの違いは多少人工的ですか

73
Jason Baker

具体的な構文ツリーは、解析された形式でソーステキストを正確に表します。一般に、ソース言語を定義する文脈自由文法に準拠しています。

ただし、具体的な文法とツリーには、ソーステキストを明確に解析可能にするために必要なものがたくさんありますが、実際の意味には寄与しません。たとえば、演算子の優先順位を実装するために、CFGには通常、複数レベルの式コンポーネント(用語、因子など)があり、演算子は異なるレベルでそれらを接続します(用語を追加して式を取得し、用語はオプションで乗算された因子で構成されます)など)。ただし、実際に言語を解釈またはコンパイルするには、これは必要ありません。演算子とオペランドを持つ式ノードのみが必要です。抽象構文ツリーは、具体的な構文ツリーを、プログラムの意味を表現するために実際に必要なものまで簡略化した結果です。このツリーの定義ははるかに単純であるため、実行の後の段階での処理が容易です。

通常、具体的な構文ツリーを実際に構築する必要はありません。 YACC(またはAntlr、Menhir、その他)文法のアクションルーチンは、抽象構文ツリーを直接構築できるため、具体的な構文ツリーは、ソーステキストの解析構造を表す概念的なエンティティとしてのみ存在します。

56

具象構文ツリーは、文法規則が言う構文と一致します。 抽象的な構文ツリーの目的は、「構文ツリー」に不可欠なものを「単純」に表現することです。

AST IMHOの実際の値は、CSTよりも)小さいであるため、処理にかかる時間が短くなる(誰が気にかけているのかと言うかもしれませんが、私は一度に数千万のノードが存在するツールを使用しています!).

構文ツリーの構築をサポートするほとんどのパーサージェネレーターは、ツリーノードがCSTより「単純」であるという仮定の下で、構築方法を正確に個人的に指定することを主張します。怠))。おそらく、より少ないツリービジター関数をコーディングする必要があることを意味します。また、エンジニアリングエネルギーを最小限に抑えるという点でも価値があります。 3500のルールがある場合(たとえば、COBOLの場合)、これは重要です。そして、この「より単純な」性質は「小さい」という優れた特性につながります。

しかし、そのようなASTがあると、そこにはなかった問題が生じます。それは文法と一致せず、今では両方を精神的に追跡する必要があります。 1500 ASTノードがある場合、これは非常に重要です。グラマーが進化する場合(常にそうです!)同期。

別の解決策は、パーサーにCSTノードを単純に構築させ、それらを使用することです。これは、文法を構築する際の大きな利点です。3500の文法規則をモデル化するために1500個の特別なASTノードを作成する必要はありません。ツリーが文法と同型であることを考えてください。グラマーエンジニアのこれは完全にブレインレスであるため、グラマーを正しく理解し、それを心のコンテンツにハッキングすることに集中できます。おそらく、ノードビジタールールをさらに記述する必要がありますが、これは管理できます。

DMS Software Reengineering Toolkit を使用して行うことは、(GLR)解析プロセスの結果に基づいてCSTを自動的に構築することです。 DMSは、スペースを節約するために、値を持たない端末(キーワード、句読点)、意味的に無用な単項生成を排除し、次のようなリストの文法規則のリストを作成することにより、自動的に「圧縮」CSTを構築します:

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

そして、そのような形式の多種多様なバリエーション。文法規則と仮想CSTの観点から考えます。ツールは圧縮表現で動作します。脳で簡単、実行時の高速化/小型化。

驚くべきことに、この方法で構築された圧縮CSTは、手作業で設計したASTのように見えます(例の最後のリンクを参照)。特に、圧縮CSTにはノードがありません。ちょっとした厄介さがあります:例えば、式のサブ文法で古典的に見られる '('と ')'の具象ノードはツリーにありませんが、「括弧ノード」doesは、圧縮されたCSTに表示され、処理する必要があります。trueASTはこれを持ちません。 AST構造をこれまでに指定する必要はありません。ツリーのドキュメントは常に利用可能で正しいです:文法isドキュメント。

「余分な訪問者」を避ける方法完全にではありませんが、DMSはASTライブラリを提供し、ASTを歩き、CSTとAST透過的にDMSは、「属性文法」エバリュエーター(AGE)も提供します。これは、計算された値をツリーの上下に渡す方法です; AGEは、ツリー表現の問題をすべて処理するため、ツールエンジニアは、最後に、DMSは「表面構文」パターンも提供します。これにより、関連するノードタイプのほとんどを知らなくても、文法からのコードフラグメントを使用して特定のタイプのサブツリーを見つけることができます。

他の答えの1つは、ソースを再生成できるツールを構築する場合、ASTはCSTと一致する必要があります。実際には正しくありませんが、ソースを再生成する方がはるかに簡単ですCSTノードがある場合 DMSはprettyprinterのほとんどを自動的に生成します 両方にアクセスできるため:-}

結論:ASTは、物理学と概念の両方の小規模に適しています。自動化されたAST CSTからの構築は両方を提供し、2つの異なるセットを追跡する問題を回避できます。

編集2015年3月: この方法で作成されたCSTと「AST」の例へのリンク

30
Ira Baxter

これは、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)

解析ツリー

解析ツリーは、入力の具体的な表現です。解析ツリーは、入力のすべての情報を保持します。空のボックスは空白、つまり行末を表します。

Parse Tree

AST

ASTは入力の抽象表現です。関連付けはツリー構造から派生しているため、ASTには括弧がありません。

AST

編集

詳細な説明については、 Compilers and Compiler Generators pgを参照してください。 23

18
Guy Coder

具象構文ツリーは、言語の文法の規則に従います。文法では、「式リスト」は通常2つのルールで定義されます

  • expression_listは次のいずれかです。
  • expression_listには、expression、expression_listを指定できます

文字通り、これら2つのルールは、プログラムに表示される式リストにくし形を与えます。

抽象構文ツリーは、さらに操作するのに便利な形式です。プログラムの記述方法だけでなく、プログラムの意味を理解している人にとって意味のある方法で物事を表します。関数の引数のリストである可能性のある上記の式のリストは、式のベクトルとして便利に表現できます。静的解析では、式の総数を明示的に利用でき、各式にその式によってアクセスできるためです。インデックス。

9
Pascal Cuoq

単純に、ASTにはコードのセマンティクスのみが含まれ、Parse tree/CSTにはコードが正確に記述された方法に関する情報も含まれます。

1
mym

違いを生まない違いです。

ASTは通常、字句の内容を捨ててプログラミング言語の表現のセマンティクスを近似する方法として説明されています。たとえば、文脈自由文法では、次のEBNFルールを書くことができます

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

一方、ASTの場合は、 mul_rule そして div_rule 適切な算術演算を表します。

そもそもこれらのルールを文法に導入することはできませんか?もちろん。上記のコンパクトおよびabstractルールをさらに細かく書き換えることで、前述のASTノードを模倣するために使用されるルール:concreteルールを作成できます。

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

さて、トップダウン解析の観点から考えると、2番目の term 間のFIRST/FIRST競合を導入します mul_rule そして div_rule LL(1)パーサーが処理できないもの。最初のルール形式は、2番目のルール形式の左因数分解バージョンで、構造を効果的に削除しました。ここでLL(1)を使用するための賞金を支払う必要があります。

したがって、ASTは、文法とパーサーの欠陥を修正するために使用される特別な補足です。 CST-> AST変換はリファクタリングの動きです。追加のカンマまたはコロンが構文ツリーに格納されている場合、だれも気にしません。反対に、一部の著者はさまざまなツリーを同時に維持する代わりに、リファクタリングを行うためにASTを使用するか、追加の推論エンジンを記述します。プログラマーは、正当な理由で怠け者です。

1
Kay Schluehr

具体的な構文ツリーには、余分な括弧、空白、コメントなどのすべての情報が含まれます。抽象構文ツリーは、この情報から抽象化します。

NB:おもしろい、リファクタリングエンジンを実装すると、ASTにはすべての具体的な情報が含まれますが、引き続き=として参照しますASTそれはフィールドの標準用語になったためです(そのため、その元の意味がずっと前に失われたと言うことができます)。

1
akuhn