Seorang intepreter akan bekerja tentang cara Anda menebak. Dalam model sederhana, ini akan mempertahankan satu kamus dengan nama variabel sebagai kunci kamus dan nilai variabel sebagai nilai kamus. Jika bahasa tahu konsep variabel yang hanya terlihat dalam konteks tertentu, penerjemah akan mempertahankan beberapa kamus untuk mencerminkan konteks yang berbeda. Juru bahasa itu sendiri biasanya merupakan program yang dikompilasi, jadi untuk penyimpanannya, lihat di bawah.
Penyusun
(Ini sangat tergantung pada bahasa dan kompiler dan sangat disederhanakan, jadi itu hanya dimaksudkan untuk memberikan beberapa ide.)
Katakanlah, kita memiliki variabel global int five = 5. Variabel global hanya ada satu kali dalam program, sehingga kompiler cadangan satu area memori 4 byte (ukuran int) di area data. Itu dapat menggunakan alamat tetap, katakanlah 1234. Ke dalam file yang dapat dieksekusi, kompiler menempatkan informasi bahwa empat byte mulai dari 1234 diperlukan sebagai memori data statis, harus diisi dengan angka 5 pada saat program dimulai dan secara opsional (untuk dukungan debugger) info tempat tempat 1234 dipanggil fivedan berisi bilangan bulat. Di mana pun beberapa baris kode lainnya merujuk ke variabel yang bernama five, kompiler ingat bahwa ia ditempatkan pada 1234 dan menyisipkan memori baca atau tulis instruksi untuk alamat 1234.
Jika int six = 6ada variabel lokal dalam suatu fungsi, itu harus ada satu kali untuk setiap panggilan aktif saat ini dari fungsi ini (bisa ada beberapa karena rekursi atau multi-threading). Jadi, setiap pemanggilan fungsi menumpuk ruang yang cukup ke stack untuk menampung variabel-variabelnya (termasuk empat byte untuk sixvariabel kita . Kompilator memutuskan di mana menempatkan sixvariabel dalam bingkai stack ini, mungkin pada 8 byte dari frame start dan mengingat posisi relatif itu. Jadi, instruksi yang dihasilkan oleh kompiler untuk fungsi tersebut adalah:
memajukan penunjuk tumpukan dengan byte yang cukup untuk semua variabel lokal fungsi.
simpan angka 6 (nilai awal six) ke lokasi momory 8 byte di atas penunjuk tumpukan.
dimanapun fungsi merujuk six, kompiler memasukkan instruksi baca atau tulis untuk lokasi momory 8 byte di atas stack pointer.
ketika selesai dengan fungsi, gulung kembali penunjuk tumpukan ke nilai lamanya.
Sekali lagi, itu hanya model yang sangat sederhana, tidak mencakup semua jenis variabel, tapi mungkin itu membantu untuk mendapatkan pemahaman ...
Mudah dimengerti bagi seseorang dari tingkat pengetahuan saya. Terima kasih banyak! Anda benar-benar menjelaskan ini!
baranskistad
Itu menjadi lebih gila ketika kompiler tidak mengkompilasi semua ini menjadi biner monolitik, tetapi unit kompilasi yang lebih kecil (katakanlah, satu per file sumber). Maka semua hal eksternal (seperti global) harus mendapatkan alamatnya diselesaikan kemudian, dengan alat terpisah yang disebut tautan (yang akan menggabungkan semua file "objek" kecil ini menjadi satu biner yang lebih besar).
Kat
Juga, jika seseorang terbiasa dengan versi C yang lebih lama, sifat bagaimana variabel lokal bekerja membuatnya jelas mengapa C dulu mengharuskan semua variabel lokal dideklarasikan di bagian atas fungsi. Kemudian kami memutuskan bahwa itu cukup bisa dilakukan untuk menguraikan seluruh fungsi terlebih dahulu, sehingga Anda akhirnya bisa memiliki deklarasi variabel di mana pun Anda inginkan.
Kat
Akhirnya, mungkin juga relevan bahwa tidak ada yang menghentikan Anda dari menggunakan kamus untuk variabel lokal dengan kompiler. Ini tentu akan membuat pengetikan dinamis jauh lebih mudah (tipe dinamis tidak dapat sepenuhnya disimpan di stack karena mereka tidak memiliki ukuran yang diketahui pada waktu kompilasi). Hanya kamus yang lambat. Kebetulan mengapa sebagian besar bahasa yang dikompilasi menggunakan pengetikan statis.
Kat
10
Tergantung implementasinya.
Sebagai contoh, kompiler C mungkin mempertahankan tabel simbol selama kompilasi. Ini adalah struktur data yang kaya yang memungkinkan mendorong dan meletupnya cakupan, karena setiap brace pembuka pernyataan majemuk {berpotensi memperkenalkan ruang lingkup baru untuk variabel lokal baru. Selain menangani cakupan yang datang dan pergi, ia mencatat variabel yang dideklarasikan, dan untuk masing-masing menyertakan nama dan tipenya.
Struktur data tabel simbol ini juga mendukung pencarian informasi variabel berdasarkan nama, misalnya oleh pengenalnya, dan kompiler melakukan ini ketika ia mengikat informasi variabel yang dideklarasikan ke pengidentifikasi mentah yang dilihatnya di parse, jadi ini cukup awal saat kompilasi.
Pada titik tertentu, kompiler memberikan lokasi ke variabel. Mungkin tugas lokasi dicatat dalam struktur data tabel simbol yang sama. Compiler dapat melakukan penugasan lokasi secara langsung selama parsing, tetapi kemungkinan dapat melakukan pekerjaan yang lebih baik jika menunggu tidak hanya sampai setelah parsing, tetapi setelah optimasi umum.
Pada titik tertentu, untuk variabel lokal, kompiler menetapkan lokasi stack atau register CPU (bisa jadi lebih kompleks karena variabel sebenarnya dapat memiliki beberapa lokasi, seperti lokasi stack untuk beberapa bagian dari kode yang dihasilkan dan CPU daftar untuk bagian lain).
Akhirnya, kompiler menghasilkan kode aktual: instruksi mesin yang mereferensikan nilai-nilai variabel secara langsung oleh register CPU mereka atau lokasi stack yang ditentukan, sebagaimana diperlukan untuk mengeksekusi kode yang sedang dikompilasi. Setiap baris kode sumber mengkompilasi serangkaian instruksi kode mesinnya sendiri, sehingga instruksi yang dihasilkan tidak hanya mengkode operasi (menambah, mengurangi) tetapi juga lokasi variabel yang dirujuk.
Kode objek akhir yang keluar dari kompiler tidak lagi memiliki nama dan tipe variabel; hanya ada lokasi, lokasi tumpukan atau register CPU. Lebih lanjut tidak ada tabel lokasi, melainkan lokasi ini digunakan oleh setiap instruksi mesin mengetahui lokasi di mana nilai variabel disimpan. Tanpa melihat pengidentifikasi dalam kode runtime, setiap bit kode yang dihasilkan hanya mengetahui operasi yang harus dilakukan dan lokasi yang akan digunakan.
Ketika debugging diaktifkan selama kompilasi, kompiler akan menampilkan bentuk tabel simbol sehingga, misalnya, debuggers akan mengetahui nama-nama variabel di berbagai lokasi stack.
Beberapa bahasa lain memiliki kebutuhan untuk mencari pengidentifikasi secara dinamis saat runtime, jadi mungkin juga menyediakan beberapa bentuk tabel simbol untuk mendukung kebutuhan tersebut.
Penerjemah memiliki beragam pilihan. Mereka mungkin mempertahankan struktur data seperti tabel simbol untuk digunakan selama eksekusi (selain digunakan selama parsing), meskipun alih-alih menugaskan / melacak lokasi stack, cukup simpan nilai untuk variabel, yang terkait dengan entri variabel dalam tabel simbol struktur data.
Tabel simbol mungkin disimpan di heap daripada di stack (meskipun menggunakan stack untuk cakupan dan variabel tentu saja mungkin, dan lebih lanjut mungkin meniru stack di heap untuk mendapatkan keuntungan dari cache dengan mengemas nilai variabel dekat masing-masing). lain), jadi penerjemah mungkin menggunakan memori tumpukan untuk menyimpan nilai-nilai variabel sedangkan kompiler menggunakan lokasi tumpukan. Secara umum, juru bahasa juga tidak memiliki kebebasan untuk menggunakan register CPU sebagai penyimpanan untuk nilai-nilai variabel karena register CPU sebaliknya sibuk menjalankan garis-garis kode interpreter itu sendiri ...
Cara terbaik untuk memahami apa kode Anda sedang dikompilasi ke dalam adalah untuk mengkompilasi kode Anda untuk perakitan . Kode perakitan paling dekat dengan instruksi prosesor yang sedang dijalankan.
Tergantung implementasinya.
Sebagai contoh, kompiler C mungkin mempertahankan tabel simbol selama kompilasi. Ini adalah struktur data yang kaya yang memungkinkan mendorong dan meletupnya cakupan, karena setiap brace pembuka pernyataan majemuk
{
berpotensi memperkenalkan ruang lingkup baru untuk variabel lokal baru. Selain menangani cakupan yang datang dan pergi, ia mencatat variabel yang dideklarasikan, dan untuk masing-masing menyertakan nama dan tipenya.Struktur data tabel simbol ini juga mendukung pencarian informasi variabel berdasarkan nama, misalnya oleh pengenalnya, dan kompiler melakukan ini ketika ia mengikat informasi variabel yang dideklarasikan ke pengidentifikasi mentah yang dilihatnya di parse, jadi ini cukup awal saat kompilasi.
Pada titik tertentu, kompiler memberikan lokasi ke variabel. Mungkin tugas lokasi dicatat dalam struktur data tabel simbol yang sama. Compiler dapat melakukan penugasan lokasi secara langsung selama parsing, tetapi kemungkinan dapat melakukan pekerjaan yang lebih baik jika menunggu tidak hanya sampai setelah parsing, tetapi setelah optimasi umum.
Pada titik tertentu, untuk variabel lokal, kompiler menetapkan lokasi stack atau register CPU (bisa jadi lebih kompleks karena variabel sebenarnya dapat memiliki beberapa lokasi, seperti lokasi stack untuk beberapa bagian dari kode yang dihasilkan dan CPU daftar untuk bagian lain).
Akhirnya, kompiler menghasilkan kode aktual: instruksi mesin yang mereferensikan nilai-nilai variabel secara langsung oleh register CPU mereka atau lokasi stack yang ditentukan, sebagaimana diperlukan untuk mengeksekusi kode yang sedang dikompilasi. Setiap baris kode sumber mengkompilasi serangkaian instruksi kode mesinnya sendiri, sehingga instruksi yang dihasilkan tidak hanya mengkode operasi (menambah, mengurangi) tetapi juga lokasi variabel yang dirujuk.
Kode objek akhir yang keluar dari kompiler tidak lagi memiliki nama dan tipe variabel; hanya ada lokasi, lokasi tumpukan atau register CPU. Lebih lanjut tidak ada tabel lokasi, melainkan lokasi ini digunakan oleh setiap instruksi mesin mengetahui lokasi di mana nilai variabel disimpan. Tanpa melihat pengidentifikasi dalam kode runtime, setiap bit kode yang dihasilkan hanya mengetahui operasi yang harus dilakukan dan lokasi yang akan digunakan.
Ketika debugging diaktifkan selama kompilasi, kompiler akan menampilkan bentuk tabel simbol sehingga, misalnya, debuggers akan mengetahui nama-nama variabel di berbagai lokasi stack.
Beberapa bahasa lain memiliki kebutuhan untuk mencari pengidentifikasi secara dinamis saat runtime, jadi mungkin juga menyediakan beberapa bentuk tabel simbol untuk mendukung kebutuhan tersebut.
Penerjemah memiliki beragam pilihan. Mereka mungkin mempertahankan struktur data seperti tabel simbol untuk digunakan selama eksekusi (selain digunakan selama parsing), meskipun alih-alih menugaskan / melacak lokasi stack, cukup simpan nilai untuk variabel, yang terkait dengan entri variabel dalam tabel simbol struktur data.
Tabel simbol mungkin disimpan di heap daripada di stack (meskipun menggunakan stack untuk cakupan dan variabel tentu saja mungkin, dan lebih lanjut mungkin meniru stack di heap untuk mendapatkan keuntungan dari cache dengan mengemas nilai variabel dekat masing-masing). lain), jadi penerjemah mungkin menggunakan memori tumpukan untuk menyimpan nilai-nilai variabel sedangkan kompiler menggunakan lokasi tumpukan. Secara umum, juru bahasa juga tidak memiliki kebebasan untuk menggunakan register CPU sebagai penyimpanan untuk nilai-nilai variabel karena register CPU sebaliknya sibuk menjalankan garis-garis kode interpreter itu sendiri ...
sumber
Cara terbaik untuk memahami apa kode Anda sedang dikompilasi ke dalam adalah untuk mengkompilasi kode Anda untuk perakitan . Kode perakitan paling dekat dengan instruksi prosesor yang sedang dijalankan.
sumber