Apa itu penerjemah. Bahasa pemrograman. compiler dan interpreter. Algoritma penerjemah sederhana

Pelaksana konkret bahasa pemrograman adalah penerjemah dan juru bahasa.

Penerjemah adalah program yang dengannya komputer mengubah program yang dimasukkan ke dalamnya menjadi bahasa mesin, karena program tersebut dapat mengeksekusi program yang ditulis hanya dalam bahasa prosesornya, dan algoritme yang ditentukan dalam bahasa lain harus diterjemahkan ke dalam bahasa mesin sebelum dieksekusi .

Penerjemah- program atau sarana teknis yang melakukan siaran program.

Siaran program- transformasi program yang disajikan dalam salah satu bahasa pemrograman menjadi program dalam bahasa lain, setara dengan hasil yang pertama. Penerjemah biasanya juga melakukan diagnosa kesalahan, membuat kamus pengidentifikasi, mencetak teks program, dll.

Bahasa di mana program input disajikan disebut asli bahasa, dan program itu sendiri - kode sumber. Bahasa output disebut bahasa target atau objektif kode. Tujuan penerjemahan adalah untuk mengubah teks dari satu bahasa ke bahasa lain yang dapat dimengerti oleh penerima teks. Dalam hal program penerjemah, tujuannya adalah perangkat teknis(prosesor) atau program juru bahasa.

Penerjemah diimplementasikan sebagai kompiler atau juru bahasa. Dalam hal melakukan pekerjaan, kompiler dan juru bahasa sangat berbeda.

Bahasa prosesor (kode mesin) adalah level rendah. Penerjemah yang mengubah program menjadi bahasa mesin yang diterima dan dieksekusi langsung oleh prosesor disebut penyusun.

Penyusun(Bahasa inggris) penyusun- compiler, collector) membaca keseluruhan program, menerjemahkannya dan membuat versi lengkap dari program dalam bahasa mesin, yang kemudian dijalankan. Output dari kompiler adalah file yang dapat dieksekusi biner.

Keunggulan kompiler: program dikompilasi sekali dan tidak diperlukan transformasi tambahan untuk setiap eksekusi. Oleh karena itu, kompiler tidak diperlukan pada mesin target yang programnya sedang dikompilasi. Kerugian: Langkah kompilasi terpisah memperlambat penulisan dan debugging dan menyulitkan untuk menjalankan program kecil, sederhana, atau sekali pakai.

Jika bahasa sumbernya adalah bahasa rakitan (bahasa tingkat rendah yang mirip dengan bahasa mesin), maka penyusun bahasa tersebut disebut assembler.

Metode implementasi lainnya adalah ketika program dijalankan dengan penerjemah tidak ada terjemahan sama sekali.

Penerjemah(Bahasa inggris) penerjemah- interpreter, interpreter) menerjemahkan dan mengeksekusi program baris demi baris.

Penerjemah secara terprogram mensimulasikan mesin yang pengulangan pengambilan-eksekusinya beroperasi berdasarkan instruksi dalam bahasa tingkat tinggi daripada instruksi mesin. Pemodelan perangkat lunak semacam itu menciptakan mesin virtual yang mengimplementasikan bahasa. Pendekatan ini disebut interpretasi murni. Interpretasi murni biasanya digunakan untuk bahasa dengan struktur sederhana (misalnya APL atau Lisp). Penerjemah garis komando memproses perintah dalam skrip di UNIX atau dalam file batch (.bat) di MS-DOS, biasanya juga dalam mode interpretasi murni.

Keuntungan dari juru bahasa murni: tidak adanya tindakan perantara untuk terjemahan menyederhanakan penerapan juru bahasa dan membuatnya lebih nyaman untuk digunakan, termasuk dalam mode interaktif. Kerugiannya adalah interpreter harus tersedia di mesin target tempat program akan dieksekusi. Juga, sebagai aturan, ada penurunan kecepatan yang kurang lebih signifikan. Dan properti dari juru bahasa murni, bahwa kesalahan dalam program yang ditafsirkan terdeteksi hanya ketika upaya dilakukan untuk mengeksekusi perintah (atau baris) dengan kesalahan, dapat dikenali sebagai kerugian dan keuntungan.

Ada kompromi antara kompilasi dan interpretasi murni dari implementasi bahasa pemrograman, ketika juru bahasa, sebelum menjalankan program, menerjemahkannya ke dalam bahasa perantara (misalnya, ke bytecode atau p-code), yang lebih nyaman untuk interpretasi (yaitu, kita berbicara tentang juru bahasa dengan penerjemah bawaan) . Metode seperti itu disebut implementasi campuran. Perl adalah contoh penerapan bahasa campuran. Pendekatan ini menggabungkan keuntungan kompiler dan juru bahasa (kecepatan eksekusi yang lebih tinggi dan kemudahan penggunaan) dan kerugian (sumber daya tambahan diperlukan untuk menerjemahkan dan menyimpan program dalam bahasa perantara; juru bahasa harus disediakan untuk menjalankan program di mesin sasaran). Sama seperti dalam kasus kompiler, implementasi campuran membutuhkannya sebelum dieksekusi sumber tidak mengandung kesalahan (leksikal, sintaksis dan semantik).

Dengan peningkatan sumber daya komputer dan perluasan jaringan heterogen (termasuk Internet) yang menghubungkan komputer dari berbagai jenis dan arsitektur, jenis interpretasi baru telah muncul, di mana kode sumber (atau perantara) dikompilasi ke dalam kode mesin secara langsung saat runtime , "dengan cepat". Bagian kode yang sudah dikompilasi di-cache sehingga ketika diakses kembali, mereka segera menerima kontrol, tanpa kompilasi ulang. Pendekatan ini disebut kompilasi dinamis.

Keuntungan dari kompilasi dinamis adalah kecepatan interpretasi program menjadi sebanding dengan kecepatan eksekusi program dalam bahasa yang dikompilasi konvensional, sementara program itu sendiri disimpan dan didistribusikan dalam satu bentuk, terlepas dari platform target. Kerugiannya adalah kompleksitas implementasi yang lebih besar dan kebutuhan sumber daya yang lebih besar daripada kompiler sederhana atau juru bahasa murni.

Metode ini sangat cocok untuk aplikasi web. Dengan demikian, kompilasi dinamis muncul dan didukung sampai batas tertentu dalam implementasi Java, . .NET Framework, Perl, Phyton.

Setelah program dikompilasi, baik kode sumber untuk program maupun kompiler tidak diperlukan untuk menjalankan program. Pada saat yang sama, program yang diproses oleh interpreter harus diterjemahkan ulang ke dalam bahasa mesin setiap kali program dijalankan. Artinya, file sumber dapat dieksekusi secara langsung.

Program yang dikompilasi berjalan lebih cepat, tetapi program yang ditafsirkan lebih mudah untuk diperbaiki dan diubah.

Setiap bahasa tertentu difokuskan pada kompilasi atau interpretasi, tergantung pada tujuan pembuatannya. Sebagai contoh, C++ biasanya digunakan untuk memecahkan masalah yang agak kompleks dimana kecepatan program penting, sehingga bahasa ini diimplementasikan menggunakan kompiler.

Untuk mencapai kecepatan program yang lebih tinggi dalam bahasa pemrograman yang ditafsirkan, terjemahan ke bytecode perantara dapat digunakan. Bahasa yang memungkinkan trik ini adalah Java, Python dan beberapa bahasa pemrograman lainnya.

Algoritma juru bahasa sederhana:

2. menganalisis instruksi dan menentukan tindakan yang tepat;

3. mengambil tindakan yang tepat;

4. jika kondisi penghentian program tidak tercapai, baca instruksi selanjutnya dan lanjutkan ke langkah 2

Bahasa pemrograman dapat dibagi menjadi dikompilasi dan ditafsirkan.

Suatu program dalam bahasa yang dikompilasi diubah (dikompilasi) menjadi sekumpulan instruksi untuk dari jenis ini prosesor (kode mesin) dan kemudian ditulis ke dalam modul yang dapat dieksekusi, yang dapat diluncurkan untuk dieksekusi sebagai program terpisah. Dengan kata lain, kompiler menerjemahkan kode sumber program dari bahasa pemrograman tingkat tinggi menjadi kode biner dari instruksi prosesor.

Jika program ditulis dalam bahasa yang ditafsirkan, maka juru bahasa langsung mengeksekusi (menafsirkan) teks sumber tanpa terjemahan sebelumnya. Program tetap dalam bahasa aslinya dan tidak dapat dijalankan tanpa penerjemah. Dapat dikatakan bahwa prosesor komputer adalah penafsir kode mesin.

Singkatnya, kompiler menerjemahkan kode sumber program ke dalam bahasa mesin segera dan seluruhnya, membuat program yang dapat dieksekusi terpisah, dan juru bahasa mengeksekusi kode sumber tepat selama eksekusi program.

Pembagian ke dalam bahasa yang dikompilasi dan ditafsirkan agak sewenang-wenang. Jadi, untuk bahasa yang dikompilasi secara tradisional, seperti Pascal, Anda dapat menulis juru bahasa. Selain itu, sebagian besar penafsir "murni" modern tidak mengeksekusi konstruksi bahasa secara langsung, tetapi mengompilasinya menjadi beberapa representasi perantara tingkat tinggi (misalnya, dengan dereferensi variabel dan perluasan makro).

Untuk bahasa apa pun yang ditafsirkan, Anda dapat membuat kompiler - misalnya, bahasa Lisp, yang awalnya ditafsirkan, dapat dikompilasi tanpa batasan apa pun. Kode yang dihasilkan saat runtime juga dapat dikompilasi secara dinamis saat runtime.

Sebagai aturan, program yang dikompilasi berjalan lebih cepat dan tidak perlu program tambahan, karena sudah diterjemahkan ke dalam bahasa mesin. Pada saat yang sama, dengan setiap perubahan teks program, diperlukan kompilasi ulang, yang menimbulkan kesulitan dalam pengembangan. Selain itu, program yang dikompilasi hanya dapat dijalankan pada jenis komputer yang sama, dan biasanya di bawah sistem operasi yang sama, yang dirancang untuk kompiler tersebut. Untuk membuat executable untuk jenis mesin yang berbeda, diperlukan kompilasi baru.

Bahasa yang diterjemahkan memiliki beberapa fitur tambahan khusus (lihat di atas), selain itu, program di dalamnya dapat dijalankan segera setelah modifikasi, yang membuat pengembangan menjadi lebih mudah. Program bahasa yang ditafsirkan sering dapat dijalankan pada berbagai jenis mesin dan sistem operasi tanpa usaha tambahan.

Namun, program yang ditafsirkan berjalan lebih lambat daripada program yang dikompilasi, dan tidak dapat berjalan tanpa program juru bahasa tambahan.

Beberapa bahasa, seperti Java dan C#, berada di antara kompilasi dan interpretasi. Yaitu, program tidak dikompilasi ke dalam bahasa mesin, tetapi menjadi kode independen mesin tingkat rendah, bytecode. Selanjutnya, bytecode dijalankan mesin virtual. Untuk mengeksekusi bytecode biasanya digunakan interpretasi, meskipun beberapa bagiannya dapat diterjemahkan ke dalam kode mesin secara langsung selama eksekusi program menggunakan kompilasi Just-in-time (JIT) untuk mempercepat program. Untuk Java, bytecode dijalankan oleh virtual mesin Jawa(Java Virtual Machine, JVM), untuk C# - Common Language Runtime.

Pendekatan ini, dalam arti tertentu, memungkinkan Anda untuk menggunakan keuntungan dari penafsir dan kompiler. Sebutkan juga harus dibuat dari bahasa Forth asli, yang memiliki juru bahasa dan kompiler.

