随想録


【声明:著作権所有、転載歓迎、商業用途に使用しないでください.連絡ポスト:[email protected]
コンパイラはずっと私の好きな話題です.コンパイラは、もともと意味のない文字データを1行1行実行可能なコードに変換する不思議なツールです.各クラス出身の学生として、コンパイル原理は専門学習の中で経験しなければならない部分である.ただ、その後の仕事では、本当にコンパイラの開発に従事する学生は少ないですが、コンパイル原理に関するメカニズムを知っていれば、あなたの仕事に大きな助けになります.コンパイル原理に関する本はたくさんありますが、ネット上ではアホバージョンの「コンパイル原理」があり、陳火旺院士の「コンパイル原理」があり、張素琴バージョンの「コンパイル原理」があり、3冊の本がいいと思います.また、現在ではコンパイル原理についても多くの開発ツールがあります.例えばlex&yaccは、基本的な文法パターンを書くことができれば、自分のコンパイラを設計するのも難しくありません.
実は、今のコンパイラはとっくに元の概念を突破しています.例えば、コンパイラの最終的なコードは必ずしも実際のマシン上で実行されるとは限らず、仮想マシンである可能性があります.コンパイラが言語をコンパイルする際に実行可能なファイルを生成する必要はなく、解釈できればよい.コンパイラは並列にコンパイルしたほうがいい.コンパイラは必ずしも大きくないので、luaなど、十数個のファイルでいいかもしれません.しかし、私たちが今日言ったコンパイラは伝統的なcコンパイラで、興味のある学生はコンパイラがどのように実行可能なファイルを生成するのに役立つかを見ることができます.文法、文法、意味、最適化の順に展開します.このようなコードがあると仮定すると
#include <stdio.h>

#define MAX_VALUE 7
int test(int value)
{
	return MAX_VALUE + 1 + value * 4;
}

int main(int argc, char* argv)
{
	int p;
	p = test(3);
	printf("p = %d", p);
	return 1;
}

   
(1)文法分析
文法分析はファイル全体のコンパイルの最も基本的な一環である.上のファイルには多くの文字が存在するので、それぞれ処理する必要があります.例えば、通常の分類はそうかもしれませんが、
a)文字が数字かどうか、例えば7,1,4
b)文字がstringタイプかどうか、例えば「p=%d」
c)文字がキーワードかどうか、例えばdefine
d)文字が変数であるかどうか、例えばvalue,argc,argv,p
e)文字が演算子かどうか、例えば+
f)文字が丸括弧、角括弧、花括弧などであるか
(2)構文解析
構文解析の目的は、現在のファイルがプログラミング言語の構文構造に合致しているかどうかを分析する構文ツリーを構築することです.例えば、
a)文字列全体が式の要件を満たしているか
b)文字列が判定文の要求に合致するか
c)文字列が循環文の要求を満たしているか
d)文字列が関数要求に合致するか
e)文字列がinclude構文の要件を満たしているか
f)宣言されていない変数などがあるかどうか.
(3)意味解析
意味分析は文法分析と結びついている場合がある.しかし、ここではそれを単独で一部に分解しました.意味解析とは,前に生成した構文木を分解し,原子文操作を生成する過程である.例えば、上のファイルはこのような形式である可能性が高いです.
SET value
mov temp1[inner], 7
add temp1[inner], 1
mul temp2,value[param], 4
add temp1, temp2
mov result, temp1
pop


SET argc[param]
SET argv[param]
SET 3
call test
pop 
get result
mov p[inner], result
SET p
SET string "p = %d"
pop
pop
mov result, 1
pop
pop
ここでは、意味変換の構造と形式は、実際には各コンパイラが独自に定義しており、必ずしも共通の構造があるとは限らないことを説明する必要があります.ここの文は私自身が思いついただけで、実際の形式とは大きな違いがあるかもしれませんが、基本的な方法は同じはずです.主な解釈は以下の通りです.
a)SET値が関数パラメータ
b)callは関数呼び出し
c)popをスタックバランスに使用
d)現在の変数が関数中の一時変数であることを示すデータ[inner]
e)現在の変数がパラメータであることを示すデータ[param]
f)tempは,コンパイラが自身の計算を容易にするために一時的に追加した局所変数を表す.
g)resultは戻り値を表す
(4)コード最適化
コード最適化はコンパイラ処理の重要な一環であり、コード最適化の目的は主に不要な計算と処理を減らすことである.
a)使用価値のない一時変数の計算
b)判断価値のないif文を除く
c)いくつかのconst変数については、コンパイラが事前に計算し、ここでtemp 1を事前に計算することができる.
d)その他の最適化措置等
(5)アセンブリコードの生成
(3)で生成されるコードは中間コードにすぎず,完全な意味でのアセンブリ言語ではない.したがって、コンパイラはarm言語、x 86言語、powerpc言語など、対応するバイナリコードに翻訳する必要があります.もちろんこの中にはいくつかのテクニックがあります
a)マルチパラメータの関数については,一部のcpuはレジスタで代用でき,一部のcpuはスタックで表す.
b)一部のcpuはバイトの位置合わせを必要とし、一部のcpuは必要としない
c)一部のcpuはバイト順の要求があり、一部のcpuはどうでもいいが、一部のcpuはオプションである
d)一時変数については,レジスタで表すことができるcpuもあれば,temp変数を1つしか生成できないcpuもある.
    
ここまで言うと、私たちも自分でちょっと試して、コードがどのように生成されているかを見て、x 86コードに詳しい学生も自分で試してみることができます.
push ebp
mov ebp, esp
push ebx
push ecx
mov ebx, 8
mov ecx, ebp[8]
mul ecx, 4
add ebx, ecx
mov eax, ebx
pop ecx
pop ebx
mov esp, ebp
pop ebp


push ebp
mov ebp, esp
sub esp, 0x4
push 3
call test
add esp 4
mov ebp[-4], eax
push ebp[-4]
push string "p = %d"
call printf
add esp, 8
mov eax, 1
sub esp, 0x4
mov esp, ebp
pop ebp
     
(6)アセンブラレベルコード最適化
ここの最適化は実際には多いですが、機能は基本的に限られています.
a)乗算からシフトへの移行
b)除算からシフトへの移行
c)レジスタ最適化使用
d)レジスタを削除する繰り返し操作手順
e)一部の関数パラメータをレジスタに置き換えるなど
(7)実行可能ファイルのリンクと生成
コンパイル中、いくつかのコードコンパイルが通過したが、リンクが失敗したことがよく見られます.これは正常なことです.最後に生成されたファイルでは、各変数と関数に出典があるはずです.そうしないとリンクに失敗します.どんなシステムプラットフォームでも、リンクは大学の質問です.この時、やっていることは実は多いです.例えば、
a)実行ファイルを生成し、デバッグ情報があるかどうかを確定する
b)すべての変数とコードをリンクする
c)mapファイルの生成
d)関数と変数の出所を確定し、検索に失敗したら、終了する
e)変数と関数コードの位置を調整し、ファイル構造を記入し、最終実行可能ファイルを生成する