4

bison で文脈自由文法を作成し、flex でスキャナーを作成しました。ここで、セマンティックチェックも行いたいと思います。たとえば、入力が次のようなものだとします。

int m=5;
c=c+5;

この入力は構文的に正しいですが、宣言されていない変数「c」が使用されています。どうすればそのようなセマンティックチェックを行うことができますか? どこから始めればよいですか?コードを flex と bison のどちらで書くべきですか? 誰か助けていただければ幸いです。ありがとう。

4

1 に答える 1

8

最初に考慮すべきことは、どの時点でセマンティック チェックを行うのに十分な情報があるかということです。

C のような静的言語の場合、Yacc でトリガーされたような構文指向のルールを使用して、構文解析時にこのセマンティック ライトを実行できます。

パーサーはシンボル テーブルを維持する必要があります。つまり、新しい関数本体やステートメント ブロックなどの新しいスコープを開くたびに、そのスコープ用の新しいシンボル テーブル オブジェクトを作成する必要があります (そして、グローバル パーサー変数に「現在のスコープ」としてそのポインターを保持する必要があります)。 )。スコープには、前のスコープへのポインターもあります。スコープが閉じると、元のスコープが「現在のスコープ」として復元されます。このスコープの開閉は、関数やステートメントの本体、または構造体などのブロック構成を処理するパーサー規則に関連付けられています。

スコープには、変数名とセマンティック情報 (シンボルの種類など) との関連付け、および型などのその他の属性が含まれます。

パーサーがある種の宣言を処理すると、宣言された名前が現在のシンボル テーブルに導入され、その後認識されます。

それでは、問題に早送りします。名前が定義されていないことを確認する方法です。これは難しくありません。どこかで、パーサーには次のようなルールがあります

primary_expression : '(' expression ')'
                   /* ...*/
                   | CONSTANT
                   | IDENT
                   ;

一次式は、変数、定数、または関数の名前などの識別子にすることができます。ルールが厳密で、使用できる場合は定義する必要がある場合は、ここでチェックを入れることができます。

のアクション ルールについてはIDENT、現在のシンボル テーブルで識別子を検索します。検索で何も出てこない場合は、未定義の識別子があるというエラーを発生させます。

擬似コード:

primary_expression : '(' expression ')'
                   /* ...*/
                   | CONSTANT
                   | IDENT {
                       struct symbol *sym = symbol_lookup(current_scope, $1);
                       if (sym == NULL) {
                         static_error("undeclared identifier %s", $1);
                         $$ = error_node();
                       } else {
                         /* ... */
                       }
                     }

このsymbol_lookup関数は、現在のスコープ内を検索するだけではありません! 識別子が現在のスコープで見つからない場合は、親スコープに再帰します。スコープのチェーンの最上位のスコープは、ファイル スコープです。識別子がそこにある場合、それはある種のグローバル識別子です。そこにも見つからない場合は、未定義です。私も作りましたstatic_error。のようprintfな引数を持ち、ファイル/行番号情報を追加し、エラー カウントをインクリメントします (パーサーが完了すると、ゼロ以外のエラー カウントに基づいて失敗を示すことができます)。私error_nodeも作りました。これは、エラーを示すある種のノードを生成する関数またはマクロです (おそらく単なるヌル ポインター)。パーサー ルールは、何かを生成して格納する必要があります。$$. 存在しない識別子については、代わりに何らかのマーカーをツリーに入れることができます。

Yacc を使用して C でコンパイラを作成している場合、シンボル テーブルなどのこれらすべてのデータ構造を考案し、サポート ライブラリを作成するために、多くの作業を行う必要があります。

于 2013-06-08T01:31:28.173 に答える