Karena teks yang ditulis dalam bahasa pemrograman tidak dapat dipahami oleh komputer, teks tersebut harus diterjemahkan ke dalam kode mesin. Terjemahan program seperti itu dari bahasa pemrograman ke bahasa kode mesin disebut terjemahan, dan dilakukan oleh program khusus - penerjemah.

Penerjemah - program utilitas yang mengubah program sumber yang disediakan dalam bahasa pemrograman input menjadi program kerja disajikan dalam bahasa objek.

Saat ini, kompiler dibagi menjadi tiga kelompok utama: assembler, kompiler, dan juru bahasa.

Assembler adalah utilitas sistem yang mengubah konstruksi simbolik menjadi instruksi bahasa mesin. Fitur khusus assembler adalah bahwa mereka secara harfiah menerjemahkan satu instruksi simbolik menjadi satu instruksi mesin. Dengan demikian, bahasa rakitan (juga disebut autocode) dirancang untuk memfasilitasi persepsi set instruksi komputer dan mempercepat pemrograman dalam set instruksi ini. Jauh lebih mudah bagi seorang programmer untuk mengingat penunjukan mnemonik dari instruksi mesin daripada kode binernya.

Pada saat yang sama, bahasa rakitan, selain analog dari instruksi mesin, berisi banyak arahan tambahan yang memfasilitasi, khususnya, pengelolaan sumber daya komputer, penulisan fragmen berulang, dan pembuatan program multimodul. Oleh karena itu, ekspresi bahasa jauh lebih kaya dari sekedar bahasa pengkodean simbolik, yang sangat meningkatkan efisiensi pemrograman.

Kompiler adalah program utilitas yang menerjemahkan ke dalam bahasa mesin program yang ditulis dalam bahasa pemrograman sumber. Sama seperti assembler, kompiler mengubah program dari satu bahasa ke bahasa lain (paling sering, ke bahasa komputer tertentu). Namun, perintah bahasa sumber berbeda secara signifikan dalam organisasi dan kekuatan dari perintah bahasa mesin. Ada bahasa di mana satu instruksi bahasa sumber diterjemahkan ke dalam 7-10 instruksi mesin. Namun, ada juga bahasa di mana setiap instruksi dapat sesuai dengan 100 atau lebih instruksi mesin (misalnya, Prolog). Selain itu, dalam bahasa sumber sering digunakan pengetikan data yang ketat, yang dilakukan melalui deskripsi pendahuluannya. Pemrograman mungkin tidak bergantung pada pengkodean suatu algoritme, tetapi pada pemikiran yang cermat tentang struktur atau kelas data. Proses menerjemahkan dari bahasa semacam itu biasa disebut kompilasi, dan bahasa sumber biasanya disebut sebagai bahasa pemrograman tingkat tinggi (atau bahasa tingkat tinggi). Abstraksi bahasa pemrograman dari sistem perintah komputer menyebabkan terciptanya berbagai macam bahasa secara independen yang berfokus pada penyelesaian masalah tertentu. Bahasa muncul untuk perhitungan ilmiah, perhitungan ekonomi, akses ke database, dan lain-lain.

Penerjemah adalah program atau perangkat yang melakukan terjemahan operator demi operator dan eksekusi program sumber. Tidak seperti compiler, interpreter tidak menghasilkan program bahasa mesin sebagai keluaran. Setelah mengenali perintah bahasa sumber, ia segera menjalankannya. Baik kompiler dan juru bahasa menggunakan metode yang sama untuk mem-parsing kode sumber suatu program. Tetapi juru bahasa memungkinkan Anda untuk mulai memproses data setelah menulis bahkan satu perintah. Ini membuat proses pengembangan dan debugging program menjadi lebih fleksibel. Selain itu, kurangnya kode mesin keluaran memungkinkan Anda untuk tidak "membuang sampah sembarangan" perangkat eksternal file tambahan, dan interpreter itu sendiri dapat dengan mudah disesuaikan dengan arsitektur mesin apa pun dengan mengembangkannya hanya sekali dalam bahasa pemrograman yang digunakan secara luas. Oleh karena itu, bahasa yang ditafsirkan seperti Java Script, VB Script menjadi tersebar luas. Kerugian dari juru bahasa adalah rendahnya kecepatan eksekusi program. Biasanya, program yang ditafsirkan berjalan 50 hingga 100 kali lebih lambat daripada program yang ditulis dalam kode mesin.

Emulator adalah program atau alat perangkat lunak dan perangkat keras yang memberikan kemampuan untuk menjalankan program pada komputer tertentu tanpa pemrograman ulang, menggunakan kode atau metode untuk melakukan operasi yang berbeda dari komputer ini. Emulator mirip dengan juru bahasa karena secara langsung mengeksekusi program yang ditulis dalam beberapa bahasa. Namun, paling sering itu adalah bahasa mesin atau kode perantara. Keduanya mewakili instruksi dalam kode biner yang dapat segera dieksekusi setelah mengenali opcode. Tidak seperti program teks, tidak diperlukan untuk mengenali struktur program, untuk memilih operan.

Emulator cukup sering digunakan untuk berbagai keperluan. Misalnya, saat mengembangkan sistem komputasi baru, pertama kali dibuat emulator yang menjalankan program yang sedang dikembangkan untuk komputer yang belum ada. Ini memungkinkan Anda untuk mengevaluasi sistem perintah dan mengembangkan dasar perangkat lunak bahkan sebelum peralatan yang sesuai dibuat.

Sangat sering emulator digunakan untuk menjalankan program lama di komputer baru. Biasanya, komputer yang lebih baru lebih cepat dan memiliki periferal yang lebih baik. Ini memungkinkan Anda meniru program lama dengan lebih efisien daripada menjalankannya di komputer lama.

Transcoder - program atau perangkat perangkat lunak yang menerjemahkan program yang ditulis dalam bahasa mesin satu komputer ke dalam program dalam bahasa mesin komputer lain. Jika emulator adalah analog penafsir yang kurang cerdas, maka transcoder bertindak dalam kapasitas yang sama terkait dengan kompiler. Demikian pula, kode mesin sumber (dan biasanya biner) atau representasi perantara diubah menjadi kode serupa lainnya dalam satu instruksi dan tanpa analisis umum struktur program sumber. Transcoder berguna saat mem-porting program dari satu arsitektur komputer ke arsitektur lainnya. Mereka juga dapat digunakan untuk merekonstruksi teks program bahasa tingkat tinggi dari kode biner yang tersedia.

Makroprosesor adalah program yang menggantikan satu urutan karakter dengan yang lain. Ini semacam kompiler. Ini menghasilkan teks keluaran dengan memproses sisipan khusus yang terletak di teks sumber. Sisipan ini dibuat dengan cara khusus dan termasuk dalam konstruksi bahasa, yang disebut bahasa makro. Makroprosesor sering digunakan sebagai add-on untuk bahasa pemrograman, meningkatkan fungsionalitas sistem pemrograman. Hampir semua assembler berisi makroprosesor, yang meningkatkan efisiensi pengembangan program mesin. Sistem pemrograman seperti itu biasanya disebut sebagai perakit makro.

Makroprosesor juga digunakan dengan bahasa tingkat tinggi. Mereka meningkatkan fungsionalitas bahasa seperti PL/1, C, C++. Makroprosesor banyak digunakan di C dan C++, membuatnya lebih mudah untuk menulis program. Makroprosesor meningkatkan efisiensi pemrograman tanpa mengubah sintaks dan semantik bahasa.

Sintaks - seperangkat aturan bahasa tertentu yang menentukan pembentukan elemen-elemennya. Dengan kata lain, itu adalah seperangkat aturan untuk pembentukan urutan karakter yang bermakna secara semantik dalam bahasa tertentu. Sintaks ditentukan menggunakan aturan yang menjelaskan konsep bahasa tertentu. Contoh konsep adalah: variabel, ekspresi, operator, prosedur. Urutan konsep dan penggunaannya yang diizinkan dalam aturan ditentukan secara sintaksis struktur yang benar, membentuk program. Ini adalah hierarki objek, bukan bagaimana mereka berinteraksi satu sama lain, yang ditentukan melalui sintaks. Sebagai contoh, sebuah operator dapat muncul hanya dalam sebuah prosedur, sedangkan sebuah ekspresi dalam sebuah operator, sebuah variabel dapat terdiri dari sebuah nama dan indeks opsional, dan seterusnya. Sintaks tidak terkait dengan fenomena dalam program seperti "melompat ke label yang tidak ada" atau "variabel dengan nama yang diberikan tidak ditentukan". Inilah yang dilakukan semantik.

Semantik - aturan dan kondisi yang menentukan hubungan antara unsur-unsur bahasa dan makna semantiknya, serta interpretasi makna makna dari konstruksi sintaksis bahasa tersebut. Objek bahasa pemrograman tidak hanya ditempatkan dalam teks sesuai dengan hierarki tertentu, tetapi juga saling berhubungan melalui konsep lain yang membentuk berbagai asosiasi. Misalnya, variabel yang sintaksnya menentukan lokasi yang valid hanya dalam deklarasi dan beberapa pernyataan, memiliki tipe tertentu, dapat digunakan dengan rangkaian operasi terbatas, memiliki alamat, ukuran, dan harus dideklarasikan sebelum digunakan di sebuah program.

Parser adalah komponen penyusun yang memeriksa pernyataan sumber untuk kepatuhan dengan aturan sintaksis dan semantik dari bahasa pemrograman tertentu. Terlepas dari namanya, penganalisis memeriksa sintaks dan semantik. Ini terdiri dari beberapa blok, yang masing-masing memecahkan masalahnya sendiri. Ini akan dipertimbangkan lebih detail saat menjelaskan struktur penerjemah. bahasa pemograman kompiler penerjemah

Setiap penerjemah melakukan tugas utama berikut:

  • - menganalisis program siaran, khususnya, menentukan apakah mengandung kesalahan sintaksis;
  • - menghasilkan program keluaran (sering disebut program objek) dalam bahasa instruksi mesin;
  • - mengalokasikan memori untuk program objek.1.1 Interpreter

Salah satu keuntungan yang sering dikutip dari implementasi juru bahasa adalah memungkinkan "mode langsung". Mode langsung memungkinkan Anda menanyakan komputer tugas seperti PRINT 3.14159*3/2.1 dan mengembalikan jawabannya kepada Anda segera setelah Anda menekan ENTER (ini memungkinkan Anda menggunakan komputer seharga $3.000 sebagai kalkulator $10). Selain itu, juru bahasa memiliki atribut khusus yang mempermudah proses debug. Anda dapat, misalnya, menginterupsi pemrosesan program juru bahasa, menampilkan konten variabel tertentu, menelusuri program, lalu melanjutkan eksekusi.

Apa yang paling disukai programmer tentang juru bahasa adalah kemampuan untuk mendapatkan respons yang cepat. Tidak perlu kompilasi di sini, karena juru bahasa selalu siap mengintervensi program Anda. Masukkan RUN dan hasilnya adalah milik Anda sendiri perubahan terakhir muncul di layar.

Namun, bahasa juru bahasa memiliki kekurangan. Misalnya, perlu memiliki salinan juru bahasa di memori setiap saat, sementara banyak fitur juru bahasa, dan karenanya fitur-fiturnya, mungkin tidak diperlukan untuk menjalankan program tertentu.

Kerugian halus dari juru bahasa adalah bahwa mereka cenderung mencegah gaya pemrograman yang baik. Karena komentar dan detail lain yang dapat diformalkan menghabiskan banyak memori program, orang cenderung tidak menggunakannya. Iblis tidak semarah pemrogram penerjemah BASIC yang mencoba memasukkan program 120K ke dalam memori 60K. tetapi yang terburuk, penerjemah bergerak lambat.

