私は自分が何をすべきかを理解するのに苦労しています。私が理解した唯一のことは、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 マイナス プログラムでなければなりません。
スコープ:
最も基本的なアプローチには、グローバル スコープと、宣言された各関数のスコープがあります。この言語では、複合ステートメント内での宣言、つまりスコープのネストが可能です。これを実装するには、ある種のスコープの番号付けまたはスタック方式が必要になります。(スタッキングは、私たちが構築しているワンパス コンパイラに最適です。)