3

簡単なパーサーを書くのは簡単で、私は何年にもわたっていくつか実装してきました。大学では、私たちもそれを書かなければなりませんでした。しかし、この方法を使用して意味のある出力を生成する必要はありませんでした。バックエンドの作成方法を学んだことはありません。

単純化された Pascal で動作する再帰降下パーサーがあり、そのコードを C++ に変換したい場合、どうすればよいでしょうか? 抽象構文ツリーの生成などの中間ステップが必要だとは思いません。

では、コンパイルまたは変換されたコードを出力するにはどうすればよいでしょうか。これについて私が見つけた唯一の有用な例は、Jack Crenshaw のチュートリアルにありますが、他のほとんどのリソースと同様に、フロント エンドに重点を置いています。パーサー コードと文法の関係は非常に明白です。パーサーのメソッドと出力の関係はどうですか? 関数宣言用の私のパーサー メソッドは、正確に 1 つの EmitLn(ここでは C++ コード) 呼び出しに関連付けることができます。しかし、式など、それほど簡単ではないパーサー メソッドについてはどうでしょう。式はさらに多くの呼び出しに分割される可能性があるため、式の出力コードを 1 つずつ分割できるようにする Emit() 関数が必要であることを暗示しています。コードを出力するための定型コードはありますか?Jack Crenshaw の Lets Build a Compiler? の EmitLn 関数など。これは、基本的なシンボル テーブルを維持する必要があることも示しています。これは、ほとんどの例で省略されていることがよくあります。

私は正しいですか?他に何を知っておくべきですか?ヒント/提案、またはリソースはありますか? 私の大きな質問は、コンパイラのフロント エンドに関するチュートリアルがたくさんありますが、バック エンドについての説明はどうですか? 私は言語を解析できますが、それを他の言語に翻訳してコンパイルできるように進化させたいと考えています。

4

2 に答える 2

3

あなたがやろうとしているように、解析中にコードを吐き出す「オンザフライ」コードジェネレーターを使用する簡単なコンパイラーがあります。良いニュースは、それらが簡単に見えることです。

問題は、コンパイルとは基本的に、コードの一部から別の部分に情報を拡散して、適切なコードを生成できるようにすることです。そのために、コンパイラの専門家はずっと前に解析とコード生成を分離することに決めました。パーサーはコードを解析し、プログラムを表す別の中間データ構造 (多くの場合、抽象構文ツリーまたはトリプル) を構築します。

多くの場合、適切なコードを生成する方法を決定するために、中間構造に対して非常に深い分析が行われます。これをうまく行うための手法は複雑ですが、優れた (そして正しい) コードを作成する必要性が動機となっています。

標準のコンパイラ リソースを確認してみてください。 コンパイラの書き方を学ぶ

ハッキングする代わりに、これらのリファレンスのいくつかを詳細に読むことは、あなたの時間の価値があります. ひとつだけ挙げるとすれば、『アホとウルマン』は定番の本です。

オンザフライ コード生成がどのように適切に機能するかを確認したい場合は、 metacompilersを確認してください。

于 2011-10-20T08:56:17.060 に答える
1

簡単な答え文法のルールに一致した後、入力に基づいて何かを行う関数を呼び出します。

長い答え:構文指向の通訳者について議論しているTerenceParrによる言語実装パターンから:

構文指向のインタープリターは、ASTを作成したり、ソースコードをバイトコードに変換したりしません...インタープリターは、構文を直接フィードしてステートメントを実行します。

これはまさに私が最初の質問で目指していたアイデアです。本の続きで、彼はテクニック、それがどのように機能するか、それが何で構成されているか、そして制限について説明します。汎用言語ではなく、DSLおよび小さな言語で機能します。

彼は、IFやループなどの構成は実装が難しいと述べています。これは本当のようですが、私の言語であるPeayBASICでそのような機能を実装するのに問題はありませんでした。このパターンには、一連の命令または単純なステートメントである言語が理想的です。彼は例としてテキスト処理言語を挙げています。

文法は、「これに一致し、それを呼び出す」ペアで構成されるように拡張されています。したがって、文法に必要なルールには、それに関連付けられたアクションが必要です。代入ステートメントの例:

assignment : ID '=' expr {interp.assign($ID, $expr.value);};
expr returns [Object value] : ... ;
于 2012-08-30T18:47:55.870 に答える