Mereka menghabiskan terlalu banyak waktu untuk mencari tahu apa yang harus dilakukan daripada melakukan hal yang sebenarnya. Ketika mengeksekusi pernyataan program, interpreter pertama-tama harus memindai setiap pernyataan untuk membaca isinya (apa yang orang ini minta saya lakukan?) dan kemudian melakukan operasi yang diminta. Pernyataan dalam loop terlalu banyak dipindai.

Pertimbangkan programnya: pada penerjemah BASIC 10 FOR N=1 TO 1000 20 PRINT N,SQR(N) 30 NEXT N pada transisi pertama melalui program ini, Penerjemah BASIC harus menebak arti baris 20:

  • 1. konversikan variabel numerik N ke string
  • 2. kirim string ke layar
  • 3. pindah ke area cetak berikutnya
  • 4. hitung akar pangkat dua dari N
  • 5. ubah hasil menjadi string
  • 6. kirim string ke layar

Pada putaran kedua dari loop, semua tebakan ini diulangi lagi, karena semua hasil mempelajari string ini beberapa milidetik yang lalu benar-benar dilupakan. Dan di semua 998 lintasan berikutnya. Jelas, jika Anda entah bagaimana dapat memisahkan fase pemindaian/pemahaman dari fase eksekusi, Anda akan memiliki lebih banyak program cepat. Dan itulah gunanya kompiler.


4. Prinsip dasar membangun penerjemah. Penerjemah, penyusun, dan juru bahasa - skema kerja umum. Kompiler dan juru bahasa modern.

Prinsip dasar membangun penerjemah.

Penerjemah, penyusun, juru bahasa - skema kerja umum.

Definisi penerjemah, kompiler, juru bahasa

Untuk memulainya, mari kita berikan beberapa definisi - apa yang telah disebutkan oleh penerjemah dan penyusun berkali-kali.

Definisi formal dari penerjemah

Penerjemah adalah program yang menerjemahkan program input dalam bahasa sumber (input) menjadi program output yang setara dalam bahasa hasil (output). Dalam definisi ini, kata "program" muncul tiga kali, dan ini bukan kesalahan atau tautologi. Memang, tiga program selalu berpartisipasi dalam pekerjaan penerjemah.

Pertama, penerjemah itu sendiri adalah program 1 - biasanya disertakan dalam perangkat lunak sistem sistem komputer. Artinya, penerjemah adalah bagian dari perangkat lunak (perangkat lunak), itu adalah sekumpulan instruksi dan data mesin dan dijalankan oleh komputer, seperti semua program lain dalam sistem operasi (OS). Semua komponen penerjemah adalah fragmen atau modul program dengan data masukan dan keluarannya sendiri.

Kedua, data awal untuk pekerjaan penerjemah adalah teks dari program input - beberapa urutan kalimat dari bahasa pemrograman input. Ini biasanya berupa file karakter, tetapi file ini harus berisi teks program yang memenuhi persyaratan sintaksis dan semantik dari bahasa masukan. Selain itu, file ini memiliki arti tertentu, ditentukan oleh semantik bahasa input.

Ketiga, output dari penerjemah adalah teks dari program yang dihasilkan. Program yang dihasilkan dibangun sesuai dengan aturan sintaksis yang ditentukan dalam bahasa keluaran penerjemah, dan maknanya ditentukan oleh semantik bahasa keluaran. Persyaratan penting dalam definisi penerjemah adalah kesetaraan input dan output program. Kesetaraan dua program berarti kebetulan artinya dalam hal semantik bahasa masukan (untuk program sumber) dan semantik bahasa keluaran (untuk program yang dihasilkan). Tanpa memenuhi persyaratan ini, penerjemah itu sendiri kehilangan semua arti praktisnya.

