3

パーサー ツリー (ST) を生成するか、抽象構文ツリー (AST) を生成するかのどちらかを選択するために、あなたの意見が必要です。コンテキストは次のとおりです。

C のような言語 (より疑似コード指向にするためにいくつかの変更を加えた C のサブセット) を解析したいのですが、他の出力言語/ファイルに翻訳するためではなく、実行プロセスをアニメーション化するためにその文を実行します。 (Qt を使用して描画します)。この C サブセットの機能は、ネストされたスコープを有効にすることです。ST と AST の間の私の選択に関連する私の疑問は、シンボル テーブルから生じます。一般的な考え方は次のとおりです (Boost.spirit を使用):

  1. カスタム Boost.spirit パーサーによるソース コード ファイルの解析。
  2. セマンティック アクションは、ソース コードの構文ツリーのコピーにすぎない構文ツリーを生成します (または、Boost.spirit の内部構文ツリーのコピーですが、独自のクラスと構造を使用します)。したがって、AST はありません。
  3. この ST を使用して、プログラムはこの構文ツリーを次のようにトップダウン方向に読み取ります。
    1. 最初の文を実行します。
    2. 新しい (文の結果) 値を含むシンボル テーブルをアップロードします。
    3. シンボル テーブルの実際の状態をプログラム状態スタックに保存します。
    4. ST が完全に処理されるまで 3.1 に。
    5. プログラム状態スタックを読み取って描画するアルゴリズムをアニメーション化します。

2 つの理由:

  1. AST を使用すると、解析後に変数宣言やその型などに関する情報が失われます。したがって、パーサーのセマンティック アクションを使用してシンボル テーブルを操作する必要があり、パーサーの記述と理解が複雑になります。さらに、実際のスコープに関係なく、すべての変数を含むシンボルテーブルで常に作業する必要があります (スコープ i にいる場合は、スコープ i、i-1、....、1 のみが必要です。アルゴリズム全体のすべてのスコープ)。これはメモリを消費します。
  2. アニメーションによるアルゴリズムの理解を複雑にしないために、プログラム状態スタックでは、実際のスコープと以前のスコープの変数のみが必要です。ST を使用する場合、スタックに保存する前に不要なシンボルをすべて削除する必要があります。これには時間がかかります。
  3. コントロール スコープを持つ静的シンボル テーブルは、動的シンボル テーブルよりも設計と使用が難しくなります。静的シンボル テーブルには、各スコープの識別子 (たとえば) が必要であり、ツリーの各ノードを各識別子に関連付ける必要があります。スコープ i にいる場合、必要な「ベクトル」は 2 つだけ (おそらくダブル キューとスタック) であるため、ダイナミック シンボル テーブルの方が簡単に機能します。

    • シンボルとその関連情報を含むコンテナー (ダブル キュー?): コンテナー内の最後の変数は、最も近い宣言された変数です。
    • 各スコープの開始 (ダブル キューのインデックス) を示す、整数のコンテナー (スタック)。

    たとえば、スコープ i の場合:

    • コンテナ 1: [xyzxabzfaz]
    • コンテナ 2: [0 3 6 8]

    スコープ i を離れると、最後の整数と記号を位置 8 から最後まで消去するだけで済みます。ツリーは変更されません。

  4. 実行時間内に各文を実行する必要があるため、ST は私の実行を容易にします。

2 つの質問:

  1. じゃあどっちがいい?
  2. スピリットの内部ツリーを抽出したり、コピーしないようにカスタマイズしたりする形式はありますか?
4

1 に答える 1

1

あなたが探しているのは、プログラムのセマンティクス(構文ではなく) を表す抽象セマンティック グラフ (ASG) だと思います。あなたができることは次のとおりです。

  1. ソースを AST に解析してから、
  2. AST を ASG に変換し、最後に
  3. ASG をウォークして実際のコードを実行します。

また、抽象的すぎないASTを実際に構築できると思います。たとえば、私は現在独自のスクリプト言語インタープリターを構築しており、AST には変数名が含まれます (これは、パーサー/インタープリターおよび解析されたプログラム自体のデバッグにも役立ちます)。

于 2012-11-18T20:58:17.543 に答える