Buku terbaik untuk menjawab pertanyaan Anda mungkin adalah: Cooper dan Torczon, "Engineering a Compiler," 2003. Jika Anda memiliki akses ke perpustakaan universitas, Anda harus dapat meminjam salinannya.
Dalam kompiler produksi seperti llvm atau gcc, para desainer berusaha keras untuk menjaga semua algoritma di bawah ini O ( n2) dimana nadalah ukuran input. Untuk beberapa analisis untuk fase "optimisasi" ini berarti Anda perlu menggunakan heuristik daripada menghasilkan kode yang benar-benar optimal.
Lexer adalah mesin negara yang terbatas, jadi O ( n ) dalam ukuran input (dalam karakter) dan menghasilkan aliran O ( n ) token yang diteruskan ke parser.
Untuk banyak kompiler untuk banyak bahasa parser adalah LALR (1) dan dengan demikian memproses token stream dalam waktu O ( n )dalam jumlah token input. Selama parsing Anda biasanya harus melacak tabel simbol, tetapi, untuk banyak bahasa, itu dapat ditangani dengan tumpukan tabel hash ("kamus"). Setiap akses kamus adalahO ( 1 ), tetapi Anda kadang-kadang harus berjalan di tumpukan untuk mencari simbol. Kedalaman tumpukan adalahO ( s ) dimana sadalah kedalaman ruang lingkup. (Jadi dalam bahasa mirip-C, berapa banyak lapisan kurung kurawal yang ada di dalam Anda.)
Kemudian pohon parse biasanya "diratakan" ke dalam grafik aliran kontrol. Node dari grafik aliran kontrol mungkin berupa instruksi 3-alamat (mirip dengan bahasa rakitan RISC), dan ukuran grafik aliran kontrol biasanya akan linier dalam ukuran pohon parse.
Kemudian serangkaian langkah-langkah eliminasi redundansi biasanya diterapkan (eliminasi subekspresi umum, gerakan kode invarian loop, propagasi konstan, ...). (Ini sering disebut "optimisasi" walaupun jarang ada yang optimal tentang hasilnya, tujuan sebenarnya adalah untuk meningkatkan kode sebanyak mungkin dalam batasan waktu dan ruang yang telah kita tempatkan pada kompiler.) Setiap langkah eliminasi redundansi akan biasanya memerlukan bukti dari beberapa fakta tentang grafik aliran kontrol. Bukti-bukti ini biasanya dilakukan dengan menggunakan analisis aliran data . Sebagian besar analisis aliran data dirancang sehingga akan menyatuO ( d) melewati grafik aliran di mana d adalah (secara kasar) kedalaman sarang loop dan melewati grafik aliran membutuhkan waktu O ( n ) dimana n adalah jumlah instruksi 3-alamat.
Untuk optimasi yang lebih canggih, Anda mungkin ingin melakukan analisis yang lebih canggih. Pada titik ini Anda mulai mengalami pengorbanan. Anda ingin algoritma analisis Anda mengambil kurang dariO ( n2)waktu dalam ukuran diagram alir seluruh program, tetapi ini berarti Anda perlu melakukannya tanpa informasi (dan program meningkatkan transformasi) yang mungkin mahal untuk dibuktikan. Contoh klasik dari hal ini adalah analisis alias, di mana untuk pasangan memori menulis Anda ingin membuktikan bahwa keduanya menulis tidak pernah dapat menargetkan lokasi memori yang sama. (Anda mungkin ingin melakukan analisis alias untuk melihat apakah Anda dapat memindahkan satu instruksi di atas yang lain.) Tetapi untuk mendapatkan informasi yang akurat tentang alias, Anda mungkin perlu menganalisis setiap jalur kontrol yang mungkin melalui program, yang eksponensial dalam jumlah cabang. dalam program (dan dengan demikian eksponensial dalam jumlah node dalam grafik aliran kontrol.)
Selanjutnya Anda masuk ke alokasi register. Alokasi register dapat dirumuskan sebagai masalah pewarnaan grafik, dan pewarnaan grafik dengan jumlah warna minimal dikenal sebagai NP-Hard. Jadi kebanyakan kompiler menggunakan semacam heuristik serakah dikombinasikan dengan tumpahan register dengan tujuan mengurangi jumlah tumpahan register sebaik mungkin dalam batas waktu yang wajar.
Akhirnya Anda masuk ke pembuatan kode. Pembuatan kode biasanya dilakukan maksimal-blok dasar pada saat di mana blok dasar adalah seperangkat node grafik aliran kontrol terhubung linear dengan entri tunggal dan keluar tunggal. Ini dapat dirumuskan ulang sebagai grafik yang mencakup masalah di mana grafik yang Anda coba untuk tutupi adalah grafik ketergantungan dari set instruksi 3-alamat di blok dasar, dan Anda mencoba untuk menutup dengan satu set grafik yang mewakili mesin yang tersedia instruksi. Masalah ini bersifat eksponensial dalam ukuran blok dasar terbesar (yang pada prinsipnya dapat menjadi urutan yang sama dengan ukuran seluruh program), jadi ini lagi biasanya dilakukan dengan heuristik di mana hanya sebagian kecil dari penutup yang mungkin. diperiksa.