Jadi, untuk membuat penerjemah, Anda harus memilih bahasa input dan output terlebih dahulu. Dari sudut pandang mengubah kalimat dalam bahasa input menjadi kalimat yang setara dalam bahasa output, penerjemah bertindak sebagai penerjemah. Misalnya, menerjemahkan program dari C ke bahasa rakitan pada dasarnya tidak berbeda dengan menerjemahkan, katakanlah, dari bahasa Rusia ke bahasa Inggris, dengan satu-satunya perbedaan adalah kompleksitas bahasa agak berbeda (mengapa tidak ada penerjemah dari bahasa alami ​​- lihat bagian "Klasifikasi bahasa dan tata bahasa, bab 9). Oleh karena itu, kata "penerjemah" sendiri (bahasa Inggris: translator) berarti "penerjemah".

Hasil pekerjaan penerjemah akan menjadi program yang dihasilkan, tetapi hanya jika teks dari program sumber benar - tidak mengandung kesalahan dalam hal sintaks dan semantik bahasa masukan. Jika program sumber salah (mengandung setidaknya satu kesalahan), maka hasil pekerjaan penerjemah akan berupa pesan kesalahan (sebagai aturan, dengan penjelasan tambahan dan indikasi lokasi kesalahan di program sumber). Dalam pengertian ini, penerjemah mirip dengan penerjemah, misalnya dari bahasa Inggris, yang salah menyelipkan teks.

Secara teoritis, dimungkinkan untuk mengimplementasikan penerjemah menggunakan perangkat keras. Penulis telah bertemu dengan perkembangan seperti itu, tetapi aplikasi praktisnya yang luas tidak diketahui. Dalam hal ini, semua komponen penerjemah dapat diimplementasikan dalam bentuk perangkat keras dan fragmennya - kemudian rangkaian pengenal dapat memperoleh implementasi yang sepenuhnya praktis!

definisi penyusun.

Perbedaan antara kompiler dan penerjemah

Selain konsep "penerjemah", konsep "penyusun" yang dekat artinya juga banyak digunakan.

Penyusun - adalah penerjemah yang menerjemahkan program sumber ke program objek yang setara dalam bahasa mesin atau bahasa rakitan.

Jadi, kompiler berbeda dari penerjemah hanya karena program yang dihasilkan harus selalu ditulis dalam kode mesin atau bahasa rakitan. Program penerjemah yang dihasilkan, secara umum, dapat ditulis dalam bahasa apa pun - dimungkinkan, misalnya, untuk menerjemahkan program dari Pascal ke C. Dengan demikian, setiap kompiler adalah penerjemah, tetapi tidak sebaliknya - tidak setiap penerjemah akan menjadi kompiler . Misalnya, penerjemah dari Pascal ke C yang disebutkan di atas tidak akan menjadi 1 .

Kata "penyusun" sendiri berasal dari istilah bahasa Inggris"kompiler" ("kompiler", "penghubung"). Rupanya, istilah tersebut berasal dari kemampuan kompiler untuk membuat program objek berdasarkan program sumber.

Program kompiler yang dihasilkan disebut "program objek" atau "kode objek". File yang ditulis biasanya disebut "file objek". Bahkan ketika program yang dihasilkan dihasilkan dalam bahasa mesin, ada perbedaan yang signifikan antara program objek (file objek) dan program yang dapat dieksekusi (file yang dapat dieksekusi). Program yang dihasilkan oleh kompiler tidak dapat langsung dieksekusi di komputer, karena tidak terikat pada area memori tertentu tempat kode dan datanya harus ditempatkan (untuk lebih jelasnya, lihat bagian "Prinsip Fungsi Sistem Pemrograman", Bab 15 ) 2 .

Kompiler sejauh ini merupakan jenis kompiler yang paling umum (banyak yang menganggapnya sebagai satu-satunya jenis kompiler, meskipun sebenarnya tidak). Mereka memiliki aplikasi praktis terluas, yang disebabkan oleh distribusi yang luas dari semua jenis bahasa pemrograman. Berikut ini, kita akan selalu berbicara tentang kompiler, yang berarti bahwa program keluaran ditulis

Secara alami, penerjemah dan kompiler, seperti semua program lainnya, dikembangkan oleh seseorang (orang) - biasanya sekelompok pengembang. Pada prinsipnya, mereka dapat membuatnya langsung dalam bahasa instruksi mesin, tetapi jumlah kode dan data penyusun modern sedemikian rupa sehingga pembuatannya dalam bahasa instruksi mesin hampir tidak mungkin dilakukan dalam waktu yang wajar dengan biaya tenaga kerja yang masuk akal. Oleh karena itu, hampir semua kompiler modern juga dibuat menggunakan kompiler (biasanya, versi kompiler sebelumnya dari pabrikan yang sama bertindak dalam peran ini). Dan dalam kapasitas ini, kompiler sudah menjadi program keluaran untuk kompiler lain, yang tidak lebih baik dan tidak lebih buruk dari semua program keluaran lain yang dihasilkan 2 .

Definisi juru bahasa. Perbedaan antara interpreter dan penerjemah

Selain konsep "penerjemah" dan "penyusun" yang serupa, ada konsep penerjemah yang berbeda secara fundamental.

Penerjemah - itu adalah program yang mengambil program input dalam bahasa sumber dan menjalankannya.

Tidak seperti penerjemah, juru bahasa tidak menghasilkan program yang dihasilkan (atau kode apa pun yang dihasilkan secara umum) - dan inilah perbedaan mendasar di antara keduanya. Penerjemah, seperti penerjemah, menganalisis teks dari program sumber. Namun, itu tidak menghasilkan program yang dihasilkan, tetapi segera menjalankan program aslinya sesuai dengan makna yang diberikan oleh semantik bahasa input. Dengan demikian, hasil dari interpreter akan menjadi hasil yang diberikan oleh program sumber, jika program ini benar, atau pesan kesalahan jika program sumber salah.

Tentu saja, untuk menjalankan program sumber, penerjemah entah bagaimana harus mengubahnya menjadi bahasa mesin, karena jika tidak, tidak mungkin menjalankan program di komputer. Ia melakukannya, tetapi kode mesin yang dihasilkan tidak dapat diakses - tidak terlihat oleh pengguna juru bahasa. Kode mesin ini dihasilkan oleh juru bahasa, dieksekusi dan dihancurkan

1 Harus disebutkan secara khusus bahwa sekarang kompiler mulai muncul dalam sistem pemrograman modern di mana program yang dihasilkan dibuat bukan dalam bahasa instruksi mesin dan bukan dalam bahasa rakitan, tetapi dalam beberapa bahasa perantara. Dengan sendirinya, bahasa perantara ini tidak dapat langsung dieksekusi di komputer, tetapi membutuhkan juru bahasa perantara khusus untuk menjalankan program yang ditulis di dalamnya. Meskipun dalam kasus ini istilah "penerjemah" mungkin lebih tepat, istilah "penyusun" digunakan dalam literatur, karena bahasa perantara adalah bahasa tingkat sangat rendah, terkait dengan instruksi mesin dan bahasa rakitan.

Ini memunculkan pertanyaan ayam dan telur yang sudah tua. Tentu saja, pada generasi pertama, kompiler pertama ditulis langsung dalam instruksi mesin, tetapi kemudian, dengan munculnya kompiler, praktik ini ditinggalkan. Bahkan bagian paling kritis dari kompiler dibuat, minimal, menggunakan bahasa rakitan - dan juga diproses oleh kompiler. tozhayutsya sesuai kebutuhan - seperti yang dipersyaratkan oleh implementasi spesifik) dari penerjemah. Pengguna melihat hasil dari eksekusi kode-kode ini - ada hasil dari eksekusi program sumber (persyaratan untuk kesetaraan program sumber dan kode mesin yang dihasilkan dalam hal ini, (dengan syarat, harus dipenuhi).

Secara lebih rinci, masalah yang terkait dengan implementasi juru bahasa dan kepergiannya dari kompiler dibahas nanti di bagian yang sesuai.

Tujuan penerjemah, penyusun dan juru bahasa. Contoh implementasi

Program pertama yang dibuat untuk komputer generasi pertama ditulis langsung dalam bahasa kode mesin. Itu benar-benar pekerjaan yang luar biasa. Segera menjadi jelas bahwa seseorang tidak boleh dan tidak dapat berbicara bahasa perintah mesin, bahkan jika dia adalah seorang spesialis komputer. HAI; Namun, semua upaya untuk mengajar komputer untuk berbicara bahasa orang telah dimahkotai dengan sukses dan kemungkinan besar tidak akan pernah dimahkotai (untuk itu ada alasan positif tertentu yang dibahas dalam bab pertama manual ini).

Sejak itu, seluruh pengembangan perangkat lunak komputer terkait erat dengan kemunculan dan perkembangan kompiler.

Kompiler pertama adalah kompiler dari bahasa rakitan atau, demikian sebutannya, kode mnemonik. Mnemocode telah mengubah "surat filkin" dari perintah mesin menjadi bahasa yang kurang lebih dapat dimengerti oleh seorang spesialis - sebutan monik (terutama bahasa Inggris) dari perintah ini. (Sudah menjadi lebih mudah untuk memberikan program, tetapi tidak ada satu komputer pun yang mampu mengeksekusi mnem (bahasa rakitan), oleh karena itu, ada kebutuhan untuk membuat kompiler. Kompiler ini dasar, tetapi mereka terus memainkan peran penting dalam sistem pemrograman hari ini Detail lebih lanjut tentang bahasa rakitan dan kompiler dari ceritanya: lebih lanjut di bagian yang sesuai.

Langkah selanjutnya adalah pembuatan bahasa tingkat tinggi. Bahasa tingkat tinggi (mayoritas bahasa pemrograman milik mereka) mewakili semacam hubungan perantara antara bahasa formal murni dan bahasa komunikasi alami orang. Dari yang pertama mereka mendapat malisasi yang ketat dari struktur sintaksis kalimat bahasa, dari yang kedua - bagian penting dari kosa kata, semantik dari struktur dan ekspresi utama (dengan elemen operasi matematika yang berasal dari aljabar).

Munculnya bahasa tingkat tinggi sangat menyederhanakan proses pemrograman, meskipun tidak mereduksinya menjadi "tingkat ibu rumah tangga", seperti yang diminta oleh beberapa penulis pada awal kelahiran bahasa pemrograman 1 . Ada beberapa bahasa seperti itu, lalu lusinan, sekarang, mungkin, ada lebih dari seratus. Tidak ada akhir yang terlihat dari proses ini. Namun demikian, komputer dengan arsitektur tradisional "Neumann", yang hanya dapat memahami instruksi mesin, masih berlaku, sehingga pertanyaan tentang membuat kompiler tetap relevan.

Segera setelah ada kebutuhan besar untuk membuat kompiler, sebuah teori khusus mulai berkembang. Seiring waktu, dia menemukan aplikasi praktis dalam berbagai kompiler yang dibuat. Kompiler telah dibuat dan terus dibuat tidak hanya untuk bahasa baru, tetapi juga untuk bahasa yang sudah lama dikenal. Banyak pabrikan dari perusahaan terkenal dan terkemuka (seperti Microsoft atau Inprise) hingga tim penulis yang kurang dikenal merilis semakin banyak sampel kompiler baru di pasar. Ini karena sejumlah alasan, yang akan dibahas di bawah ini.

Akhirnya, karena sebagian besar aspek teoretis di bidang kompiler telah menerima implementasi praktisnya (dan ini, harus dikatakan, terjadi cukup cepat, di akhir tahun 60-an), pengembangan kompiler telah mengikuti jalur keramahan mereka ke seseorang - pengguna, pengembang program dalam bahasa tingkat tinggi. Kesimpulan logis dari proses ini adalah pembuatan sistem pemrograman - sistem perangkat lunak, yang menggabungkan, selain kompiler langsung, banyak komponen perangkat lunak terkait. Setelah muncul, sistem pemrograman dengan cepat menaklukkan pasar dan sekarang mendominasi sebagian besar (pada kenyataannya, kompiler terpisah jarang terjadi di antara alat perangkat lunak modern). Untuk informasi tentang apa itu sistem pemrograman modern dan bagaimana pengaturannya, lihat bab Sistem Pemrograman Modern. Sekarang kompiler adalah bagian integral dari sistem komputasi apa pun. Tanpa keberadaan mereka, pemrograman tugas terapan apa pun akan sulit, jika bukan tidak mungkin. Dan pemrograman tugas sistem khusus, sebagai aturan, dilakukan jika tidak dalam bahasa tingkat tinggi (C saat ini paling sering digunakan dalam peran ini), maka dalam bahasa rakitan, oleh karena itu, kompiler yang sesuai digunakan. Pemrograman langsung dalam bahasa kode mesin sangat jarang dan hanya untuk menyelesaikan masalah yang sangat sempit. Beberapa kata tentang contoh implementasi kompiler dan juru bahasa, serta bagaimana hubungannya dengan yang sudah ada alat perangkat lunak. Compiler, seperti yang akan ditunjukkan nanti, biasanya lebih mudah diimplementasikan daripada interpreter. Dalam hal efisiensi, mereka juga mengungguli mereka - jelas bahwa kode yang dikompilasi akan selalu dieksekusi lebih cepat daripada interpretasi program sumber serupa. Selain itu, tidak semua bahasa pemrograman memungkinkan pembuatan juru bahasa sederhana. Namun, juru bahasa memiliki satu keuntungan signifikan - kode yang dikompilasi selalu terikat dengan arsitektur sistem komputer yang diorientasikan, dan program sumber hanya terikat pada semantik bahasa pemrograman, yang jauh lebih mudah untuk distandarisasi. Aspek ini awalnya diabaikan. Kompiler pertama adalah kompiler mnemonik. Keturunan mereka - kompiler modern dari bahasa rakitan - ada untuk hampir semua sistem komputasi yang dikenal. Mereka sangat terfokus pada arsitektur. Lalu ada kompiler dari bahasa seperti FORTRAN, ALGOL-68, PL/1. Mereka berfokus pada komputer mainframe dengan pemrosesan batch tugas. Dari hal di atas, hanya FORTRAN yang mungkin terus digunakan hingga saat ini, karena memiliki banyak sekali perpustakaan untuk berbagai keperluan. Banyak bahasa, setelah lahir, tidak tersebar luas - ADA, Modula, Simula hanya diketahui oleh kalangan spesialis yang sempit. Pada saat yang sama, pasar sistem perangkat lunak didominasi oleh para penyusun bahasa-bahasa yang diperkirakan tidak akan bermasa depan cerah. Pertama-tama, sekarang C dan C ++. Yang pertama dari mereka lahir dengan sistem operasi seperti UNIX, bersama-sama memenangkan "tempatnya di bawah sinar matahari", dan kemudian pindah ke OS jenis lain. Yang kedua berhasil mewujudkan contoh penerapan ide-ide pemrograman berorientasi objek dengan dasar praktis yang mapan 1 . Anda juga dapat menyebutkan Pascal yang cukup umum, yang, secara tidak terduga bagi banyak orang, telah melampaui ruang lingkup bahasa pendidikan murni untuk lingkungan universitas.

Sejarah penafsir tidak begitu kaya (belum!). Seperti yang telah disebutkan, awalnya mereka tidak dianggap penting, karena hampir dalam semua hal mereka lebih rendah dari kompiler. Dari bahasa terkenal yang menyiratkan interpretasi, hanya Basic yang dapat disebutkan, meskipun sebagian besar sekarang mengetahui implementasinya yang dikompilasi dari Visual Basic, yang dibuat oleh Microsoft. Namun, sekarang situasinya agak berubah, karena masalah portabilitas perangkat lunak dan independensi platform perangkat keras menjadi semakin penting dengan perkembangan Internet. Contoh paling terkenal saat ini adalah bahasa Java (yang dengan sendirinya menggabungkan kompilasi dan interpretasi) dan JavaScript yang terkait. Lagi pula, bahasa HTML, yang menopang protokol HTTP yang memunculkan perkembangan pesat World Wide Web, juga merupakan bahasa yang ditafsirkan. Menurut penulis, kejutan masih menunggu semua orang di bidang munculnya penerjemah baru, dan yang pertama sudah muncul - misalnya, bahasa C # ("C-sharp", tetapi namanya ada di mana-mana “C sharp”), diumumkan oleh Microsoft.

HAI b sejarah bahasa pemrograman dan keadaan pasar kompiler saat ini, Anda dapat berbicara untuk waktu yang lama dan banyak. Penulis menganggap mungkin untuk membatasi diri pada apa yang telah dikatakan, karena ini bukan tujuan dari manual ini. Mereka yang ingin dapat merujuk pada literatur.

tahapan penerjemahan. Skema umum penerjemah

Pada ara. 13.1 menunjukkan skema umum kompiler. Dari situ jelas bahwa b Secara umum, proses kompilasi terdiri dari dua tahap utama - sintesis dan analisis.

Pada tahap analisis, teks program sumber dikenali, tabel pengidentifikasi dibuat dan diisi. Hasil pekerjaannya adalah representasi internal tertentu dari program, yang dapat dimengerti oleh kompiler.

Pada tahap sintesis, berdasarkan representasi internal program dan informasi yang terkandung dalam tabel (tabel) pengidentifikasi, teks dari program yang dihasilkan dihasilkan. Hasil dari tahap ini adalah kode objek.

Selain itu, kompiler berisi bagian yang bertanggung jawab untuk menganalisis dan mengoreksi kesalahan, yang jika ada kesalahan dalam teks program sumber, harus memberi tahu pengguna selengkap mungkin tentang jenis kesalahan dan tempat terjadinya. Paling-paling, kompiler dapat menawarkan opsi kepada pengguna untuk memperbaiki kesalahan.

Langkah-langkah ini, pada gilirannya, terdiri dari langkah-langkah kecil yang disebut fase kompilasi. Komposisi fase kompilasi diberikan dalam bentuk paling umum, implementasi spesifiknya, dan proses interaksinya

Pertama, ini adalah pengenal bahasa program sumber. Kemudian dia harus menerima rangkaian karakter dari bahasa masukan sebagai masukan, memeriksa kepemilikan bahasa tersebut dan, terlebih lagi, mengidentifikasi aturan yang digunakan untuk membangun rantai ini (karena jawaban atas pertanyaan tentang kepemilikan "ya" dan "tidak" kurang diminati). Sangat menarik bahwa pengguna, pembuat program masukan, bertindak sebagai penghasil rangkaian bahasa masukan.

Kedua, compiler adalah generator untuk bahasa program yang dihasilkan. Dia harus membangun rantai bahasa keluaran dengan oprah pada keluarannya; aturan yang diberikan, bahasa mesin yang dimaksud, atau bahasa saya sampler. Pengenal rantai ini akan menjadi sistem komputer tempat program yang dihasilkan dibuat.

Analisis leksikal(scanner) adalah bagian dari kompiler yang membaca program literal dalam bahasa sumber dan membangun kata-kata (token) dari bahasa sumber darinya. Input dari penganalisa leksikal menerima teks dari program sumber, dan informasi keluaran ditransmisikan untuk diproses lebih lanjut oleh kompiler pada tahap penguraian. Dari sudut pandang teoretis, penganalisis leksikal bukanlah bagian penyusun yang wajib dan diperlukan. Namun, ada alasan yang menentukan keberadaannya di hampir semua kompiler. Untuk detail lebih lanjut, lihat bagian “Penganalisis leksikal (pencatat). Prinsip-prinsip membangun pemindai”.

Mengurai adalah bagian utama penyusun pada tahap analisis. O melakukan ekstraksi konstruksi sintaksis dalam teks program sumber, diproses oleh penganalisa leksikal. Pada fase kompilasi yang sama, kebenaran sintaksis program diperiksa. Parser memainkan peran utama - peran pengenal teks bahasa pemrograman input (lihat bagian "Parser. Terjemahan yang Dikontrol Secara Sintaktis" pada bab ini).

Analisis semantik adalah bagian dari kompiler yang memeriksa teks yang benar* dari program sumber dalam kaitannya dengan semantik bahasa masukan. Validasi langsung CRS, analisis semantik harus melakukan konversi; Definisi teks diperlukan oleh semantik bahasa sumber (seperti penambahan fungsi konversi tipe implisit). Dalam berbagai implementasi comp. Tori, analisis semantik sebagian dapat memasuki fase parsing * sintaksis, sebagian - ke dalam fase persiapan pembuatan kode.

Mempersiapkan pembuatan kode adalah fase di mana kompiler melakukan tindakan pendahuluan yang terkait langsung dengan sintesis teks program yang dihasilkan, tetapi belum mengarah pada pembuatan teks dalam bahasa target. Biasanya, fase ini mencakup aktivitas yang berkaitan dengan identifikasi elemen bahasa, alokasi memori, dll. (lihat bagian "Analisis semantik dan persiapan pembuatan kode", Bab 14).

Pembuatan kode- ini adalah fase yang terkait langsung dengan pembentukan koma dari kalimat penyusun bahasa target dan teks yang dihasilkan secara keseluruhan

Mereka dapat, tentu saja, bervariasi tergantung pada versi kompiler. Namun, dalam satu atau lain bentuk, semua fase yang disajikan hampir selalu ada di setiap kompiler tertentu.

Penyusun secara keseluruhan, dari sudut pandang teori bahasa formal, bertindak dalam “dua peran”, menjalankan dua fungsi utama. program. Ini adalah fase utama pada tahap sintesis dari program yang dihasilkan. Selain pembuatan langsung teks dari program yang dihasilkan, pembuatan biasanya juga mencakup pengoptimalan - proses yang terkait dengan pemrosesan teks yang sudah dihasilkan. Kadang-kadang pengoptimalan dipilih sebagai fase kompilasi yang terpisah, karena ini berdampak signifikan pada kualitas dan efisiensi program yang dihasilkan (lihat bagian "Pembuatan kode. Metode pembuatan kode" dan "Pengoptimalan kode. Metode pengoptimalan dasar", Bab 14 ).

Tabel pengidentifikasi(terkadang "tabel karakter") adalah kumpulan data yang diatur secara khusus yang berfungsi untuk menyimpan informasi tentang elemen program sumber, yang kemudian digunakan untuk menghasilkan teks dari program yang dihasilkan. Mungkin ada satu tabel pengidentifikasi dalam implementasi kompiler tertentu, atau mungkin ada beberapa tabel seperti itu. Elemen dari program sumber, informasi yang harus disimpan selama kompilasi, adalah variabel, konstanta, fungsi, dll. - komposisi spesifik dari kumpulan elemen bergantung pada bahasa pemrograman input yang digunakan. Konsep "tabel" sama sekali tidak menyiratkan bahwa gudang data ini harus diatur secara tepat dalam bentuk tabel atau susunan informasi lainnya - metode yang mungkin untuk mengaturnya dibahas secara rinci nanti, di bagian "Tabel Pengidentifikasi. Organisasi tabel pengidentifikasi.

Ditunjukkan pada Gambar. 13.1 Pembagian proses kompilasi ke dalam fase-fase lebih berfungsi untuk tujuan metodologis dan dalam praktiknya mungkin tidak dipatuhi secara ketat. Subbagian berikut dari manual ini membahas berbagai opsi untuk organisasi teknis dari fase kompilasi yang disajikan. Ini menunjukkan bagaimana mereka dapat berhubungan satu sama lain. Di sini kami hanya mempertimbangkan aspek umum dari hubungan semacam ini.

Pertama, selama fase analisis leksikal, token diekstraksi dari teks program input sejauh diperlukan untuk fase parsing berikutnya. Kedua, seperti yang akan ditunjukkan di bawah ini, penguraian dan pembuatan kode dapat dilakukan secara bersamaan. Dengan demikian, ketiga fase kompilasi ini dapat bekerja dalam kombinasi, dan persiapan untuk pembuatan kode juga dapat dilakukan bersamaan. Selanjutnya, kami mempertimbangkan masalah teknis implementasi fase utama kompilasi, yang terkait erat dengan konsep jalan.

Konsep bagian. Kompiler multi-pass dan single-pass

Seperti yang sudah disebutkan, proses kompilasi program terdiri dari beberapa tahapan. Dalam kompiler nyata, komposisi fase-fase ini mungkin agak berbeda dari yang dipertimbangkan di atas - beberapa di antaranya dapat dibagi menjadi beberapa komponen, sementara yang lain, sebaliknya, digabungkan menjadi satu fase. Urutan eksekusi fase kompilasi juga dapat bervariasi di antara varian kompiler yang berbeda. Dalam satu kasus, kompiler melihat teks program sumber, segera melakukan semua fase kompilasi dan menerima hasilnya - kode objek. Dalam varian lain, ia hanya melakukan beberapa fase kompilasi pada teks sumber dan tidak menerima hasil akhir, tetapi satu set dari beberapa data antara. Data ini kemudian diolah kembali, dan proses ini dapat diulang beberapa kali.

Kompiler nyata, sebagai suatu peraturan, menerjemahkan teks dari program sumber dalam beberapa lintasan.

jalan - ini adalah proses pembacaan berurutan oleh penyusun data dari memori eksternal, memprosesnya dan menempatkan hasil pekerjaan di memori eksternal. Paling sering, satu pass melibatkan pelaksanaan satu atau lebih fase kompilasi. Hasil dari pass perantara adalah representasi internal dari program sumber, hasil dari pass terakhir adalah program objek yang dihasilkan.

Sebagai memori eksternal pembawa informasi apa pun dapat bertindak - RAM komputer, drive pada disk magnetik, pita magnetik, dll. Penyusun modern, pada umumnya, berusaha memanfaatkan RAM komputer secara maksimal untuk penyimpanan data, dan hanya jika ada kekurangan dari memori yang tersedia, hard drive magnetik digunakan disk. Media penyimpanan lain tidak digunakan dalam kompiler modern karena nilai tukar data yang rendah.

Selama setiap lintasan, kompiler memiliki akses ke informasi yang diperoleh dari semua lintasan sebelumnya. Sebagai aturan, ia cenderung menggunakan pertama-tama hanya informasi yang diperoleh pada pass tepat sebelum yang sekarang, tetapi pada prinsipnya ia dapat mengakses data dari pass sebelumnya hingga kode sumber program. Informasi yang diperoleh kompiler saat mengeksekusi pass tidak tersedia untuk pengguna. Itu disimpan di memori akses acak, yang dibebaskan oleh kompiler setelah proses penerjemahan selesai, atau dalam bentuk file sementara pada disk, yang juga dimusnahkan setelah kompiler selesai. Oleh karena itu, seseorang yang bekerja dengan kompiler bahkan mungkin tidak mengetahui berapa banyak operan yang dilakukan oleh kompiler - dia selalu hanya melihat teks dari program sumber dan program objek yang dihasilkan. Tetapi jumlah operan yang dilakukan adalah penting spesifikasi teknis kompiler, perusahaan terkemuka - pengembang kompiler biasanya menunjukkannya dalam deskripsi produk mereka.

Jelas bahwa pengembang mencoba meminimalkan jumlah lintasan yang dilakukan oleh kompiler. Ini meningkatkan kecepatan kompiler, mengurangi jumlah memori yang dibutuhkannya. Kompiler sekali jalan yang mengambil program sumber sebagai input dan segera menghasilkan program objek yang dihasilkan adalah ideal.

Namun, tidak selalu mungkin untuk mengurangi jumlah operan. Jumlah lintasan yang diperlukan ditentukan terutama oleh aturan tata bahasa dan semantik dari bahasa sumber. Semakin kompleks tata bahasanya dan semakin banyak opsi yang disarankan oleh aturan semantik, semakin banyak yang akan dilakukan oleh kompiler (tentu saja, kualifikasi pengembang kompiler juga berperan). Misalnya, inilah mengapa kompiler Pascal biasanya lebih cepat daripada kompiler C - tata bahasa Pascal lebih sederhana dan aturan semantiknya lebih ketat. Kompiler single-pass jarang terjadi, hanya mungkin untuk bahasa yang sangat sederhana. Kompiler sebenarnya biasanya melakukan dua hingga lima lintasan. Jadi kompiler sebenarnya adalah multi-pass. Yang paling umum adalah kompiler dua dan tiga lintasan, misalnya: lintasan pertama adalah analisis leksikal, yang kedua adalah parsing dan analisis semantik, yang ketiga adalah pembuatan dan pengoptimalan kode (opsi eksekusi, tentu saja, bergantung pada pengembang). Dalam sistem pemrograman modern, pass pertama dari kompiler (analisis leksikal kode) sering dilakukan secara paralel dengan mengedit kode program sumber (varian membangun kompiler ini dibahas nanti di bab ini).

Penerjemah. Fitur juru bangunan

Penerjemah adalah program yang mengambil program input dalam bahasa sumber dan mengeksekusinya. Seperti disebutkan di atas, perbedaan utama antara juru bahasa dan penerjemah dan kompiler adalah bahwa juru bahasa tidak menghasilkan program yang dihasilkan, tetapi hanya mengeksekusi program sumber.

Istilah 'penerjemah', seperti 'penerjemah', berarti 'penerjemah'. Dari segi terminologi, konsep-konsep ini serupa, tetapi dari segi teori bahasa formal dan kompilasi, terdapat perbedaan mendasar yang besar di antara keduanya. Jika konsep "penerjemah" dan "penyusun" hampir tidak dapat dibedakan, maka tidak dapat disamakan dengan konsep "penerjemah".

Cara paling sederhana untuk mengimplementasikan juru bahasa adalah dengan membuat program sumber terlebih dahulu diterjemahkan sepenuhnya ke dalam instruksi mesin dan kemudian segera dieksekusi. Dalam implementasi seperti itu, penerjemah sebenarnya tidak akan jauh berbeda dari kompiler, dengan satu-satunya perbedaan bahwa program yang dihasilkan di dalamnya tidak dapat diakses oleh pengguna. Kerugian dari juru bahasa seperti itu adalah bahwa pengguna harus menunggu seluruh program sumber dikompilasi sebelum dapat dieksekusi. Bahkan, juru bahasa seperti itu tidak masuk akal - itu tidak akan memberikan keuntungan apa pun dibandingkan kompiler serupa 1 . Oleh karena itu, sebagian besar penafsir bertindak sedemikian rupa sehingga mereka menjalankan program sumber secara berurutan, saat memasuki input penafsir. Kemudian pengguna tidak perlu menunggu selesainya kompilasi seluruh program sumber. Selain itu, ia dapat secara berurutan memasuki program sumber dan segera mengamati hasil eksekusinya saat perintah dimasukkan.

Dengan urutan kerja juru bahasa ini, fitur penting dimanifestasikan yang membedakannya dari kompiler - jika juru bahasa mengeksekusi perintah saat mereka tiba, maka ia tidak dapat melakukan pengoptimalan program sumber. Konsekuensinya, fase optimisasi dalam keseluruhan struktur interpreter tidak akan ada. Kalau tidak, itu akan sedikit berbeda dari struktur kompiler serupa. Seharusnya hanya diperhitungkan bahwa pada tahap terakhir - pembuatan kode - instruksi mesin tidak ditulis ke file objek, tetapi dieksekusi saat dihasilkan.

Tidak adanya langkah pengoptimalan menentukan fitur lain yang khas untuk banyak penafsir: notasi Polandia terbalik sangat sering digunakan sebagai representasi internal program (lihat bagian "Pembuatan Kode. Metode Pembuatan Kode", Bab 14). Bentuk representasi operasi yang nyaman ini hanya memiliki satu kelemahan signifikan - sulit untuk dioptimalkan. Tetapi dalam penerjemah, inilah yang tidak diperlukan.

Tidak semua bahasa pemrograman memungkinkan pembangunan juru bahasa yang dapat mengeksekusi program sumber saat perintah tiba, untuk melakukan ini, bahasa harus mengizinkan adanya kompiler yang mem-parsing program sumber dalam satu lintasan. Selain itu, bahasa tidak dapat diartikan sebagai perintah yang diterima jika memungkinkan panggilan ke fungsi dan struktur data muncul sebelum dijelaskan secara langsung. Oleh karena itu, bahasa seperti C dan Pascal tidak dapat diinterpretasikan dengan metode ini.

Tidak adanya langkah pengoptimalan mengarah pada fakta bahwa eksekusi program dengan bantuan juru bahasa kurang efisien dibandingkan dengan bantuan kompiler serupa. Selain itu, saat menginterpretasikan, program sumber harus diurai ulang setiap kali dijalankan, sedangkan saat kompilasi, diurai hanya sekali, dan file objek selalu digunakan setelah itu. Dengan demikian, juru bahasa selalu kalah dalam kinerja dibandingkan dengan kompiler.

Keuntungan dari interpreter adalah independensi eksekusi program dari arsitektur sistem komputer target. Sebagai hasil kompilasi, diperoleh kode objek yang selalu berorientasi pada arsitektur tertentu. Untuk beralih ke arsitektur lain dari sistem komputasi target], program harus dikompilasi ulang. Dan untuk menafsirkan program] hanya perlu memiliki kode sumber dan juru bahasa dari bahasa yang sesuai.

