抽象構文木と具体的な構文木の違いは何ですか?


84

インタプリタ/コンパイラがどのように機能するかについて少し読んでいますが、混乱している領域の1つは、ASTとCSTの違いです。私の理解では、パーサーはCSTを作成し、それをセマンティックアナライザーに渡してASTに変換します。ただし、私の理解では、セマンティックアナライザーは単にルールが守られていることを確認します。なぜ具体的ではなく抽象的にするために実際に変更を加えるのか、私にはよくわかりません。

セマンティックアナライザーについて私が見逃しているものはありますか、それともASTとCSTの違いはやや人工的なものですか?

回答:


62

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

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

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


2
補足:Pythonインタープリターは最初にCSTを構築し、次にASTに変換します。
cgsdfc 2018

33

具体的な構文木の文法規則は、構文で言うマッチ。抽象構文ツリーの目的は、「構文ツリー」に不可欠なものを「単純に」表現することです。

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

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

しかし、そのようなASTがあると、そこにはなかった問題が発生します。文法と一致しないため、両方を精神的に追跡する必要があります。そして、3500ルール文法に対して1500のASTノードがある場合、これは非常に重要です。そして、文法が進化した場合(常に進化します!)、同期を保つための2つの巨大なセットがあります。

もう1つの解決策は、パーサーにCSTノードを作成させ、それらを使用させることです。これは、文法を構築する際の大きな利点です。3500の文法ルールをモデル化するために1500の特別なASTノードを発明する必要はありません。木が文法と同型であると考えてください。文法エンジニアの観点からは、これは完全に頭脳がないため、文法を正しく理解し、心ゆくまでハッキングすることに集中できます。おそらく、ノードビジタールールをさらに作成する必要がありますが、それは管理できます。これについては後で詳しく説明します。

私たちがやるとDMSソフトウェアリエンジニアリングツールキットは、自動的に(GLR)の解析プロセスの結果に基づいて、CSTを構築することです。次に、DMSは、スペース効率の理由から、値を持たない端末(キーワード、句読点)、意味的に役に立たない単項生成を排除し、次のようなリストである文法ルールペアのリストを形成することにより、「圧縮」CSTを自動的に構築します。

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

そしてそのような形の多種多様なバリエーション。あなたは文法規則と仮想CSTの観点から考えます。ツールは圧縮された表現で動作します。あなたの脳にやさしく、実行時に速く/小さくなります。

驚くべきことに、この方法で構築された圧縮CSTは、手作業で設計した可能性のあるASTのように見えます(例の最後にあるリンクを参照)。特に、圧縮されたCSTは、具体的な構文であるノードを伝送しません。少し厄介な点があります。たとえば、式のサブグラマーに古典的に見られる「(」および「)」の具象ノードはツリーにありませんが、「括弧ノード」圧縮されたCSTに表示されるため、処理する必要があります。真のASTにはこれがありません。これは、AST構造を指定する必要がないという利便性のために、かなり小さな価格のように思えます。また、ツリーのドキュメントはいつでも利用でき、正しいものです。文法ドキュメントです。

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

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

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

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


25

これは、TerrenceParrによるExpressionEvaluatorの文法に基づいています。

この例の文法:

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に存在しないことに注意してください。

AST

編集

詳細な説明については、コンパイラとコンパイラジェネレータのページを参照してください。23


20

このブログ投稿は役に立つかもしれません。

ASTは、セマンティクスに寄与しないであろう多くの中間的な文法/構造情報を「捨てる」ように私には思えます。たとえば、3がアトムであり、項がファクターである3かどうかは気にしません。指数式などを実装するときだけ気にします。


9

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

  • expression_listは次のようになります:expression
  • expression_listには、expression、expression_listを指定できます。

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

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


2

簡単に言うと、ASTにはコードのセマンティクスのみが含まれ、解析ツリー/ CSTにはコードがどのように正確に記述されたかに関する情報も含まれます。


1

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

 

注意:おかしなことに、リファクタリングエンジンを実装すると、ASTにはすべての具体的な情報が再び含まれますが、それがこの分野の標準用語になっているため、ASTと呼び続けることになります(したがって、長いと言えます)以前は元の意味を失いました)。


まあ、それはすべての具体的な情報を持っていないかもしれません。必要なのは、その情報を再生成できることだけです。私の答えを見てください。
Ira Baxter

昨日コメントしましたか?SOバグですか、それとも私が知らないコメントネクロマンサーバッジを獲得する必要がありますか?:)(PS:でも、あなたから聞いて良かったです。DMSに関するGoogle Techの講演に
偶然出くわしました

1

違いはありません。

ASTは通常、字句の内容を破棄することによってプログラミング言語式のセマンティクスを概算する方法として説明されます。たとえば、文脈自由文法では、次のEBNFルールを記述できます。

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

一方、ASTの場合は、適切な算術演算を表すmul_rulediv_ruleのみを使用します。

そもそもこれらのルールを文法に取り入れることはできないのでしょうか。もちろん。上記のコンパクトで抽象的なルールを、前述のASTノードを模倣するために使用されるより具体的なルールに分割することで書き直すことができます。

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

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

したがって、ASTは、文法とパーサーの欠陥を修正するために使用されるアドホックサプリメントです。CST-> AST変換はリファクタリングの動きです。追加のコンマまたはコロンが構文ツリーに格納されている場合、誰も気にしませんでした。それどころか、さまざまなツリーを同時に維持したり、追加の推論エンジンを作成したりする代わりに、リファクタリングを行うためにASTを使用することを好むため、一部の作成者はそれらをASTに後付けします。プログラマーは正当な理由で怠惰です。実際には、エラー報告のために、字句解析によって収集された行と列の情報をASTに格納します。確かに非常に抽象的な。


0

CST(Concrete Syntax Tree)は、文法(プログラムの記述方法の規則)のツリー表現です。コンパイラのアーキテクチャによっては、パーサーがASTを生成するために使用できます。

AST(抽象構文木)は、コンパイラのパーサー部分によって生成された、解析されたソースのツリー表現です。トークン+文法に関する情報を格納します。

コンパイラのアーキテクチャに応じて、CSTを使用してASTを生成できます。CSTはASTに進化すると言っても過言ではありません。または、ASTはより豊富なCSTです。

詳細については、次のリンクを参照してください:http//eli.thegreenplace.net/2009/02/16/abstract-vs-concrete-syntax-trees#id6


1
これらは特に「単純化された」について明確にする必要があると思います。少なくとも概念的には「複雑」と見なされる傾向がありますが、それでも有用なことは何も説明されていません。
Joshua Hedges 2018

1
-1を+1に変更しました。あなたが行った説明で十分だと思います。
JoshuaHedges18年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.