1

私は自分が何をすべきかを理解するのに苦労しています。私が理解した唯一のことは、cminus.y ファイルで yacc を使用する必要があるということです。その後のことについては完全に混乱しています。私が何をする必要があるかを理解できるように、誰かが私にこれを別の方法で説明できますか?

前書き:

lex/flex と yacc/Bison を使用して LALR パーサーを生成します。cminus.y というファイルをお渡しします。これは、C-minus と呼ばれる単純な C に似た言語の yacc 形式の文法ファイルで、Kenneth C. Louden 著 Compiler Construction という本から引用されています。文法はかなり明白であるべきだと思います。Yahoo グループには、yacc の使用方法に関するいくつかの説明へのリンクがあります。flex を理解したので、yacc を学ぶのはかなり簡単です。基本型は int のみです。int は 4 バイトです。ブール値は、C のように int として処理されます (実際には、文法では変数を void 型として宣言できますが、そうしないでください)。1 次元配列を使用できます。ポインターはありませんが、配列要素への参照は (C のように) ポインターとして扱われるべきです。この言語は、代入、IF-ELSE、WHILE、および関数の呼び出しと戻りを提供します。コンパイラに MIPS アセンブリ コードを出力させ、それを SPIM で実行できるようにします。このような最適化のない単純なコンパイラの場合、IR は必要ありません。アセンブリ コードを 1 回のパスで直接出力できます。ただし、最初のステップはシンボル テーブルを生成することです。

記号表:

ここでの Barrett 博士のアプローチは気に入っています。これは、さまざまな型のオブジェクトを処理するために多くのポインターを使用します。基本的に、シンボル テーブルの要素は、識別子、型、および属性オブジェクトへのポインターです。属性オブジェクトの構造は、タイプによって異なります。扱うタイプはごく少数です。少なくとも最初は、線形検索を使用してテーブル内のシンボルを見つけることをお勧めします。より良いパフォーマンスが必要な場合は、後でハッシュに変更できます。(C で保持したい場合は、malloc を使用してオブジェクトの動的割り当てを行うことができます。) 最初に、存在するすべての異なる種類のシンボルのリストを作成する必要があります (それほど多くはありません)。各。まだすべての問題をカバーしていないため、新しい属性を追加できるようにしてください。文法を見てみると、関数のパラメーター リストの問題は、設計に考慮が必要な場所です。シンボル テーブルのエントリとポインタを増やすことをお勧めします。

テスト:

文法は正しいので、既存の文法をそのまま使用してパーサーを生成すると、パーサーは正しい C マイナス プログラムを受け入れますが、ルールに関連付けられたコード スニペットがないため、出力は生成されません。コード スニペットを追加して、シンボル テーブルを作成し、その際に情報を出力します。識別子が宣言されたら、シンボル テーブルに入力されている情報を出力する必要があります。同じスコープで同じシンボルの以前の宣言が見つかった場合は、エラー メッセージが出力されます。識別子が参照されている場合は、テーブルで参照して、そこにあることを確認する必要があります。現在のスコープで宣言されていない場合は、エラー メッセージが出力されます。スコープを閉じるとき、参照されていない識別子に対して警告が生成される必要があります。テスト入力は、正しく形成された C マイナス プログラムでなければなりません。

スコープ:

最も基本的なアプローチには、グローバル スコープと、宣言された各関数のスコープがあります。この言語では、複合ステートメント内での宣言、つまりスコープのネストが可能です。これを実装するには、ある種のスコープの番号付けまたはスタック方式が必要になります。(スタッキングは、私たちが構築しているワンパス コンパイラに最適です。)

4

1 に答える 1

3

(免責事項)私はコンパイラークラスの経験があまりありませんが(コンパイラーの学校のコースのように)、私が理解していることは次のとおりです。

1)パーサーを作成するには、前述のツールを使用する必要があります。パーサーは、入力が与えられると、cminus.yで定義された文法に関して入力が正しいプログラムであるかどうかをユーザーに通知します。私はyacc/bisonを使ったことがないので、それがどのように行われるのかわかりませんが、これは行われているようです:

  • (入力)解析される出力を表すある種のファイル
  • (出力)reply-of-some-sortは、提供された文法に関して(入力)が正しいかどうかを示します。

2)また、出力は変数の整合性をチェックする必要があるようです(つまり、他のプログラミング言語と同じように宣言していない変数を使用することはできません)。これはシンボルテーブルを介して行われます。つまり、何かが宣言されるたびに、それをシンボルテーブルに追加します。識別子に遭遇したとき、それが言語識別子(ifまたはwhile、などfor)のいずれでもない場合は、シンボルテーブルでそれを検索して、宣言されているかどうかを判断します。そこにある場合は、続行します。そうでない場合-ある種のエラーを出力します

注:point(2)は、シンボルテーブルの簡略化されたテイクです。実際には、私が今書いた以上のものがありますが、それで始められるはずです。

私はyaccの例から始めます-yaccが何ができるか、そしてそれがどのようにそれを行うかを見てください。さらに理解するために読むことができる、いくつかの大きな例(シンボル付きの完全なテーブル)がそこにあるに違いないと思います。

例:

入力Aを取りましょう:

int main()
{
     int a;
     a = 5;
     return 0;
}

そして入力B:

   int main()
    {
         int a;
         b = 5;
         return 0;
    }

解析にC構文を使用していると仮定します。パーサーは入力Aを大丈夫と見なす必要がありますが、入力Bに対して「bは宣言されていません」と叫ぶ必要があります。

于 2009-11-16T10:06:07.600 に答える