Penerjemah untuk waktu yang lama secara signifikan lebih rendah dalam prevalensi siapa pengupas. Sebagai aturan, juru bahasa ada untuk rentang terbatas bahasa pemrograman yang relatif sederhana (seperti, misalnya, alat pengembangan perangkat lunak profesional Berperforma Tinggi Dasar dibangun di atas kompiler.

Dorongan baru untuk pengembangan penafsir diberikan oleh penyebaran global jaringan komputer. Jaringan semacam itu dapat mencakup komputer dengan arsitektur pribadi, dan kemudian persyaratan untuk penerapan teks program sumber yang seragam pada masing-masing jaringan menjadi penentu. Oleh karena itu, dengan perkembangan jaringan global dan penyebaran Internet di seluruh dunia,
Dalam sistem pemrograman modern, ada implementasi perangkat lunak yang menggabungkan fungsi kompiler dan fungsi juru bahasa - tergantung pada kebutuhan pengguna, program sumber dikompilasi atau dieksekusi (ditafsirkan). Selain itu, beberapa bahasa pemrograman modern melibatkan dua tahap pengembangan: pertama, program sumber dikompilasi menjadi kode perantara (beberapa bahasa tingkat rendah), dan kemudian hasil kompilasi ini dieksekusi menggunakan juru bahasa perantara ini. Secara lebih rinci, opsi untuk sistem semacam itu dibahas di bab "Sistem Pemrograman Modern".

Contoh bahasa interpretasi yang banyak digunakan adalah HTML (Hypertext Markup Language), bahasa deskripsi hypertext. Hampir seluruh struktur Internet saat ini berfungsi atas dasar itu. Contoh lain - bahasa Jawa dan JavaScript - menggabungkan fungsi kompilasi dan interpretasi. Teks program sumber dikompilasi menjadi beberapa kode biner perantara yang tidak bergantung pada arsitektur sistem komputer target, kode ini didistribusikan melalui jaringan dan dieksekusi di sisi penerima - ditafsirkan.

Penerjemah bahasa rakitan ("assembler")

Bahasa campuran - itu adalah bahasa tingkat rendah. Struktur dan interkoneksi rantai bahasa ini dekat dengan instruksi mesin dari sistem komputer target, di mana program yang dihasilkan harus dijalankan. Penggunaan bahasa rakitan memungkinkan pengembang mengelola sumber daya (prosesor, RAM, perangkat eksternal, dll.) dari sistem komputer target pada tingkat instruksi mesin. Setiap instruksi program sumber dalam bahasa rakitan diubah menjadi satu instruksi mesin sebagai hasil kompilasi.

Penerjemah dari bahasa rakitan tentu saja akan selalu menjadi kompiler, karena bahasa dari program yang dihasilkan adalah kode mesin. Penerjemah bahasa rakitan sering disebut sebagai "assembler" atau "program assembler".

Implementasi kompiler dari bahasa assembly

Bahasa rakitan biasanya berisi kode mnemonik untuk instruksi mesin. Paling sering, mnemonik perintah berbahasa Inggris digunakan, tetapi ada varian lain dari bahasa rakitan (termasuk versi bahasa Rusia). Itu sebabnya bahasa rakitan dulu disebut "bahasa mnemocode" (sekarang nama ini praktis tidak digunakan lagi). Semua kemungkinan instruksi dalam setiap bahasa rakitan dapat dibagi menjadi dua kelompok: kelompok pertama mencakup instruksi bahasa biasa, yang diubah menjadi instruksi mesin selama penerjemahan; kelompok kedua terdiri dari instruksi bahasa khusus yang tidak diubah menjadi instruksi mesin, tetapi digunakan oleh kompiler untuk melakukan tugas kompilasi (seperti tugas mengalokasikan memori). Sintaks bahasanya sangat sederhana. Perintah program sumber biasanya ditulis sedemikian rupa sehingga ada satu perintah per baris program. Setiap instruksi bahasa rakitan, sebagai aturan, dapat dibagi menjadi tiga komponen, mengikuti secara berurutan satu demi satu: label, opcode, dan bidang operan. Kompiler dari bahasa rakitan biasanya juga menyediakan kemungkinan memiliki komentar dalam program input yang dipisahkan dari perintah oleh pembatas yang diberikan.

Bidang label berisi pengidentifikasi yang mewakili label, atau kosong. Setiap pengidentifikasi label hanya dapat terjadi sekali dalam program bahasa rakitan. Label dianggap dijelaskan di mana itu pada bertemu biasa-biasa saja dalam program (diperlukan deskripsi awal label). Label dapat digunakan untuk mentransfer kontrol ke perintah yang dikirimkannya. Tidak jarang label dipisahkan dari perintah lainnya dengan karakter pemisah (biasanya tanda titik dua ":").

Kode operasi selalu merupakan mnemonik yang ditentukan secara ketat dari salah satu perintah prosesor yang mungkin atau juga perintah yang ditentukan secara ketat (dari kompiler saya. Kode operasi ditulis dalam karakter alfabet bahasa asli. Paling sering, panjangnya 3-4, lebih jarang - 5 atau 6 karakter.

Bidang operan kosong atau daftar satu, dua, lebih jarang tiga operan. Jumlah operan ditentukan secara ketat dan bergantung pada kode operasi - setiap operasi bahasa rakitan menyediakan jumlah operan yang tetap. Dengan demikian, masing-masing opsi ini sesuai dengan instruksi unaddressed, uniaddress, two-address, atau three-address (sejumlah besar operan praktis tidak digunakan; di komputer modern, bahkan instruksi tiga alamat jarang terjadi). Sebagai opera; dov dapat berupa pengidentifikasi atau konstanta.

Fitur dari bahasa rakitan adalah bahwa sejumlah pengidentifikasi dalam n dialokasikan secara khusus untuk menunjuk register prosesor. Fikator semacam itu, di satu sisi, tidak memerlukan deskripsi awal, tetapi dengan D1, mereka tidak dapat digunakan oleh pengguna untuk tujuan lain. Himpunan pengidentifikasi ini telah ditentukan sebelumnya untuk setiap bahasa rakitan.

Kadang-kadang bahasa rakitan memungkinkan penggunaan sebagai operan dari kombinasi terbatas tertentu dari penunjukan register, pengidentifikasi, dan konstanta, yang digabungkan oleh beberapa tanda operator. Kombinasi semacam itu paling sering digunakan untuk menentukan jenis pengalamatan, misalnya, dalam instruksi mesin dari sistem komputer target.

Misalnya urutan perintah berikut ini

Ini adalah contoh urutan perintah bahasa assembly n; prosesor dari keluarga Intel 80x86. Di sini ada perintah untuk menggambarkan satu set (data (db), label (loop), opcodes (mov, dec dan jnz).Operan adalah pengenal kumpulan data (data), penunjukan register proses

(bx dan cx), label (loop) dan konstanta (4). Operan majemuk data memetakan pengalamatan tidak langsung dari data ke register basis bx pada offset 4.

Sintaks bahasa ini dapat dengan mudah dijelaskan menggunakan tata bahasa biasa. Oleh karena itu, membangun pengenal untuk bahasa rakitan tidaklah sulit. Untuk alasan yang sama, dalam kompiler dari bahasa rakitan, analisis leksikal dan sintaksis biasanya digabungkan menjadi satu pengenal.

Semantik bahasa rakitan sepenuhnya dan sepenuhnya ditentukan oleh sistem komputer target yang menjadi orientasi bahasa ini. Semantik bahasa rakitan menentukan instruksi mesin mana yang sesuai dengan setiap instruksi bahasa rakitan, serta operan mana dan berapa banyak yang diizinkan untuk opcode tertentu.

Oleh karena itu, analisis semantik dalam kompiler bahasa rakitan sesederhana analisis sintaksis. Tugas utamanya adalah untuk memeriksa validitas operan untuk setiap opcode, dan juga untuk memeriksa bahwa semua pengidentifikasi dan label yang ditemukan dalam program input dijelaskan dan pengidentifikasi yang menunjukkannya tidak cocok dengan pengidentifikasi yang telah ditentukan sebelumnya yang digunakan untuk menunjuk opcode dan register prosesor.

Skema parsing dan semantik dalam kompiler bahasa rakitan dapat diimplementasikan berdasarkan mesin negara konvensional. Fitur inilah yang menentukan fakta bahwa kompiler bahasa rakitan secara historis adalah kompiler pertama yang dibuat untuk komputer. Ada juga sejumlah fitur lain yang khusus untuk bahasa rakitan dan membuatnya lebih mudah untuk membangun kompiler untuknya.

Pertama, dalam kompiler dari bahasa rakitan, tidak ada identifikasi variabel tambahan yang dilakukan - semua variabel bahasa mempertahankan nama yang diberikan oleh pengguna. Pengembang program sumber bertanggung jawab atas keunikan nama dalam program sumber, semantik bahasa tidak memaksakan persyaratan tambahan pada proses ini. Kedua, dalam kompiler dari bahasa rakitan, alokasi memori sangat disederhanakan. Compiler dari bahasa assembly hanya bekerja dengan memori statis. Jika memori dinamis digunakan, maka untuk bekerja dengannya, Anda perlu menggunakan pustaka atau fungsi OS yang sesuai, dan pengembang program sumber bertanggung jawab atas alokasinya. Pengembang program sumber juga bertanggung jawab untuk meneruskan parameter dan mengatur tampilan memori dari prosedur dan fungsi. Dia juga harus berhati-hati dalam memisahkan data dari kode program - kompiler bahasa rakitan, tidak seperti kompiler dari bahasa tingkat tinggi, tidak secara otomatis melakukan pemisahan seperti itu. Dan ketiga, pada tahap pembuatan kode dalam kompiler dari bahasa rakitan, pengoptimalan tidak dilakukan, karena pengembang program sumber bertanggung jawab atas pengaturan kalkulasi, urutan instruksi mesin, dan alokasi register prosesor.

Kecuali untuk fitur-fitur ini, kompiler bahasa rakitan adalah kompiler normal, tetapi lebih disederhanakan dibandingkan dengan kompiler bahasa tingkat tinggi mana pun. Compiler dari bahasa assembly paling sering diimplementasikan dalam skema two-pass. Pada lintasan pertama, kompiler mem-parsing program sumber, mengubahnya menjadi kode mesin, dan sekaligus mengisi tabel pengidentifikasi. Tetapi pada lintasan pertama dalam instruksi mesin, alamat operan yang terletak di RAM tetap tidak terisi. Pada lintasan kedua, kompiler mengisi alamat ini dan secara bersamaan mendeteksi pengidentifikasi yang tidak dideklarasikan. Ini karena operan dapat dideklarasikan dalam program setelah digunakan untuk pertama kali. Maka alamatnya belum diketahui pada saat pembuatan instruksi mesin, dan oleh karena itu diperlukan langkah kedua. Contoh khas dari operan semacam itu adalah label yang melompat ke depan dalam urutan instruksi.

Definisi makro dan perintah makro

Mengembangkan program dalam bahasa rakitan adalah proses yang agak melelahkan yang seringkali membutuhkan pengulangan sederhana dari operasi berulang yang sama. Contohnya adalah urutan instruksi yang dijalankan setiap kali untuk mengatur tampilan tumpukan memori saat prosedur atau fungsi dimasukkan.

Untuk memudahkan pekerjaan pengembang, yang disebut makro telah dibuat.

makro adalah substitusi teks, di mana setiap pengidentifikasi tipe tertentu diganti dengan serangkaian karakter dari beberapa penyimpanan data. Proses mengeksekusi makro disebut pembuatan makro, dan rangkaian karakter yang dihasilkan dari eksekusi makro disebut ekspansi makro.

Proses mengeksekusi makro terdiri dari meninjau teks program sumber secara berurutan, mendeteksi pengidentifikasi tertentu di dalamnya dan menggantinya dengan string karakter yang sesuai. Selain itu, penggantian tekstual dari satu rangkaian karakter (pengidentifikasi) dengan rangkaian karakter (string) lainnya yang dilakukan. Substitusi semacam itu disebut substitusi makro.

Definisi makro digunakan untuk menentukan pengidentifikasi mana yang harus diganti dengan baris mana. Definisi makro hadir langsung dalam teks program sumber. Mereka dibedakan oleh kata kunci atau pembatas khusus yang tidak dapat ditemukan di tempat lain dalam teks program. Selama pemrosesan, semua definisi makro sepenuhnya dikecualikan dari teks program masukan, dan informasi yang terkandung di dalamnya disimpan untuk diproses saat menjalankan perintah makro.

Makro dapat berisi parameter. Kemudian setiap makro yang sesuai dengannya harus, saat dipanggil, berisi string karakter, bukan setiap parameter. String ini diganti saat menjalankan makro di setiap tempat di mana parameter yang sesuai muncul dalam definisi makro. Parameter makro dapat berupa makro lain, dalam hal ini akan dipanggil secara rekursif setiap kali substitusi parameter perlu dilakukan. Pada prinsipnya, makro dapat membentuk urutan

Panggilan rekursif, mirip dengan urutan panggilan prosedur dan fungsi rekursif, tetapi alih-alih menghitung dan meneruskan parameter, mereka hanya melakukan substitusi tekstual 1 .

Perintah makro dan definisi makro diproses oleh modul khusus yang disebut prosesor makro atau generator makro. Makrogenerator menerima sebagai masukan teks dari program sumber yang berisi definisi makro dan perintah makro, dan pada keluarannya muncul teks ekstensi makro dari program sumber, yang tidak berisi definisi makro dan perintah makro. Kedua teks hanyalah teks program, tidak ada pemrosesan lain yang dilakukan. Ini adalah perluasan makro dari teks sumber yang masuk ke input kompiler.

Sintaks perintah makro dan definisi makro tidak didefinisikan secara ketat. Ini mungkin berbeda tergantung pada implementasi kompiler dari bahasa rakitan. Tetapi prinsip melakukan substitusi makro dalam teks program tidak berubah dan tidak bergantung pada sintaksnya.

Makrogenerator paling sering tidak ada sebagai modul program terpisah, tetapi merupakan bagian dari kompiler dari bahasa rakitan. Ekstensi makro dari program sumber biasanya tidak tersedia untuk pengembangnya. Selain itu, substitusi makro dapat dilakukan secara berurutan saat mem-parsing kode sumber pada lintasan pertama kompiler, bersama dengan mem-parsing seluruh teks program, dan kemudian perluasan makro dari program sumber secara keseluruhan mungkin tidak ada sama sekali.

Misalnya, teks berikut mendefinisikan makro push_0 dalam bahasa rakitan prosesor tipe Intel 8086:

Hog ah, ah ■ mendorong kapak endm

Semantik makro ini adalah menulis angka "0" ke tumpukan melalui kapak register prosesor. Lalu di mana-mana di teks program, di mana makro akan bertemu

Itu akan diganti sebagai hasil dari substitusi makro dengan urutan perintah:

Hog ah, ah ■ mendorong kapak

Ini adalah definisi makro paling sederhana. Dimungkinkan untuk membuat definisi makro yang lebih kompleks dengan parameter. Salah satu definisi makro ini dijelaskan di bawah ini:

Kedalaman rekursi tersebut biasanya sangat terbatas. Urutan panggilan rekursif ke makro biasanya tunduk pada batasan yang jauh lebih ketat daripada urutan panggilan rekursif ke prosedur dan fungsi, yang, dengan tampilan memori bertumpuk, hanya dibatasi oleh ukuran tumpukan transfer parameter. add_abx makro xl,x2

mendorong kapak
endm

Kemudian perintah makro juga harus ditentukan dalam teks program dengan jumlah parameter yang sesuai. Dalam contoh ini, makro

Add_abx4,8 akan diganti dengan urutan perintah sebagai hasil dari substitusi makro:

Tambahkan kapak,4 tambahkan bx.4 tambahkan ex,8 kapak dorong

Dalam banyak kompiler dari bahasa rakitan, konstruksi yang lebih kompleks dimungkinkan, yang dapat berisi variabel dan label lokal. Contoh konstruksi semacam itu adalah definisi makro:

Loop_ax makro xl,x2,yl

Hog bx.bx loopax: tambahkan bx.yl

Di sini label 1 oopax bersifat lokal, hanya ditentukan dalam makro ini. Dalam hal ini, substitusi teks sederhana dari perintah makro ke dalam teks program tidak dapat lagi dilakukan, karena jika perintah makro ini dijalankan dua kali, ini akan menyebabkan munculnya dua label identik dalam teks program. Dalam hal ini, makrogenerator harus menggunakan metode substitusi teks yang lebih kompleks, mirip dengan yang digunakan oleh kompiler saat mengidentifikasi elemen leksikal dari program input, untuk memberikan semua variabel lokal yang mungkin dan nama unik label makro di dalam keseluruhan program. Definisi makro dan perintah makro tidak hanya digunakan dalam bahasa rakitan, tetapi juga dalam banyak bahasa tingkat tinggi. Di sana mereka diproses oleh modul khusus yang disebut preprocessor bahasa (misalnya, preprocessor bahasa C dikenal luas). Prinsip pemrosesan tetap sama dengan program bahasa rakitan - preprocessor melakukan substitusi teks langsung pada baris program sumber itu sendiri. Dalam bahasa tingkat tinggi, definisi makro harus dipisahkan dari teks program sumber itu sendiri, sehingga preprosesor tidak dapat mengacaukannya dengan sintaks bahasa masukan. Untuk melakukan ini, baik karakter khusus dan perintah (perintah preprosesor) digunakan, yang tidak akan pernah muncul dalam teks program sumber, atau definisi makro ditemukan.

Di dalam bagian yang tidak penting dari program sumber - adalah bagian dari komentar (implementasi seperti itu ada, misalnya, di kompiler Pascal yang dibuat oleh Borland). Makro, di sisi lain, dapat muncul di mana saja dalam kode sumber program, dan secara sintaksis panggilannya mungkin tidak berbeda dengan panggilan fungsi dalam bahasa sumber.

Harus diingat bahwa, terlepas dari kesamaan sintaks panggilan, perintah makro pada dasarnya berbeda dari prosedur dan fungsi, karena mereka tidak menghasilkan kode yang dihasilkan, tetapi merupakan substitusi teks yang dilakukan langsung dalam teks program sumber. Hasil pemanggilan fungsi dan makro bisa sangat berbeda karena hal ini.

Pertimbangkan contoh dalam bahasa C. Jika suatu fungsi dijelaskan

Int fKint a) ( return a + a: ) dan makro serupa

#define f2(a) ((a) + (a)) maka hasil pemanggilannya tidak akan selalu sama.

Memang, panggilan j=fl(i) dan j=f2(i) (di mana i dan j adalah beberapa variabel bilangan bulat) akan menghasilkan hasil yang sama. Tapi panggilan j=fl(++i) dan j=f2(++i) akan memberi arti yang berbeda variabel j. Faktanya adalah karena f2 adalah definisi makro, dalam kasus kedua substitusi teks akan dilakukan, yang akan menghasilkan urutan operator j=((++i) + (++i)). Terlihat bahwa pada urutan ini operasi ++i akan dieksekusi dua kali, berbeda dengan pemanggilan fungsi fl(++i) yang hanya dieksekusi sekali.

Karena teks program yang ditulis dalam beberapa bahasa pemrograman tidak dapat dimengerti oleh komputer, teks tersebut harus diterjemahkan ke dalam bahasa mesin. Terjemahan program dari bahasa pemrograman ke bahasa kode mesin disebut siaran(terjemahan - terjemahan), dan dilakukan oleh program khusus - penerjemah.

Ada dua jenis penerjemah: juru bahasa dan kompiler.

Penerjemah disebut penerjemah yang melakukan terjemahan operator-oleh-operator (perintah-demi-perintah) dan eksekusi selanjutnya dari operator yang diterjemahkan dari program sumber. Dua kelemahan dari metode interpretasi:

1. Program interpretasi harus ada di memori komputer selama seluruh proses eksekusi program asli, yaitu menempati sejumlah memori;

2. Proses penerjemahan pernyataan yang sama diulangi sebanyak berapa kali perintah ini harus dijalankan dalam program.

Penyusun adalah program yang mengubah (menerjemahkan) program sumber menjadi program (modul) dalam bahasa mesin. Setelah itu, program ditulis ke memori komputer dan baru kemudian dieksekusi.

Selama kompilasi, proses terjemahan dan eksekusi dipisahkan dalam waktu: pertama, program sumber sepenuhnya diterjemahkan ke dalam bahasa mesin (setelah itu kehadiran penerjemah dalam RAM tidak diperlukan), dan kemudian program yang diterjemahkan dapat dieksekusi berulang kali.

Setiap penerjemah menyelesaikan tugas utama berikut:

1. Menganalisis program siaran dan menentukan apakah mengandung kesalahan sintaksis;

2. Menghasilkan program keluaran dalam bahasa perintah komputer;

3. Mengalokasikan memori untuk program keluaran, mis. setiap variabel, konstanta, array, dan objek lainnya memiliki area memorinya sendiri.

Lewat sini, Penyusun(Bahasa inggris) penyusun- compiler, collector) membaca seluruh program sepenuhnya, menerjemahkannya dan membuat versi lengkap program dalam bahasa mesin, yang kemudian dijalankan.

Penerjemah(Bahasa inggris) penerjemah- juru bahasa, juru bahasa) menerjemahkan dan menjalankan program baris demi baris.

