注:タイトルで「複雑」を使用したとき、式には多くの演算子とオペランドがあることを意味します。式自体が複雑なわけではありません。
私は最近、x86-64アセンブリの単純なコンパイラに取り組んでいます。コンパイラのメインフロントエンド(レクサーとパーサー)を終了し、プログラムの抽象構文ツリー表現を生成できるようになりました。そして、私の言語は静的に型付けされるので、次のフェーズ、つまりソースコードの型チェックを実行しています。しかし、私は問題に遭遇し、自分で合理的に解決することができませんでした。
次の例を考えてみましょう。
私のコンパイラのパーサーは、次のコード行を読み取りました。
int a = 1 + 2 - 3 * 4 - 5
そして、それを次のASTに変換しました:
=
/ \
a(int) \
-
/ \
- 5
/ \
+ *
/ \ / \
1 2 3 4
次に、ASTを入力する必要があります。最初に=
演算子をチェックするタイプから始まります。まず、オペレーターの左側をチェックします。変数a
が整数として宣言されていることがわかります。そのため、右側の式が整数に評価されることを確認する必要があります。
式が1
or などの単一の値である場合、これがどのように行われるかを理解しています'a'
。しかし、複数の値とオペランドを持つ式 -上記のような複雑な式 -では、これはどのように行われますか?式の値を正しく判断するには、型チェッカーが実際に式自体を実行し、結果を記録する必要があるようです。しかし、これは明らかにコンパイル段階と実行段階を分離する目的を無効にしているようです。
私がこれを行うことができると思う他の唯一の方法は、ASTの各部分式のリーフを再帰的にチェックし、リーフのすべてのタイプが期待される演算子タイプと一致することを確認することです。そのため、=
演算子から始めて、型チェッカーは左側のすべてのASTをスキャンし、リーフがすべて整数であることを確認します。次に、部分式の各演算子に対してこれを繰り返します。
「The Dragon Book」のコピーでトピックを調査しようとしましたが、あまり詳細に説明されていないようで、すでに知っていることを繰り返します。
コンパイラが多くの演算子とオペランドを含む式を型チェックするときに使用される通常の方法は何ですか?上記の方法のいずれかが使用されていますか?そうでない場合、メソッドは何であり、どのように正確に機能しますか?
double a = 7/2
は、右側をdoubleとして解釈しようとするため、分子と分母をdoubleとして解釈し、必要に応じて変換しようとします。結果としてa = 3.5
。ボトムアップは整数除算を実行し、最後のステップ(割り当て)でのみ変換しa = 3.0
ます。
int a = 1 + 2 - 3 * 4 - 5
それにint a = 5 - ((4*3) - (1+2))