Setelah program dikompilasi, baik program sumber maupun kompiler tidak diperlukan lagi. Pada saat yang sama, program yang sedang diproses oleh juru bahasa harus diulangi lagi transfer ke dalam bahasa mesin setiap kali program dijalankan.

Setiap bahasa tertentu difokuskan pada kompilasi atau interpretasi, tergantung pada tujuan pembuatannya. Sebagai contoh, Pascal biasanya digunakan untuk memecahkan masalah yang agak rumit di mana kecepatan program itu penting. Oleh karena itu, bahasa ini biasanya diimplementasikan menggunakan penyusun. Di sisi lain, DASAR dibuat sebagai bahasa untuk pemrogram pemula, yang eksekusi program baris demi baris memiliki keunggulan yang tak terbantahkan. Terkadang untuk satu bahasa ada dan penyusun, dan juru bahasa. Dalam hal ini, Anda dapat menggunakan juru bahasa untuk mengembangkan dan menguji program, lalu mengkompilasi program yang di-debug untuk mempercepat eksekusinya.

Karena teks yang ditulis dalam bahasa pemrograman tidak dapat dipahami oleh komputer, teks tersebut harus diterjemahkan ke dalam kode mesin. Terjemahan program seperti itu dari bahasa pemrograman ke bahasa kode mesin disebut terjemahan, dan dilakukan oleh program khusus - penerjemah.

Penerjemah adalah program utilitas yang mengubah program sumber yang disediakan dalam bahasa pemrograman input menjadi program kerja yang disajikan dalam bahasa objek.

Saat ini, kompiler dibagi menjadi tiga kelompok utama: assembler, kompiler, dan juru bahasa.

Assembler adalah utilitas sistem yang mengubah konstruksi simbolik menjadi instruksi bahasa mesin. Fitur khusus assembler adalah bahwa mereka secara harfiah menerjemahkan satu instruksi simbolik menjadi satu instruksi mesin. Dengan demikian, bahasa rakitan (juga disebut autocode) dirancang untuk memfasilitasi persepsi set instruksi komputer dan mempercepat pemrograman dalam set instruksi ini. Jauh lebih mudah bagi seorang programmer untuk mengingat penunjukan mnemonik dari instruksi mesin daripada kode binernya.

Pada saat yang sama, bahasa rakitan, selain analog dari instruksi mesin, berisi banyak arahan tambahan yang memfasilitasi, khususnya, pengelolaan sumber daya komputer, penulisan fragmen berulang, dan pembuatan program multimodul. Oleh karena itu, ekspresi bahasa jauh lebih kaya dari sekedar bahasa pengkodean simbolik, yang sangat meningkatkan efisiensi pemrograman.

Kompiler adalah program utilitas yang menerjemahkan ke dalam bahasa mesin program yang ditulis dalam bahasa pemrograman sumber. Sama seperti assembler, kompiler mengubah program dari satu bahasa ke bahasa lain (paling sering, ke bahasa komputer tertentu). Namun, perintah bahasa sumber berbeda secara signifikan dalam organisasi dan kekuatan dari perintah bahasa mesin. Ada bahasa di mana satu instruksi bahasa sumber diterjemahkan ke dalam 7-10 instruksi mesin. Namun, ada juga bahasa di mana setiap instruksi dapat sesuai dengan 100 atau lebih instruksi mesin (misalnya, Prolog). Selain itu, dalam bahasa sumber sering digunakan pengetikan data yang ketat, yang dilakukan melalui deskripsi pendahuluannya. Pemrograman mungkin tidak bergantung pada pengkodean suatu algoritme, tetapi pada pemikiran yang cermat tentang struktur atau kelas data. Proses menerjemahkan dari bahasa semacam itu biasa disebut kompilasi, dan bahasa sumber biasanya disebut sebagai bahasa pemrograman tingkat tinggi (atau bahasa tingkat tinggi). Abstraksi bahasa pemrograman dari sistem perintah komputer menyebabkan terciptanya berbagai macam bahasa secara independen yang berfokus pada penyelesaian masalah tertentu. Bahasa muncul untuk perhitungan ilmiah, perhitungan ekonomi, akses ke database, dan lain-lain.

Penerjemah adalah program atau perangkat yang melakukan terjemahan operator demi operator dan eksekusi program sumber. Tidak seperti compiler, interpreter tidak menghasilkan program bahasa mesin sebagai keluaran. Setelah mengenali perintah bahasa sumber, ia segera menjalankannya. Baik kompiler dan juru bahasa menggunakan metode yang sama untuk mem-parsing kode sumber suatu program. Tetapi juru bahasa memungkinkan Anda untuk mulai memproses data setelah menulis bahkan satu perintah. Ini membuat proses pengembangan dan debugging program menjadi lebih fleksibel. Selain itu, tidak adanya kode mesin keluaran memungkinkan untuk tidak "mengotori" perangkat eksternal dengan file tambahan, dan penerjemah itu sendiri dapat dengan mudah disesuaikan dengan arsitektur mesin apa pun, setelah mengembangkannya hanya sekali dalam bahasa pemrograman yang banyak digunakan. Oleh karena itu, bahasa yang ditafsirkan seperti Java Script, VB Script menjadi tersebar luas. Kerugian dari juru bahasa adalah rendahnya kecepatan eksekusi program. Biasanya, program yang ditafsirkan berjalan 50 hingga 100 kali lebih lambat daripada program yang ditulis dalam kode mesin.

Emulator adalah program atau alat perangkat lunak dan perangkat keras yang memberikan kemampuan untuk menjalankan program pada komputer tertentu tanpa pemrograman ulang, menggunakan kode atau metode untuk melakukan operasi yang berbeda dari komputer ini. Emulator mirip dengan juru bahasa karena secara langsung mengeksekusi program yang ditulis dalam beberapa bahasa. Namun, paling sering itu adalah bahasa mesin atau kode perantara. Keduanya mewakili instruksi dalam kode biner yang dapat segera dieksekusi setelah mengenali opcode. Tidak seperti program teks, tidak diperlukan untuk mengenali struktur program, untuk memilih operan.

Emulator cukup sering digunakan untuk berbagai keperluan. Misalnya, saat mengembangkan sistem komputasi baru, pertama kali dibuat emulator yang menjalankan program yang sedang dikembangkan untuk komputer yang belum ada. Ini memungkinkan set instruksi untuk dievaluasi dan perangkat lunak dasar dikembangkan sebelum perangkat keras yang sesuai dibuat.

Sangat sering emulator digunakan untuk menjalankan program lama di komputer baru. Biasanya, komputer yang lebih baru lebih cepat dan memiliki periferal yang lebih baik. Ini memungkinkan Anda meniru program lama dengan lebih efisien daripada menjalankannya di komputer lama.

Transcoder - program atau perangkat perangkat lunak yang menerjemahkan program yang ditulis dalam bahasa mesin satu komputer ke dalam program dalam bahasa mesin komputer lain. Jika emulator adalah analog penafsir yang kurang cerdas, maka transcoder bertindak dalam kapasitas yang sama terkait dengan kompiler. Demikian pula, kode mesin sumber (dan biasanya biner) atau representasi perantara diubah menjadi kode serupa lainnya dalam satu instruksi dan tanpa analisis umum struktur program sumber. Transcoder berguna saat mem-porting program dari satu arsitektur komputer ke arsitektur lainnya. Mereka juga dapat digunakan untuk merekonstruksi teks program bahasa tingkat tinggi dari kode biner yang tersedia.

Makroprosesor adalah program yang menggantikan satu urutan karakter dengan yang lain. Ini semacam kompiler. Ini menghasilkan teks keluaran dengan memproses sisipan khusus yang terletak di teks sumber. Sisipan ini dibuat dengan cara khusus dan termasuk dalam konstruksi bahasa, yang disebut bahasa makro. Makroprosesor sering digunakan sebagai add-on untuk bahasa pemrograman, meningkatkan fungsionalitas sistem pemrograman. Hampir semua assembler berisi makroprosesor, yang meningkatkan efisiensi pengembangan program mesin. Sistem pemrograman seperti itu biasanya disebut sebagai perakit makro.

Makroprosesor juga digunakan dengan bahasa tingkat tinggi. Mereka meningkatkan fungsionalitas bahasa seperti PL/1, C, C++. Makroprosesor banyak digunakan di C dan C++, membuatnya lebih mudah untuk menulis program. Makroprosesor meningkatkan efisiensi pemrograman tanpa mengubah sintaks dan semantik bahasa.

Sintaks - seperangkat aturan bahasa tertentu yang menentukan pembentukan elemen-elemennya. Dengan kata lain, itu adalah seperangkat aturan untuk pembentukan urutan karakter yang bermakna secara semantik dalam bahasa tertentu. Sintaks ditentukan menggunakan aturan yang menjelaskan konsep bahasa tertentu. Contoh konsep adalah: variabel, ekspresi, operator, prosedur. Urutan konsep dan penggunaannya yang diizinkan dalam aturan menentukan struktur yang benar secara sintaksis yang membentuk program. Ini adalah hierarki objek, bukan bagaimana mereka berinteraksi satu sama lain, yang ditentukan melalui sintaks. Sebagai contoh, sebuah operator dapat muncul hanya dalam sebuah prosedur, sedangkan sebuah ekspresi dalam sebuah operator, sebuah variabel dapat terdiri dari sebuah nama dan indeks opsional, dan seterusnya. Sintaks tidak terkait dengan fenomena dalam program seperti "melompat ke label yang tidak ada" atau "variabel dengan nama yang diberikan tidak ditentukan". Inilah yang dilakukan semantik.

Semantik - aturan dan kondisi yang menentukan hubungan antara unsur-unsur bahasa dan makna semantiknya, serta interpretasi makna makna dari konstruksi sintaksis bahasa tersebut. Objek bahasa pemrograman tidak hanya ditempatkan dalam teks sesuai dengan hierarki tertentu, tetapi juga saling berhubungan melalui konsep lain yang membentuk berbagai asosiasi. Misalnya, variabel yang sintaksnya menentukan lokasi yang valid hanya dalam deklarasi dan beberapa pernyataan, memiliki tipe tertentu, dapat digunakan dengan rangkaian operasi terbatas, memiliki alamat, ukuran, dan harus dideklarasikan sebelum digunakan di sebuah program.

Parser adalah komponen penyusun yang memeriksa pernyataan sumber untuk kepatuhan dengan aturan sintaksis dan semantik dari bahasa pemrograman tertentu. Terlepas dari namanya, penganalisis memeriksa sintaks dan semantik. Ini terdiri dari beberapa blok, yang masing-masing memecahkan masalahnya sendiri. Ini akan dipertimbangkan lebih detail saat menjelaskan struktur penerjemah.

Setiap penerjemah melakukan tugas utama berikut:

Menganalisis program yang sedang diterjemahkan, khususnya, menentukan apakah mengandung kesalahan sintaksis;

Menghasilkan program keluaran (sering disebut program objek) dalam bahasa instruksi mesin;

Mengalokasikan memori untuk program objek.