Bagaimana cara membuat bahasa pemrograman saya sendiri dan kompiler untuk itu [ditutup]


427

Saya teliti dengan pemrograman dan telah menemukan bahasa termasuk BASIC, FORTRAN, COBOL, LISP, LOGO, Java, C ++, C, MATLAB, Mathematica, Python, Ruby, Perl, JavaScript, Majelis dan sebagainya. Saya tidak mengerti bagaimana orang membuat bahasa pemrograman dan membuat kompiler untuk itu. Saya juga tidak mengerti bagaimana orang membuat OS seperti Windows, Mac, UNIX, DOS dan sebagainya. Hal lain yang misterius bagi saya adalah bagaimana orang membuat perpustakaan seperti OpenGL, OpenCL, OpenCV, Cocoa, MFC dan sebagainya. Hal terakhir yang tidak bisa saya pahami adalah bagaimana para ilmuwan merancang bahasa assembly dan assembler untuk mikroprosesor. Saya benar-benar ingin mempelajari semua hal ini dan saya berusia 15 tahun. Saya selalu ingin menjadi ilmuwan komputer seseorang seperti Babbage, Turing, Shannon, atau Dennis Ritchie.


Saya sudah membaca Aho Compiler Design dan buku konsep OS Tanenbaum dan mereka semua hanya membahas konsep dan kode di tingkat tinggi. Mereka tidak masuk ke rincian dan nuansa dan cara menyusun kompiler atau sistem operasi. Saya ingin pemahaman konkret sehingga saya bisa membuatnya sendiri dan bukan hanya pemahaman tentang apa thread, semaphore, proses, atau parsing itu. Saya bertanya kepada saudara saya tentang semua ini. Dia adalah seorang siswa SB di EECS di MIT dan tidak memiliki petunjuk tentang bagaimana sebenarnya membuat semua hal ini di dunia nyata. Yang dia tahu hanyalah pemahaman tentang Desain Kompiler dan konsep OS seperti yang telah Anda sebutkan (yaitu seperti Thread, Sinkronisasi, Concurrency, manajemen memori, Analisis Leksikal, pembuatan kode Intermediate dan sebagainya)


Jika Anda berada di Unix / Linux, Anda bisa mendapatkan informasi tentang alat khusus: lex, yaccdan bison.
mouviciel

Saran pertama saya adalah Membaca Buku Naga oleh Aho. amazon.com/Compiler-Principles-Techniques-Alfred-Aho/dp/…
Julian

1
Mungkin tidak terlalu membantu, tetapi saya sarankan untuk mengunjungi sites.google.com/site/steveyegge2/blog-rants (blog Steve Yegge), dan steve-yegge.blogspot.com/ (blog Steve Yegge lainnya).
KK.

3
Pelajari sebanyak mungkin bahasa pemrograman. Dengan begitu Anda akan belajar dari konsep dan kesalahan mereka. Mengapa puas dengan kurcaci, ketika Anda bisa berdiri di bahu raksasa?
sbi

1
petunjuk: seorang juru bahasa lebih mudah daripada seorang kompiler; itu hanya kelas yang "melakukan sesuatu" berdasarkan input teks yang dibaca baris demi baris. petunjuk lain: ikat ini ke refleksi dan Anda dapat mengontrol objek sewenang-wenang dengan skrip Anda.
Dave Cousineau

Jawaban:


407

Pada dasarnya, pertanyaan Anda adalah "bagaimana chip komputer, set instruksi, sistem operasi, bahasa, perpustakaan, dan aplikasi dirancang dan diimplementasikan?" Itu adalah industri multi-miliar dolar di seluruh dunia yang mempekerjakan jutaan orang, banyak di antaranya adalah spesialis. Anda mungkin ingin sedikit memfokuskan pertanyaan Anda.

Yang mengatakan, saya bisa istirahat di:

Saya tidak mengerti bagaimana orang membuat bahasa pemrograman dan membuat kompiler untuk itu.

Ini mengejutkan bagi saya, tetapi banyak orang melihat bahasa pemrograman sebagai magis. Ketika saya bertemu orang-orang di pesta atau apa pun, jika mereka bertanya kepada saya apa yang saya lakukan, saya memberi tahu mereka bahwa saya merancang bahasa pemrograman dan mengimplementasikan kompiler dan alat, dan mengejutkan berapa kali orang - programmer profesional, ingatlah Anda - katakan "wow, aku tidak pernah memikirkannya, tapi ya, seseorang harus mendesain hal-hal itu". Sepertinya mereka berpikir bahwa bahasa baru saja terbentuk sepenuhnya dengan infrastruktur alat di sekitar mereka.

Mereka tidak muncul begitu saja. Bahasa dirancang seperti produk lainnya: dengan hati-hati membuat serangkaian pengorbanan di antara berbagai kemungkinan yang bersaing. Kompiler dan alat dibuat seperti produk perangkat lunak profesional lainnya: dengan memecah masalah, menulis satu baris kode pada satu waktu, dan kemudian menguji coba keluar dari program yang dihasilkan.

Desain bahasa adalah topik yang sangat besar. Jika Anda tertarik mendesain bahasa, tempat yang baik untuk memulai adalah dengan memikirkan kekurangan apa yang ada dalam bahasa yang sudah Anda ketahui. Keputusan desain sering muncul karena mempertimbangkan cacat desain pada produk lain.

Sebagai alternatif, pertimbangkan domain yang Anda minati, dan kemudian rancang bahasa khusus domain (DSL) yang menentukan solusi untuk masalah di domain itu. Anda menyebutkan LOGO; itu adalah contoh yang bagus dari DSL untuk domain "menggambar garis". Ekspresi reguler adalah DSL untuk domain "temukan pola dalam string". LINQ di C # / VB adalah DSL untuk domain "filter, gabung, urutkan, dan proyeksikan data". HTML adalah DSL untuk domain "jelaskan tata letak teks pada halaman", dan seterusnya. Ada banyak domain yang dapat menerima solusi berbasis bahasa. Salah satu favorit saya adalah Inform7, yang merupakan DSL untuk domain "game petualangan berbasis teks"; mungkin bahasa pemrograman serius tingkat tertinggi yang pernah saya lihat.

Setelah Anda membuat sketsa seperti apa bahasa yang Anda inginkan, cobalah untuk menuliskan dengan tepat apa aturannya untuk menentukan program apa yang legal dan ilegal. Biasanya Anda ingin melakukan ini pada tiga tingkatan:

  1. leksikal : apa aturan untuk kata-kata dalam bahasa, karakter apa yang legal, seperti apa bentuk angka, dan sebagainya.
  2. sintaksis : bagaimana kata-kata bahasa bergabung menjadi unit yang lebih besar? Dalam C # unit yang lebih besar adalah hal-hal seperti ekspresi, pernyataan, metode, kelas, dan sebagainya.
  3. semantik : diberikan program yang secara sintaksis legal, bagaimana Anda mengetahui apa yang dilakukan oleh program tersebut ?

Tuliskan aturan-aturan ini setepat mungkin . Jika Anda melakukan pekerjaan dengan baik maka Anda dapat menggunakannya sebagai dasar untuk menulis kompiler atau juru bahasa. Lihatlah spesifikasi C # atau spesifikasi skrip ECMAS untuk melihat apa yang saya maksud; mereka penuh dengan aturan yang sangat tepat yang menggambarkan apa yang membuat program hukum dan bagaimana mencari tahu apa yang dilakukan seseorang.

Salah satu cara terbaik untuk memulai menulis kompiler adalah dengan menulis kompiler bahasa tingkat tinggi ke tinggi . Tulis kompiler yang mengambil string dalam bahasa Anda dan keluarkan string dalam C # atau JavaScript atau bahasa apa pun yang Anda ketahui; biarkan kompiler untuk bahasa itu lalu urus tugas berat mengubahnya menjadi kode runnable.

Saya menulis blog tentang desain C #, VB, VBScript, JavaScript, dan bahasa serta alat lainnya; jika hal ini menarik minat Anda, coba lihat. http://blogs.msdn.com/ericlippert (historical) dan http://ericlippert.com (saat ini)

Secara khusus Anda mungkin menemukan posting ini menarik; di sini saya mencantumkan sebagian besar tugas yang dilakukan oleh kompiler C # untuk Anda selama analisis semantiknya. Seperti yang Anda lihat, ada banyak langkah. Kami memecah masalah analisis besar menjadi serangkaian masalah yang dapat kami pecahkan secara individual.

http://blogs.msdn.com/b/ericlippert/archive/2010/02/04/how-many-passes.aspx

Akhirnya, jika Anda mencari pekerjaan untuk melakukan hal ini ketika Anda lebih tua maka pertimbangkan untuk datang ke Microsoft sebagai mahasiswa magang dan mencoba masuk ke divisi pengembang. Itulah sebabnya saya berakhir dengan pekerjaan saya hari ini!


Sudahkah Anda menulis tentang optimasi kompiler tingkat mana yang tidak dilakukan lagi karena CLR dapat melakukannya secara otomatis?

6
@ Thorbjørn: Mari kita perjelas terminologinya. "Compiler" adalah perangkat apa pun yang menerjemahkan dari satu bahasa pemrograman ke yang lain. Salah satu hal menyenangkan tentang memiliki kompiler C # yang mengubah C # menjadi IL, dan kompiler IL ("jitter") yang mengubah IL menjadi kode mesin, adalah Anda dapat menulis kompiler C # menjadi IL (mudah!), Dan letakkan optimisasi spesifik prosesor dalam jitter. Bukan berarti optimisasi kompiler "tidak dilakukan", melainkan tim kompiler jit yang melakukannya untuk kita. Lihat blogs.msdn.com/b/ericlippert/archive/2009/06/11/...
Eric Lippert

6
@ Cyclotis04: Inform6 mengkompilasi ke Z-code, yang merupakan contoh awal yang sangat terkenal dari mesin virtual berbasis bytecode. Itulah sebabnya semua game Infocom pada 1980-an bisa lebih besar dari memori dan portabel untuk beberapa arsitektur; permainan dikompilasi menjadi z-code dan kemudian z-code interpreter dengan paging memori kode diimplementasikan untuk beberapa mesin. Saat ini tentu saja Anda dapat menjalankan juru bahasa zcode pada jam tangan jika perlu, tetapi kembali pada hari yang berteknologi tinggi . Lihat en.wikipedia.org/wiki/Z-machine untuk detailnya.
Eric Lippert

@EricLippert Compiler tidak perangkat, perangkat adalah sesuatu mengandung hardware.We bisa mengatakan program yang telah ditetapkan yang memiliki seperangkat aturan untuk mengkonversi input data ke kode mesin
dharam

2
@ Demam: Perangkat apa pun yang dibuat untuk tujuan tertentu. Setiap kompiler yang pernah saya tulis dijalankan pada perangkat keras yang dibuat khusus untuk memungkinkan kompiler ada.
Eric Lippert

127

Anda mungkin menemukan Lets Build a Compiler oleh Jack Crenshaw pengantar yang menarik untuk menulis kompiler dan bahasa assembly.

Penulis membuatnya sangat sederhana dan berfokus pada membangun fungsionalitas aktual.


2
Apa yang menarik tentang intro Crenshaw adalah bahwa itu berakhir (spoiler: itu tidak lengkap) hanya tentang waktu Anda menjalankan menampar ke masalah yang akan membuat Anda menyadari, hei, saya benar-benar harus merancang bahasa saya sepenuhnya sebelum mulai mengimplementasikannya. Dan kemudian Anda berkata, hei, jika saya harus menulis spesifikasi bahasa lengkap, mengapa tidak melakukannya dalam notasi formal yang kemudian dapat saya masukkan ke dalam alat untuk menghasilkan parser? Dan kemudian Anda melakukannya seperti orang lain.
kindall

3
@indall, Anda harus melakukannya dengan tangan untuk menyadari bahwa ada alasan untuk menggunakan alat.

72

"Saya benar - benar ingin mempelajari hal ini". Jika Anda serius untuk jangka panjang:

  • Pergilah kuliah, berspesialisasi dalam rekayasa perangkat lunak. Ambil setiap kelas kompiler yang bisa Anda dapatkan. Orang-orang yang memberikan kelas lebih berpendidikan dan lebih berpengalaman daripada Anda; Sebaiknya gunakan perspektif ahli mereka untuk menyajikan informasi kepada Anda dengan cara yang tidak akan pernah Anda dapatkan dari membaca kode.

  • Tetaplah mengikuti kelas matematika hingga sekolah menengah dan lanjutkan ke perguruan tinggi selama 4 tahun. Fokus pada matematika non-standar: logika, teori grup, meta-matematika. Ini akan memaksa Anda untuk berpikir secara abstrak. Ini akan memungkinkan Anda untuk membaca makalah teori lanjutan tentang kompilasi dan memahami mengapa teori-teori itu menarik dan bermanfaat. Anda dapat mengabaikan teori-teori canggih itu, jika Anda selamanya ingin berada di belakang keadaan modern.

  • Kumpulkan / baca teks-teks kompiler standar: Aho / Ullman, dll. Teks-teks itu berisi apa yang umumnya disetujui masyarakat adalah hal-hal mendasar. Anda mungkin tidak menggunakan semuanya dari buku-buku itu, tetapi Anda harus tahu itu ada, dan Anda harus tahu mengapa Anda tidak menggunakannya. Saya pikir Muchnick hebat, tetapi untuk topik yang cukup canggih.

  • Bangun kompiler. Mulai SEKARANG dengan membangun yang busuk. Ini akan mengajarkan Anda beberapa masalah. Bangun yang kedua. Ulangi. Pengalaman ini membangun sinergi besar dengan pembelajaran buku Anda.

  • Tempat yang sangat bagus untuk memulai adalah belajar tentang BNF (Backus Naur Form), parser, dan parser-generator. BNF secara efektif digunakan secara universal di lahan kompiler, dan Anda tidak dapat berbicara secara realistis dengan sesama tipe kompiler jika Anda tidak mengetahuinya.

Jika Anda ingin pengantar pertama yang hebat untuk dikompilasi, dan nilai langsung dari BNF bukan hanya untuk dokumentasi tetapi sebagai bahasa logam yang dapat diproses dengan alat, lihat tutorial ini (bukan milik saya) untuk membangun kompiler "meta" (kompiler yang membuat kompiler) berdasarkan pada makalah dari tahun 1964 (ya, Anda membaca itu benar) ["META II bahasa penulisan kompiler berorientasi sintaks" oleh Val Schorre. (http://doi.acm.org/10.1145/800257.808896)] IMHO ini adalah salah satu kertas comp-sci terbaik yang pernah ditulis: ini mengajarkan Anda untuk membangun kompiler-kompiler dalam 10 halaman. Saya belajar awalnya dari makalah ini.

Apa yang saya tulis di atas adalah banyak dari pengalaman pribadi, dan saya pikir itu telah membantu saya dengan cukup baik. YMMV, tapi IMHO, tidak banyak.


54
-1 Tidak ada yang di atas diperlukan.
Neil Butterworth

77
@ nbt Tidak ada yang di atas yang diperlukan. Tetapi semua hal di atas membantu. Sangat banyak.
Konrad Rudolph

1
Saya khususnya tidak setuju dengan "Belajar matematika untuk berpikir secara abstrak!" saran. Bahkan jika Anda berpikir bahwa "belajar berpikir secara abstrak" sangat membantu dalam menciptakan bahasa pemrograman Anda sendiri dan kompiler (saya tidak - saya merasa jauh lebih berguna untuk belajar dengan melakukan, daripada dengan mengambil bundaran ini, rute sangat tidak langsung) , matematika bukan satu-satunya bidang dengan pemikiran abstrak! (Saya seorang ahli matematika btw, jadi saya tidak menyangkal penggunaan matematika secara umum, hanya penerapannya dalam kasus khusus ini ...)
grautur

26
Jika Anda ingin membaca makalah teknis lanjutan tentang teori kompiler, Anda sebaiknya kompeten secara matematis. Anda dapat memutuskan untuk mengabaikan literatur itu, dan teori Anda dan karenanya penyusun akan lebih miskin karenanya. Para penentang di sini membuat titik bahwa Anda dapat membangun kompiler tanpa banyak pendidikan formal, dan saya setuju. Mereka tampaknya menyiratkan Anda dapat membangun kompiler yang sangat bagus tanpanya. Itu bukan taruhan yang akan saya ambil.
Ira Baxter

7
CS adalah disiplin yang benar-benar berguna untuk desain dan implementasi bahasa. Tentu saja tidak wajib, tetapi sudah ada penelitian puluhan tahun yang dapat dan harus dimanfaatkan, dan tidak ada alasan sama sekali untuk mengulangi kesalahan orang lain.
Donal Fellows

46

Inilah buku / kursus online yang dapat Anda ikuti yang disebut Elemen Sistem Komputasi: Membangun Komputer Modern dari Prinsip Pertama .

Menggunakan simulator, Anda benar-benar membangun sistem komputer yang lengkap dari bawah ke atas. Meskipun banyak komentator menyatakan bahwa pertanyaan Anda terlalu luas, buku ini sebenarnya menjawabnya sambil tetap sangat mudah dikelola. Setelah selesai, Anda akan menulis game dalam bahasa tingkat tinggi (yang Anda rancang), yang menggunakan fungsionalitas OS Anda sendiri, yang akan dikompilasi ke dalam bahasa VM (yang Anda rancang) oleh kompiler Anda, yang menghasilkan diterjemahkan ke dalam bahasa rakitan (yang Anda rancang) oleh penerjemah VM Anda, yang akan dirakit menjadi kode mesin (yang Anda rancang) oleh assembler Anda, yang berjalan pada sistem komputer Anda yang Anda kumpulkan dari chip yang Anda rancang dengan menggunakan logika boolean dan bahasa deskripsi perangkat keras yang sederhana.

Bab-bab:

  1. Ikhtisar Kursus
  2. Logika Boolean
  3. Keripik Kombinatorial
  4. Chips berurutan
  5. Bahasa mesin
  6. Arsitektur komputer
  7. Assembler
  8. Mesin Virtual I: Aritmatika
  9. Mesin Virtual II: Kontrol
  10. Bahasa pemrograman
  11. Kompiler I: Analisis Sintaks
  12. Kompiler II: Pembuatan Kode
  13. Sistem operasi
  14. Daftar barang

Lebih Menyenangkan untuk Pergi


Terima kasih atas hasil editnya, orang yang tidak dikenal. Saya mencoba beberapa kali tetapi pikiran saya tidak cukup fokus untuk deskripsi ... tetapi tidak ingin tidak menyebutkan buku. Buku ini sekarang online di tautan Rencana Studi: www1.idc.ac.il/tecs/plan.html . Ini juga sangat terjangkau secara online. Selamat menikmati semuanya.
Joe Internet

Saya akan menyarankan ini sendiri ... untuk yang malas, lihat intro 10 menit: Dari NAND ke Tetris dalam 12 Langkah @ youtube.com/watch?v=JtXvUoPx4Qs
Richard Anthony Hein

46

Ambil langkah mundur. Kompiler hanyalah sebuah program yang menerjemahkan dokumen dalam satu bahasa menjadi dokumen dalam bahasa lain. Kedua bahasa harus didefinisikan dengan baik dan spesifik.

Bahasa tidak harus berupa bahasa pemrograman. Mereka bisa bahasa apa saja yang aturannya bisa ditulis. Anda mungkin pernah melihat Google Translate ; itu adalah kompiler karena dapat menerjemahkan satu bahasa (katakanlah, Jerman) ke yang lain (Jepang, mungkin).

Contoh lain dari kompiler adalah mesin rendering HTML. Inputnya adalah file HTML dan outputnya adalah serangkaian instruksi untuk menggambar piksel di layar.

Ketika kebanyakan orang berbicara tentang kompiler, mereka biasanya merujuk ke sebuah program yang menerjemahkan bahasa pemrograman tingkat tinggi (seperti Java, C, Prolog) menjadi yang tingkat rendah (assembly atau kode mesin). Itu bisa menakutkan. Tapi itu tidak terlalu buruk ketika Anda mengambil pandangan generalis bahwa kompiler adalah program yang menerjemahkan satu bahasa ke bahasa lain.

Bisakah Anda menulis program yang membalik setiap kata dalam sebuah string? Sebagai contoh:

When the cat's away, the mice will play.

menjadi

nehW eht s'tac yawa, eht ecim lliw yalp.

Itu bukan program yang sulit untuk ditulis, tetapi Anda perlu memikirkan beberapa hal:

  • Apa itu "kata"? Bisakah Anda menentukan karakter mana yang membentuk kata?
  • Di mana kata-kata mulai dan berakhir?
  • Apakah kata-kata dipisahkan oleh hanya satu ruang, atau dapatkah lebih - atau kurang?
  • Apakah tanda baca perlu dibalik juga?
  • Bagaimana dengan tanda baca di dalam kata?
  • Apa yang terjadi pada huruf kapital?

Jawaban atas pertanyaan ini membantu bahasanya didefinisikan dengan baik. Sekarang, lanjutkan dan tulis programnya. Selamat, Anda baru saja menulis kompiler.

Bagaimana dengan ini: Bisakah Anda menulis program yang mengambil serangkaian instruksi menggambar dan menghasilkan file PNG (atau JPEG)? Mungkin kira-kira seperti ini:

image 100 100
background black
color red
line 20 55 93 105
color green
box 0 0 99 99

Sekali lagi, Anda perlu melakukan beberapa pemikiran untuk mendefinisikan bahasa:

  • Apa saja instruksi primitifnya?
  • Apa yang muncul setelah kata "line"? Apa yang muncul setelah "warna"? Demikian juga untuk "latar belakang", "kotak", dll.
  • Apa itu angka?
  • Apakah file input kosong diizinkan?
  • Apakah boleh menggunakan huruf besar untuk kata-kata?
  • Apakah angka negatif diperbolehkan?
  • Apa yang terjadi jika Anda tidak memberikan arahan "gambar"?
  • Apakah boleh untuk tidak menentukan warna?

Tentu saja, ada lebih banyak pertanyaan untuk dijawab, tetapi jika Anda dapat memahaminya, Anda telah menentukan bahasa. Program yang Anda tulis untuk melakukan terjemahan, Anda dapat menebaknya, adalah kompiler.

Anda tahu, menulis kompiler tidaklah sulit. Kompiler yang Anda gunakan di Java atau C hanyalah versi yang lebih besar dari kedua contoh ini. Jadi lakukanlah! Tetapkan bahasa yang sederhana dan tulis program untuk membuat bahasa itu melakukan sesuatu. Cepat atau lambat Anda akan ingin memperluas bahasa Anda. Misalnya, Anda mungkin ingin menambahkan variabel atau ekspresi aritmatika. Kompiler Anda akan menjadi lebih kompleks tetapi Anda akan mengerti setiap bitnya karena Anda menulisnya sendiri. Begitulah bahasa dan kompiler muncul.


7
myFirstCompiler = (str) -> ("" + (str || "")). split (''). reverse (). join (''); jsfiddle.net/L7qSr
Larry Battle

21

Jika Anda tertarik dengan desain kompiler, lihat Buku Naga (judul resmi: Penyusun: Prinsip, Teknik, dan Peralatan). Ini secara luas dianggap sebagai buku klasik tentang topik ini.


4
Catatan, Anda mungkin perlu sedikit lebih banyak pengalaman aktual untuk mendapatkan hasil maksimal dari buku ini. Referensi yang bagus.

13
-1 Hanya seseorang yang belum membacanya yang dapat berpikir bahwa buku naga itu bagus. dan itu khususnya tidak menjawab pertanyaan.
Neil Butterworth

33
Buku Naga? Untuk anak berusia lima belas tahun yang antusias? Saya lebih suka dia menjaga antusiasmenya lebih lama.
David Thornley

1
Alternatif yang lebih mudah diakses: 'Programming Language Pragmatics' 3e .
willjcroz

@ Davidvidhorn Jangan menghitungnya sepenuhnya (Ya, saya menyadari ini adalah posting yang sangat lama). Saya mulai meneliti bagaimana bahasa bekerja pada usia 15 dan berfokus secara khusus pada mesin virtual. Sekarang saya berusia 16 tahun dan setelah berbulan-bulan penelitian, penulisan, dan penulisan ulang, saya memiliki juru bahasa dan kompiler yang saya senangi.
David


10

Jangan percaya ada sesuatu yang ajaib tentang kompiler atau OS: tidak ada. Ingat program yang Anda tulis untuk menghitung semua vokal dalam sebuah string, atau menjumlahkan angka-angka dalam array? Sebuah kompiler tidak berbeda dalam konsep; itu hanya jauh lebih besar.

Setiap program memiliki tiga fase:

  1. membaca beberapa hal
  2. proses itu: menerjemahkan data input ke data output
  3. menulis beberapa hal lain - data keluaran

Pikirkan tentang itu: apa input ke kompiler? Sederetan karakter dari file sumber.

Apa output dari kompiler? Sederetan byte yang mewakili instruksi mesin ke komputer target.

Jadi apa fase "proses" kompiler? Apa yang fase itu lakukan?

Jika Anda menganggap bahwa kompiler - seperti program lain - harus menyertakan tiga fase ini, Anda akan memiliki ide bagus tentang bagaimana kompiler dibangun.


3
Seperti yang dikatakan Neil, benar tetapi tidak bermanfaat. Aspek kompiler mendasar seperti tata bahasa rekursif dan tabel simbol tidak jelas secara intuitif.
Mason Wheeler

1
@Mason Wheeler: Saya pikir ada orang yang secara realistis bercita-cita untuk menulis kompiler (dan merancang bahasa target?) Kemungkinan besar akan berpikir tata bahasa rekursif dan tabel simbol adalah konsep yang cukup mendasar.
FumbleFingers

8

Saya bukan seorang ahli, tetapi inilah tikaman saya:

Anda sepertinya tidak bertanya tentang menulis kompiler, hanya assembler. Ini bukan sihir.

Mencuri jawaban seseorang dari SO ( https://stackoverflow.com/questions/3826692/how-do-i-translate-assembly-to-binary ), assembly terlihat seperti ini:

label:  LDA #$00
        JMP label

Kemudian Anda menjalankannya melalui assembler, dan berubah menjadi sesuatu seperti ini:

$A9 $00
$4C $10 $00

Hanya itu semua terjepit, seperti ini:

$A9 $00 $4C $10 $00

Ini benar-benar bukan sihir.

Anda tidak dapat menulis itu di notepad, karena notepad menggunakan ASCII (bukan hex). Anda akan menggunakan hex editor, atau cukup menulis byte secara terprogram. Anda menulis hex itu ke file, beri nama "a.exe" atau "a.out", lalu beri tahu OS untuk menjalankannya.

Tentu saja, CPU modern dan sistem operasi benar-benar sangat rumit, tetapi itulah ide dasarnya.

Jika Anda ingin menulis kompiler baru, berikut ini caranya:

1) Tulis bahasa yang ditafsirkan menggunakan sesuatu seperti contoh kalkulator dalam parsing (atau kerangka parsing bagus lainnya). Itu akan membuat Anda lebih cepat pada dasar-dasar parsing.

2) Menulis penerjemah. Terjemahkan bahasa Anda ke dalam, katakanlah, Javascript. Sekarang bahasa Anda akan berjalan di browser.

3) Tulis penerjemah ke tingkat yang lebih rendah, seperti LLVM, C, atau Assembly.

Anda bisa berhenti di sini, ini adalah kompiler. Ini bukan kompiler yang mengoptimalkan, tapi itu bukan pertanyaan. Anda mungkin juga perlu mempertimbangkan untuk menulis tautan dan assembler, tetapi apakah Anda benar-benar ingin melakukannya?

4) (Gila) Tulis pengoptimal. Tim-tim besar bekerja selama beberapa dekade dalam hal ini.

4) (Sane) Terlibat dalam komunitas yang ada. GCC, LLVM, PyPy, tim inti yang mengerjakan penerjemah apa pun.


8

Beberapa yang lain telah memberikan jawaban yang sangat baik. Saya hanya akan menambahkan beberapa saran lagi. Pertama, buku bagus untuk apa yang Anda coba lakukan adalah teks Implementasi Kompiler Modern Appel (pilih C , Java , atau Standard ML ). Buku ini membawa Anda melalui implementasi kompiler lengkap untuk bahasa sederhana, Tiger, hingga perakitan MIPS yang dapat dijalankan dalam emulator, bersama dengan pustaka dukungan runtime minimal. Untuk sekali melewati semua yang diperlukan untuk membuat bahasa kompilasi bekerja, ini adalah buku yang cukup bagus 1 .

Appel akan membawa Anda melalui cara mengkompilasi bahasa yang datang pra-desain, tetapi tidak menghabiskan banyak waktu pada apa arti berbagai fitur bahasa atau bagaimana berpikir tentang mereka dalam hal manfaat relatif mereka untuk merancang bahasa Anda sendiri. Untuk aspek itu, Bahasa Pemrograman: Konsep & Konstruksi layak. Konsep, Teknik, dan Model Pemrograman Komputer juga merupakan buku yang bagus untuk memikirkan secara mendalam tentang desain bahasa, meskipun ia melakukannya dalam konteks satu bahasa ( Oz ).

Akhirnya, saya menyebutkan bahwa Appel memiliki teksnya dalam C, Java, dan ML Standar - jika Anda serius tentang konstruksi kompiler dan bahasa pemrograman, saya sarankan mempelajari ML dan menggunakan versi Appel itu. Bahasa ML-family memiliki sistem tipe kuat yang sebagian besar fungsional - fitur yang akan berbeda dari banyak bahasa lain, jadi pelajari jika Anda belum tahu bahasa fungsional akan mengasah keahlian bahasa Anda. Juga, pencocokan pola dan pola pikir fungsional mereka sangat cocok untuk jenis manipulasi yang perlu Anda lakukan sering dalam kompiler, sehingga kompiler yang ditulis dalam bahasa berbasis ML biasanya jauh lebih pendek dan lebih mudah dipahami daripada kompiler yang ditulis dalam C, Java, atau bahasa serupa. Buku Harperpada Standar ML adalah panduan yang cukup bagus untuk membantu Anda memulai; bekerja melalui itu harus mempersiapkan Anda untuk mengambil buku implementasi kompiler ML Standar Appel. Jika Anda mempelajari Standar ML, maka juga akan cukup mudah untuk mengambil OCaml untuk pekerjaan selanjutnya; IMO, memiliki tooling yang lebih baik untuk programmer yang bekerja (terintegrasi lebih bersih dengan lingkungan OS sekitarnya, menghasilkan program yang dapat dieksekusi dengan mudah, dan memiliki beberapa alat pembangun kompiler yang spektakuler seperti ulex dan Menhir).


1 Untuk referensi jangka panjang, saya lebih suka Dragon Book, karena memiliki lebih banyak perincian tentang hal-hal yang cenderung saya rujuk seperti cara kerja dalam algoritma parser dan memiliki cakupan yang lebih luas dari pendekatan yang berbeda, tetapi buku Appel sangat bagus untuk umpan pertama. Pada dasarnya, Appel mengajarkan Anda satu cara untuk melakukan banyak hal melalui compiler dan memandu Anda melewatinya. Buku Naga mencakup berbagai alternatif desain yang lebih rinci, tetapi memberikan panduan yang jauh lebih sedikit tentang cara membuat sesuatu berfungsi.


Diedit : ganti referensi Aho yang salah dengan Sethi, sebutkan CTMCP.


Ugh, saya memiliki Essentials Of Programming Languages ​​untuk kelas juru bahasa perguruan tinggi saya. Itu mengerikan. Saya bahkan menyukai skema secara pribadi dan tidak keberatan dengan sintaksisnya, tetapi pengarangnya kurang memahami konsep-konsep yang merusaknya bagi saya.
Greg Guida

Saya suka kompilasi Appel dengan kelanjutan tetapi saya memang menemukan buku-bukunya diasumsikan banyak pengetahuan sebelumnya.
Jon Harrop

6

Saya harus membuat kompiler untuk kelas di perguruan tinggi.

Dasar-dasar melakukan ini tidak serumit yang Anda kira. Langkah pertama adalah membuat tata bahasa Anda. Pikirkan tata bahasa bahasa Inggris. Dengan cara yang sama Anda dapat mem-parsing kalimat jika memiliki subjek dan predikat. Untuk lebih lanjut tentang itu baca tentang Tata Bahasa Konteks Gratis .

Setelah Anda menguasai tata bahasa (aturan bahasa Anda), menulis kompiler semudah hanya mengikuti aturan itu. Compiler biasanya menerjemahkan kode mesin, tetapi kecuali jika Anda ingin belajar x86, saya sarankan Anda melihat MIPS atau membuat Mesin Virtual Anda sendiri.

Kompiler biasanya memiliki dua bagian, pemindai dan pengurai. Pada dasarnya, pemindai membaca dalam kode dan memisahkannya menjadi token. Pengurai melihat struktur token tersebut. Kemudian kompiler melewati dan mengikuti beberapa aturan sederhana untuk mengonversinya menjadi kode apa pun yang Anda perlukan (perakitan, kode perantara seperti bytecode, dll.). Jika Anda memecahnya menjadi potongan-potongan kecil dan kecil, ini akhirnya tidak menakutkan sama sekali.

Semoga berhasil!


8
Sederhana secara konseptual? Iya. Sebenarnya sederhana? Tidak.
Neil Butterworth

7
Uhm. Kompiler, setelah pemindaian / penguraian perlu melakukan pengecekan tipe / inferensi, optimisasi, alokasi register, dll. (Saat menggunakan kode yang ditafsirkan, Anda hanya menunda bagian ini ke tahap runtime.)
Macke

Tidak ada suara dari saya: sementara kompiler memiliki dua bagian dasar, salah satunya adalah membangun deskripsi abstrak dari program (yang biasanya dipecah menjadi pemindaian dan penguraian) dan yang lain untuk menulis versi deskripsi abstrak itu lagi di beberapa bentuk lain (misalnya, kode mesin). (Catatan: Mengoptimalkan kompiler biasanya mencoba untuk meningkatkan deskripsi abstrak sebelum menuliskannya, tapi itu penyempurnaan.)
Donal Fellows

6

Kode buku Petzold adalah pengantar bagus untuk non-teknis dan teknisi mulai dari prinsip pertama. Ini sangat mudah dibaca dan luas dalam cakupannya tanpa terlalu banyak macet.

Sekarang saya sudah menulis ini, saya harus membacanya kembali.



5

Ada jawaban yang sangat bagus di utas ini, tetapi saya hanya ingin menambahkan milik saya karena saya juga pernah memiliki pertanyaan yang sama. (Juga, saya ingin menunjukkan bahwa buku yang disarankan oleh Joe-Internet adalah sumber yang bagus.)

Pertama adalah pertanyaan bagaimana cara kerja komputer? Begini caranya: Input -> Compute -> Output.

Pertama-tama pertimbangkan bagian "Hitung". Kita akan melihat bagaimana Input dan Output bekerja nanti.

Komputer pada dasarnya terdiri dari prosesor (atau CPU) dan beberapa memori (atau RAM). Memori adalah kumpulan lokasi yang masing-masing dapat menyimpan jumlah bit yang terbatas, dan setiap lokasi memori tersebut dapat dirujuk dengan angka, ini disebut alamat lokasi memori. Prosesor adalah gadget yang dapat mengambil data dari memori, lakukan beberapa operasi berdasarkan data dan tulis kembali sebagian data ke memori. Bagaimana cara prosesor mengetahui apa yang harus dibaca dan apa yang harus dilakukan setelah membaca data dari memori?

Untuk menjawab ini, kita perlu memahami struktur prosesor. Berikut ini adalah tampilan yang cukup sederhana. Sebuah prosesor pada dasarnya terdiri dari dua bagian. Salah satunya adalah serangkaian lokasi memori yang dibangun di dalam prosesor yang berfungsi sebagai memori yang berfungsi. Ini disebut "register". Yang kedua adalah sekelompok mesin elektronik yang dibangun untuk melakukan operasi tertentu menggunakan data dalam register. Ada dua register khusus yang disebut "Program Counter" atau pc dan "Instruction Register" atau ir. Prosesor menganggap memori dipartisi menjadi tiga bagian. Bagian pertama adalah "memori program", yang menyimpan program komputer yang sedang dieksekusi. Yang kedua adalah "memori data". Yang ketiga digunakan untuk beberapa tujuan khusus, kita akan membicarakannya nanti. Penghitung Program berisi lokasi instruksi berikutnya untuk membaca dari Memori Program. Penghitung Instruksi Berisi nomor yang merujuk pada operasi saat ini sedang dilakukan. Setiap operasi yang dapat dilakukan prosesor mengacu pada nomor yang disebut opcode operasi. Bagaimana komputer pada dasarnya bekerja adalah membaca lokasi memori yang dirujuk oleh Penghitung Program ke dalam Register Instruksi (dan itu menambah Penghitung Program sehingga menunjuk ke lokasi memori dari instruksi berikutnya). Selanjutnya, ia membaca Register Instruksi dan melakukan operasi yang diinginkan. Misalnya instruksi dapat membaca lokasi memori tertentu ke dalam register, atau untuk menulis ke beberapa register atau untuk melakukan beberapa operasi menggunakan nilai-nilai dari dua register dan menulis output ke register ketiga. Penghitung Instruksi Berisi nomor yang merujuk pada operasi saat ini sedang dilakukan. Setiap operasi yang dapat dilakukan prosesor mengacu pada nomor yang disebut opcode operasi. Bagaimana komputer pada dasarnya bekerja adalah membaca lokasi memori yang dirujuk oleh Penghitung Program ke dalam Register Instruksi (dan itu menambah Penghitung Program sehingga menunjuk ke lokasi memori dari instruksi berikutnya). Selanjutnya, ia membaca Register Instruksi dan melakukan operasi yang diinginkan. Misalnya instruksi dapat membaca lokasi memori tertentu ke dalam register, atau untuk menulis ke beberapa register atau untuk melakukan beberapa operasi menggunakan nilai-nilai dari dua register dan menulis output ke register ketiga. Penghitung Instruksi Berisi nomor yang merujuk pada operasi saat ini sedang dilakukan. Setiap operasi yang dapat dilakukan prosesor mengacu pada nomor yang disebut opcode operasi. Bagaimana komputer pada dasarnya bekerja adalah membaca lokasi memori yang dirujuk oleh Penghitung Program ke dalam Register Instruksi (dan itu menambah Penghitung Program sehingga menunjuk ke lokasi memori dari instruksi berikutnya). Selanjutnya, ia membaca Register Instruksi dan melakukan operasi yang diinginkan. Misalnya instruksi dapat membaca lokasi memori tertentu ke dalam register, atau untuk menulis ke beberapa register atau untuk melakukan beberapa operasi menggunakan nilai-nilai dari dua register dan menulis output ke register ketiga. Setiap operasi yang dapat dilakukan prosesor mengacu pada nomor yang disebut opcode operasi. Bagaimana komputer pada dasarnya bekerja adalah membaca lokasi memori yang dirujuk oleh Penghitung Program ke dalam Register Instruksi (dan itu menambah Penghitung Program sehingga menunjuk ke lokasi memori dari instruksi berikutnya). Selanjutnya, ia membaca Register Instruksi dan melakukan operasi yang diinginkan. Misalnya instruksi dapat membaca lokasi memori tertentu ke dalam register, atau untuk menulis ke beberapa register atau untuk melakukan beberapa operasi menggunakan nilai-nilai dari dua register dan menulis output ke register ketiga. Setiap operasi yang dapat dilakukan prosesor mengacu pada nomor yang disebut opcode operasi. Bagaimana komputer pada dasarnya bekerja adalah membaca lokasi memori yang dirujuk oleh Penghitung Program ke dalam Register Instruksi (dan itu menambah Penghitung Program sehingga menunjuk ke lokasi memori dari instruksi berikutnya). Selanjutnya, ia membaca Register Instruksi dan melakukan operasi yang diinginkan. Misalnya instruksi dapat membaca lokasi memori tertentu ke dalam register, atau untuk menulis ke beberapa register atau untuk melakukan beberapa operasi menggunakan nilai-nilai dari dua register dan menulis output ke register ketiga. Bagaimana komputer pada dasarnya bekerja adalah membaca lokasi memori yang dirujuk oleh Penghitung Program ke dalam Register Instruksi (dan itu menambah Penghitung Program sehingga menunjuk ke lokasi memori dari instruksi berikutnya). Selanjutnya, ia membaca Register Instruksi dan melakukan operasi yang diinginkan. Misalnya instruksi dapat membaca lokasi memori tertentu ke dalam register, atau untuk menulis ke beberapa register atau untuk melakukan beberapa operasi menggunakan nilai-nilai dari dua register dan menulis output ke register ketiga. Bagaimana komputer pada dasarnya bekerja adalah membaca lokasi memori yang dirujuk oleh Penghitung Program ke dalam Register Instruksi (dan itu menambah Penghitung Program sehingga menunjuk ke lokasi memori dari instruksi berikutnya). Selanjutnya, ia membaca Register Instruksi dan melakukan operasi yang diinginkan. Misalnya instruksi dapat membaca lokasi memori tertentu ke dalam register, atau untuk menulis ke beberapa register atau untuk melakukan beberapa operasi menggunakan nilai-nilai dari dua register dan menulis output ke register ketiga.

Sekarang bagaimana komputer melakukan Input / Output? Saya akan memberikan jawaban yang sangat sederhana. Lihat http://en.wikipedia.org/wiki/Input/output dan http://en.wikipedia.org/wiki/Interrupt. untuk lebih. Ia menggunakan dua hal, bagian ketiga dari memori dan sesuatu yang disebut Interrupts. Setiap perangkat yang terpasang pada komputer harus dapat bertukar data dengan prosesor. Itu melakukannya dengan menggunakan bagian ketiga dari memori yang disebutkan sebelumnya. Prosesor mengalokasikan sepotong memori untuk setiap perangkat dan perangkat dan prosesor berkomunikasi melalui potongan memori itu. Tetapi bagaimana prosesor tahu lokasi apa yang merujuk ke perangkat apa dan kapan perangkat perlu bertukar data? Di sinilah interupsi masuk. Interupsi pada dasarnya adalah sinyal ke prosesor untuk menjeda apa saat ini dan menyimpan semua registernya ke lokasi yang diketahui dan kemudian mulai melakukan sesuatu yang lain. Ada banyak interupsi, masing-masing diidentifikasi dengan angka unik. Untuk setiap interupsi, ada program khusus yang terkait dengannya. Ketika interupsi terjadi, prosesor menjalankan program yang sesuai dengan interupsi. Sekarang tergantung pada bios dan bagaimana perangkat perangkat keras terhubung ke motherboard komputer, setiap perangkat mendapat interupsi yang unik dan sepotong memori. Saat mem-boot sistem operasi dengan bantuan bios menentukan lokasi interupsi dan memori masing-masing perangkat dan mengatur program khusus untuk interupsi agar dapat menangani perangkat dengan benar. Jadi, ketika suatu perangkat membutuhkan beberapa data atau ingin mengirimkan beberapa data, itu menandakan interupsi. Prosesor menjeda apa yang dilakukannya, menangani interupsi dan kemudian kembali ke apa yang dilakukannya. Ada banyak jenis interupsi, seperti untuk hdd, keyboard dll. Yang penting adalah pengatur waktu sistem, yang memanggil interupsi secara berkala. Juga ada opcodes yang dapat memicu interupsi, yang disebut interupsi perangkat lunak.

Sekarang kita hampir dapat memahami bagaimana sistem operasi bekerja. Ketika boot, os mengatur penghenti waktu, sehingga memberikan kontrol ke os secara berkala. Ini juga mengatur interupsi lain untuk menangani perangkat lain dll. Sekarang ketika komputer menjalankan banyak program, dan interupsi timer terjadi os mendapatkan kontrol dan melakukan tugas-tugas penting seperti manajemen proses, manajemen memori dll. Juga os biasanya menyediakan cara abstrak bagi program untuk mengakses perangkat perangkat keras, daripada membiarkannya mengakses perangkat secara langsung. Ketika suatu program ingin mengakses suatu perangkat, ia memanggil beberapa kode yang disediakan oleh os yang kemudian berbicara dengan perangkat tersebut. Ada banyak teori yang terlibat dalam hal ini yang berkaitan dengan konkurensi, utas, kunci, manajemen memori dll.

Sekarang, secara teori seseorang dapat menulis suatu program secara langsung menggunakan opcodes. Inilah yang disebut kode mesin. Ini jelas sangat menyakitkan. Sekarang bahasa assembly untuk prosesor tidak lain adalah mnemonik untuk opcode ini, yang membuatnya lebih mudah untuk menulis program. Assembler sederhana adalah program yang mengambil program yang ditulis dalam kumpulan dan menggantikan mnemonik dengan opcode yang sesuai.

Bagaimana cara mendesain prosesor dan bahasa assembly. Untuk mengetahui bahwa Anda harus membaca beberapa buku tentang arsitektur komputer. (lihat bab 1-7 buku yang dirujuk oleh joe-internet). Ini melibatkan belajar tentang aljabar boolean, bagaimana membangun sirkuit kombinatorial sederhana untuk ditambahkan, gandakan dll, bagaimana membangun memori dan rangkaian sekuensial, cara membangun mikroprosesor dan sebagainya.

Sekarang bagaimana seseorang menulis bahasa komputer? Seseorang dapat memulai dengan menulis assembler sederhana dalam kode mesin. Kemudian gunakan assembler itu untuk menulis kompiler untuk bagian sederhana dari C. Kemudian gunakan bagian itu dari C untuk menulis versi yang lebih lengkap dari C. Akhirnya gunakan C untuk menulis bahasa yang lebih rumit seperti python atau C ++. Tentu saja untuk menulis bahasa Anda harus terlebih dahulu mendesainnya (dengan cara yang sama Anda desigh prosesor). Sekali lagi lihat beberapa buku pelajaran tentang itu.

Dan bagaimana cara menulis os. Pertama, Anda menargetkan platform seperti x86. Kemudian Anda mencari tahu bagaimana boot dan kapan os Anda akan dipanggil. PC khas melakukan booting dengan cara ini. Itu mulai dan bios melakukan beberapa tes. Kemudian bios membaca sektor pertama dari hdd dan memuat konten ke lokasi tertentu di memori. Kemudian mengatur cpu untuk mulai mengeksekusi data yang dimuat ini. Ini adalah titik dimana Anda dipanggil. Sebuah os khas pada saat ini memuat sisa memori itu sendiri. Kemudian menginisialisasi perangkat dan mengatur hal-hal lain dan akhirnya menyapa Anda dengan layar login.

Jadi untuk menulis os, Anda harus menulis "boot-loader". Maka Anda harus menulis kode untuk menangani interupsi dan perangkat. Maka Anda harus menulis semua kode untuk manajemen proses, manajemen perangkat dll. Kemudian Anda harus menulis api yang memungkinkan program berjalan di os Anda untuk mengakses perangkat dan sumber daya lainnya. Dan akhirnya Anda harus menulis kode yang membaca program dari disk, mengaturnya sebagai proses dan mulai menjalankannya.

Tentu saja jawaban saya disederhanakan dan mungkin kurang praktis digunakan. Dalam pembelaan saya, saya sekarang adalah mahasiswa pascasarjana dalam teori, jadi saya telah melupakan banyak hal ini. Tetapi Anda dapat google banyak hal ini dan mencari tahu lebih lanjut.


4

Saya dapat mengingat suatu titik dalam karier pemrograman saya ketika saya berada dalam keadaan yang sama membingungkannya dengan Anda: saya telah membaca sedikit tentang teorinya, buku Naga, buku Macan (merah), tetapi masih belum banyak. sebuah petunjuk bagaimana menyatukan semuanya.

Yang mengikatnya adalah menemukan proyek konkret untuk dilakukan (dan kemudian mengetahui bahwa saya hanya membutuhkan sebagian kecil dari semua teori).

Java VM memberi saya titik awal yang bagus: secara konseptual merupakan "prosesor" tetapi sangat abstrak dari detail CPU yang sebenarnya. Ini juga memberi bagian penting dan sering diabaikan dalam proses pembelajaran: memisahkan hal-hal sebelum menyatukannya kembali (seperti anak-anak yang terbiasa dengan set radio di masa lalu).

Bermain-main dengan dekompiler dan Hello, kelas dunia di Jawa. Baca spesifikasi JVM dan coba pahami apa yang terjadi. Ini akan memberi Anda wawasan didasarkan pada apa compiler melakukan .

Kemudian bermain-main dengan kode yang menciptakan Hello, World class. (Akibatnya, Anda membuat kompiler khusus aplikasi, untuk bahasa yang sangat terspesialisasi di mana Anda hanya bisa mengatakan Halo, Dunia.)

Cobalah menulis kode yang dapat dibaca dalam Hello, World yang ditulis dalam bahasa lain, dan hasilkan kelas yang sama. Buat agar Anda dapat mengubah string dari "Halo, Dunia" menjadi sesuatu yang lain.

Sekarang coba kompilasi (di Jawa) kelas yang menghitung beberapa ekspresi aritmatika, seperti "2 * (3 + 4)". Ambil kelas ini terpisah, tulis "kompiler mainan" yang dapat menyatukannya kembali.


3

1) Ceramah video yang luar biasa dari University of Washington:

Konstruksi Kompiler CSE P 501 - Musim Gugur 2009 www.cs.washington.edu/education/courses/csep501/09au/lectures/video.html *

2) SICP http://groups.csail.mit.edu/mac/classes/6.001/abelson-sussman-lectures/ Dan buku dengan nama yang sama. Ini sebenarnya wajib untuk setiap insinyur perangkat lunak di luar sana.

3) Juga, tentang pemrograman fungsional, Haskell, kalkulus lambda, semantik (termasuk denotasional) dan implementasi kompiler untuk bahasa fungsional. Anda bisa mulai dari 2005-SS-FP.V10.2005-05-24.HDV jika Anda sudah tahu Haskell. Video Uxx adalah jawabannya. Silakan ikuti video Vxx terlebih dahulu.

http://video.s-inf.de/#FP.2005-SS-Giesl.(COt).HD_Videoaufzeichnung

(Video dalam bahasa Inggris, kursus lain dalam bahasa Jerman.)

  • pengguna baru hanya dapat memposting maksimal dua hyperlink.

3

ANTLR adalah titik awal yang baik. Ini adalah kerangka kerja menghasilkan bahasa, mirip dengan Lex dan Yacc. Ada gui bernama ANTLRWorks yang menyederhanakan proses.

Di dunia .NET ada Dynamic Language Runtime yang dapat digunakan untuk menghasilkan kode di dunia .NET. Saya telah menulis bahasa ekspresi yang disebut Zentrum yang menghasilkan kode menggunakan DLR. Ini akan menunjukkan kepada Anda cara mengurai dan menjalankan ekspresi yang diketik secara statis dan dinamis.


2

Untuk pengantar sederhana tentang bagaimana kompiler bekerja dan bagaimana membuat bahasa pemrograman Anda sendiri, saya akan merekomendasikan buku baru http://createyourproglang.com yang lebih berfokus pada teori desain bahasa tanpa harus tahu tentang OS / CPU internal, yaitu lexers, parsers , juru bahasa, dll.

Ia menggunakan alat yang sama yang digunakan untuk membuat bahasa pemrograman Coffee Script dan Fancy yang baru-baru ini populer .


2

Jika semua yang Anda katakan benar, Anda memiliki profil seorang peneliti yang menjanjikan, dan pemahaman konkret hanya dapat diperoleh dengan satu cara: belajar. Dan saya tidak mengatakan " Baca semua buku ilmu komputer tingkat tinggi ini (khususnya yang ini ) yang ditulis oleh jenius ini !"; Maksud saya: Anda harus bersama orang-orang tingkat tinggi untuk menjadi ilmuwan komputer seperti Charles Babbage, Alan Turing, Claude Shannon atau Dennis Ritchie. Saya tidak membenci orang yang belajar sendiri (saya salah satu dari mereka) tetapi tidak banyak orang seperti Anda di luar sana. Saya sangat merekomendasikan Symbolic Systems Program (SSP) di Stanford University . Seperti yang dikatakan situs web mereka:

Program Sistem Simbolik (SSP) di Universitas Stanford berfokus pada komputer dan pikiran: sistem buatan dan alami yang menggunakan simbol untuk mewakili informasi. SSP menyatukan mahasiswa dan fakultas yang tertarik pada berbagai aspek hubungan manusia-komputer, termasuk ...

  • ilmu kognitif : mempelajari kecerdasan manusia, bahasa alami, dan otak sebagai proses komputasi;
  • kecerdasan buatan : menganugerahi komputer dengan perilaku dan pemahaman mirip manusia; dan
  • interaksi manusia-komputer : merancang perangkat lunak komputer dan antarmuka yang berfungsi baik dengan pengguna manusia.

2

Saya akan menyarankan sesuatu yang sedikit keluar dari bidang kiri: belajar Python (atau mungkin Ruby, tapi saya memiliki lebih banyak pengalaman dalam Python jadi itulah yang akan saya bahas). Dan tidak hanya mencoba-coba di dalamnya, tetapi benar-benar mengenalnya pada tingkat yang dalam.

Ada beberapa alasan saya menyarankan ini:

  1. Python adalah bahasa yang dirancang dengan sangat baik. Meskipun memiliki beberapa kutil, ia memiliki lebih sedikit IMHO daripada banyak bahasa lainnya. Jika Anda seorang perancang bahasa pemula, ada baiknya mengekspos diri Anda ke sebanyak mungkin bahasa yang baik.

  2. Implementasi standar Python (CPython) bersifat open-source dan terdokumentasi dengan baik, membuatnya lebih mudah untuk memahami bagaimana bahasa bekerja di bawah tenda.

  3. Python dikompilasi ke kode byte sederhana yang lebih mudah dipahami daripada perakitan dan yang berfungsi sama pada semua platform yang dijalankan oleh Python. Jadi Anda akan belajar tentang kompilasi (karena Python mengkompilasi kode sumber Anda ke kode byte) dan interpretasi (karena kode byte ini ditafsirkan dalam mesin virtual Python).

  4. Python memiliki banyak fitur baru yang diusulkan, didokumentasikan dalam PEP bernomor (Proposal Peningkatan Python). PEP menarik untuk dibaca untuk melihat bagaimana perancang bahasa mempertimbangkan untuk mengimplementasikan fitur sebelum memilih cara mereka melakukannya. (PEP yang masih dalam pertimbangan sangat menarik dalam hal ini.)

  5. Python memiliki campuran fitur dari berbagai paradigma pemrograman, sehingga Anda akan belajar tentang berbagai cara untuk mendekati penyelesaian masalah dan memiliki berbagai alat yang lebih luas untuk dipertimbangkan termasuk dalam bahasa Anda sendiri.

  6. Python membuatnya cukup mudah untuk memperluas bahasa dengan berbagai cara dengan dekorator, metaclasses, kait impor, dll. Sehingga Anda dapat bermain dengan fitur bahasa baru sampai batas tanpa benar-benar meninggalkan bahasa. (Sebagai tambahan: blok kode adalah objek kelas satu di Ruby, jadi Anda benar-benar dapat menulis struktur kontrol baru seperti loop! Saya mendapat kesan bahwa programmer Ruby tidak perlu mempertimbangkan untuk memperluas bahasa, hanya bagaimana Anda memprogram di Ruby. Tapi ini sangat keren.)

  7. Dengan Python, Anda benar-benar dapat membongkar bytecode yang dihasilkan oleh kompiler, atau bahkan menulis sendiri dari awal dan meminta penerjemah mengeksekusi (saya telah melakukan ini sendiri, dan itu membekukan pikiran tetapi menyenangkan).

  8. Python memiliki pustaka yang bagus untuk parsing. Anda dapat mengurai kode Python menjadi pohon sintaksis abstrak dan kemudian memanipulasinya menggunakan modul AST. Modul PyParsing berguna untuk mem-parsing bahasa yang arbitrer, seperti yang Anda desain. Anda bisa secara teori menulis kompiler bahasa pertama Anda dengan Python jika Anda mau (dan itu bisa menghasilkan C, assembly, atau bahkan output Python).

Pendekatan investigasi ini dapat berjalan dengan baik dengan pendekatan yang lebih formal, karena Anda akan mulai mengenali konsep yang telah Anda pelajari dalam bahasa yang Anda gunakan, dan sebaliknya.

Selamat bersenang-senang!


Tidak menggali di python, tapi itu intinya. Anak itu sudah memiliki N bahasa untuk N besar; penambahan N tidak akan membuat banyak perbedaan. Ambil C, misalnya. Itu standar. Ini memiliki banyak perpustakaan. Ini cross-platform (ketika Anda tetap pada standar). Anda dapat membongkar output. Anda dapat menulis CFront. Dll Jadi, di sana.
Ian

1

Baiklah, saya pikir pertanyaan Anda dapat ditulis ulang menjadi, "Apa konsep praktis inti dari gelar ilmu komputer", dan jawaban totalnya, tentu saja, adalah untuk mendapatkan gelar Sarjana Anda sendiri di bidang Ilmu Komputer.

Pada dasarnya, Anda membuat kompiler bahasa pemrograman Anda sendiri dengan membaca file teks, mengekstraksi informasi darinya, dan melakukan transformasi pada teks berdasarkan dari informasi yang Anda baca dari itu, sampai Anda telah mengubahnya menjadi byte yang dapat dibaca oleh loader (cf, Linker dan Loader oleh Levine). Compiler sepele adalah proyek yang cukup ketat ketika dilakukan untuk pertama kalinya.

Jantung sistem operasi adalah kernel, yang mengelola sumber daya (mis., Alokasi / deallokasi memori), dan beralih di antara tugas / proses / program.

Assembler adalah transformasi text-> byte.

Jika Anda tertarik pada hal ini, saya sarankan menulis assembler X86, di Linux, yang mendukung beberapa subset perakitan X86 standar. Itu akan menjadi titik masuk yang cukup mudah dan memperkenalkan Anda dengan masalah ini. Ini bukan proyek bayi, dan akan mengajarkan Anda banyak hal.

Saya akan merekomendasikan menulisnya dalam C; C adalah lingua franca untuk tingkat pekerjaan itu.


1
Di sisi lain, ini adalah tempat yang bagus untuk bahasa tingkat sangat tinggi. Selama Anda dapat menentukan byte individu dalam suatu file, Anda dapat membuat kompiler / assembler (yang lebih mudah) dalam bahasa apa pun. Katakan, perl. Atau VBA. Surga, kemungkinannya!
Ian

1

Lihat buku Kenneth Louden, "Konstruksi Penyusun"

http://www.cs.sjsu.edu/~louden/cmptext/

Ini memberikan pendekatan langsung yang lebih baik untuk pengembangan kompiler.

Orang belajar dengan melakukan. Hanya sejumlah kecil yang dapat melihat simbol yang tertulis di papan tulis dan melompat langsung dari teori ke praktik. Sayangnya, orang-orang itu sering dogmatis, fundamentalis, dan paling keras tentang hal itu.


1

Saya diberkati karena terkena PDP-8 sebagai bahasa majelis pertama saya. PDP-8 hanya memiliki enam instruksi, yang sangat sederhana sehingga mudah untuk membayangkan mereka dilaksanakan oleh beberapa komponen rahasia, yang sebenarnya mereka. Itu benar-benar menghapus "keajaiban" dari komputer.

Gerbang lain menuju wahyu yang sama adalah bahasa campuran "campuran" yang digunakan Knuth dalam contohnya. "Mix" tampaknya kuno hari ini, tetapi masih memiliki efek DE-mistifying.


0

Kompiler dan bahasa pemrograman (dan semuanya termasuk dalam membangun satu - seperti mendefinisikan tata bahasa yang terbatas dan konversi ke perakitan) adalah tugas yang sangat kompleks yang membutuhkan banyak pemahaman tentang sistem secara keseluruhan. Jenis kursus ini biasanya ditawarkan sebagai kelas Comp Sci tahun ke-3 / ke-4 di Universitas.

Saya akan sangat menyarankan Anda terlebih dahulu mendapatkan pemahaman yang lebih baik tentang Sistem Operasi secara umum dan bagaimana bahasa yang ada dikompilasi / dieksekusi (mis. Asli (C / C ++), dalam VM (Java) atau oleh seorang juru bahasa (Python / Javascript)).

Saya percaya kami menggunakan buku Konsep Sistem Operasi oleh Abraham Silberschatz, Peter B. Galvin, Greg Gagne dalam kursus Sistem Operasi saya (pada tahun ke-2). Ini adalah buku yang sangat bagus yang memberikan panduan menyeluruh dari setiap komponen sistem operasi - agak mahal tapi sepadan dan salinan yang lebih lama / bekas harus beredar.


Konsep OS? Sangat sedikit dari yang dibutuhkan untuk membangun kompiler. Apa yang dibutuhkan adalah pemahaman arsitektur perangkat lunak: alamat ruang, tumpukan, utas (jika dia ingin belajar kompiler, dia lebih baik belajar tentang paralelisme, masa depannya).
Ira Baxter

Segera setelah mengatakan dia ingin belajar desain dan kompiler bahasa, dia bilang dia ingin belajar tentang OS.
David Thornley

@ Isa - setuju. Saya tidak pernah menyatakan bahwa memahami OS diperlukan untuk membangun kompiler / bahasa, hanya menjelaskan bahwa itu mungkin merupakan titik awal yang lebih mudah. Semua orang fokus pada aspek 'kompiler' dari pertanyaannya, tetapi dia juga menyebutkan bahwa dia ingin pemahaman yang lebih baik tentang OS dan perpustakaan. Untuk anak berusia 15 tahun yang masih belajar tentang arsitektur, akan jauh lebih berguna untuk memahami manajemen memori, threading, penguncian, i / o, dll. Daripada belajar bagaimana mendefinisikan tata bahasa dengan yacc (IMHO)
plafond

Maaf ... melewatkan titik tentang ingin belajar tentang (membangun?) OS. Maksud saya berdiri: dia tidak membutuhkan banyak pengetahuan OS untuk kompiler. Faktanya, ini merupakan topik yang sangat berbeda, kecuali di mana kompiler dan OS berinteraksi untuk mencapai beberapa tujuan kolektif. (Multics memerlukan kompiler PL / 1 untuk membangun pemanggilan fungsi dengan cara tertentu untuk mengaktifkan VM global, misalnya).
Ira Baxter

0

Ini adalah topik besar tetapi daripada mengabaikan Anda dengan sombong "baca buku, Nak", sebagai gantinya saya akan dengan senang hati memberi Anda petunjuk untuk membantu Anda membungkus kepala Anda di sekitarnya.

Kebanyakan kompiler dan / atau penerjemah bekerja seperti ini:

Tokenize : Memindai teks kode dan memecahnya menjadi daftar token.

Langkah ini bisa rumit karena Anda tidak bisa hanya membagi string pada spasi, Anda harus mengenali bahwa itu if (bar) foo += "a string";adalah daftar 8 token: WORD, OPEN_PAREN, WORD, CLOSE_PAREN, WORD, ASIGNMENT_ADD, STRING_LITERAL, TERMINATOR. Seperti yang Anda lihat, hanya dengan memecah kode sumber pada spasi tidak akan berhasil, Anda harus membaca setiap karakter sebagai urutan, jadi jika Anda menemukan karakter alfanumerik Anda terus membaca karakter sampai Anda menekan karakter non-alfanumerik dan string yang Anda baca saja adalah KATA yang akan diklasifikasikan lebih lanjut nanti. Anda dapat memutuskan sendiri seberapa rinci tokenizer Anda: apakah menelan "a string"sebagai satu token yang disebut STRING_LITERAL untuk diuraikan lebih lanjut nanti, atau apakah ia melihat"a string" sebagai OPEN_QUOTE, UNPARSED_TEXT, CLOSE_QUOTE, atau apa pun, ini hanyalah salah satu dari banyak pilihan yang harus Anda putuskan sendiri saat Anda mengodekannya.

Lex : Jadi sekarang Anda memiliki daftar token. Anda mungkin menandai beberapa token dengan klasifikasi ambigu seperti WORD karena selama pass pertama Anda tidak menghabiskan terlalu banyak usaha untuk mencari tahu konteks dari setiap string karakter. Jadi sekarang bacalah daftar token sumber Anda lagi dan reklasifikasi masing-masing token ambigu dengan jenis token yang lebih spesifik berdasarkan kata kunci dalam bahasa Anda. Jadi Anda memiliki KATA seperti "jika", dan "jika" ada dalam daftar kata kunci khusus Anda yang disebut simbol JIKA sehingga Anda mengubah jenis simbol token itu dari WORD ke IF, dan setiap WORD yang tidak ada dalam daftar kata kunci khusus Anda , seperti WORD foo, adalah IDENTIFIER.

Parse : Jadi sekarang Anda membalikkan if (bar) foo += "a string";daftar token lexed yang terlihat seperti ini: JIKA OPEN_PAREN IDENTIFER CLOSE_PAREN IDENTIFIER ASIGN_ADD STRING_LITERAL TERMINATOR. Langkah ini mengenali urutan token sebagai pernyataan. Ini penguraian. Anda melakukan ini menggunakan tata bahasa seperti:

PERNYATAAN: = ASIGN_EXPRESSION | IF_STATEMENT

IF_STATEMENT: = IF, PAREN_EXPRESSION, STATEMENT

ASIGN_EXPRESSION: = IDENTIFIER, ASIGN_OP, VALUE

PAREN_EXPRESSSION: = OPEN_PAREN, VALUE, CLOSE_PAREN

VALUE: = IDENTIFIER | STRING_LITERAL | PAREN_EXPRESSION

ASIGN_OP: = EQUAL | ASIGN_ADD | ASIGN_SUBTRACT | ASIGN_MULT

Produksi yang menggunakan "|" antara istilah berarti "cocok dengan semua ini", jika ada koma di antara istilah itu berarti "cocok dengan urutan istilah ini"

Bagaimana Anda menggunakan ini? Dimulai dengan token pertama, cobalah untuk mencocokkan urutan token Anda dengan produksi ini. Jadi pertama-tama Anda mencoba mencocokkan daftar token Anda dengan PERNYATAAN, jadi Anda membaca aturan PERNYATAAN dan itu mengatakan "PERNYATAAN adalah ASIGN_EXPRESSION atau IF_STATEMENT" sehingga Anda mencoba untuk mencocokkan ASIGN_EXPRESSION terlebih dahulu, sehingga Anda mencari aturan tata bahasa untuk ASIGN_EXPRESSION dan dikatakan "ASIGN_EXPRESSION adalah IDENTIFIER diikuti oleh ASIGN_OP diikuti oleh VALUE, jadi Anda mencari aturan tata bahasa untuk IDENTIFIER dan Anda melihat tidak ada tata bahasa untuk IDENTIFIER sehingga berarti IDENTIFIER" terminal "yang berarti itu tidak memerlukan lebih lanjut parsing untuk mencocokkannya sehingga Anda dapat mencoba untuk mencocokkannya langsung dengan token Anda. Tapi token sumber pertama Anda adalah IF, dan IF tidak sama dengan IDENTIFIER jadi pertandingan gagal. Apa sekarang? Anda kembali ke aturan PERNYATAAN dan mencoba mencocokkan istilah berikutnya: IF_STATEMENT. Anda mencari IF_STATEMENT, itu dimulai dengan IF, lookup IF, IF adalah terminal, bandingkan terminal dengan token pertama Anda, IF token cocok, terus mengagumkan, istilah berikutnya adalah PAREN_EXPRESSION, cari PAREN_EXPRESSION, itu bukan terminal, apa itu istilah pertama, PAREN_EXPRESSION dimulai dengan OPEN_PAREN, cari OPEN_PAREN, ini terminal, cocokkan OPEN_PAREN dengan token Anda berikutnya, cocok, .... dan seterusnya.

Cara termudah untuk mendekati langkah ini adalah Anda memiliki fungsi yang disebut parse () yang Anda berikan token kode sumber yang Anda coba cocokkan dan istilah tata bahasa yang Anda coba cocokkan dengannya. Jika istilah tata bahasa bukan terminal, maka Anda berulang: Anda memanggil parse () lagi lewat token sumber yang sama dan istilah pertama aturan tata bahasa ini. Inilah sebabnya mengapa ini disebut "parser keturunan rekursif" Fungsi parse () mengembalikan (atau mengubah) posisi Anda saat ini dalam membaca token sumber, itu pada dasarnya meneruskan token terakhir dalam urutan yang cocok, dan Anda melanjutkan panggilan berikutnya untuk parse () dari sana.

Setiap parse () cocok dengan produksi seperti ASIGN_EXPRESSION Anda membuat struktur yang mewakili potongan kode itu. Struktur ini berisi referensi ke token sumber asli. Anda mulai membangun daftar struktur ini. Kami akan menyebut seluruh struktur ini Pohon Sintaksis Abstrak (AST)

Kompilasi dan / atau Jalankan : Untuk produksi tertentu dalam tata bahasa Anda, Anda telah membuat fungsi-fungsi handler yang jika diberi struktur AST, ia akan mengkompilasi atau mengeksekusi potongan AST itu.

Jadi mari kita lihat bagian AST Anda yang bertipe ASIGN_ADD. Jadi sebagai penerjemah, Anda memiliki fungsi ASIGN_ADD_execute (). Fungsi ini dilewatkan sebagai bagian dari AST yang sesuai dengan parse tree foo += "a string", jadi fungsi ini melihat struktur itu dan tahu bahwa istilah pertama dalam struktur harus IDENTIFIER, dan istilah kedua adalah VALUE, jadi ASIGN_ADD_execute () meneruskan istilah VALUE ke fungsi VALUE_eval () yang mengembalikan objek yang mewakili nilai yang dievaluasi dalam memori, lalu ASIGN_ADD_execute () melakukan pencarian "foo" di tabel variabel Anda, dan menyimpan referensi ke apa pun yang dikembalikan oleh eval_value () fungsi.

Itu penerjemah. Kompiler sebaliknya akan memiliki fungsi handler menerjemahkan AST ke dalam kode byte atau kode mesin alih-alih menjalankannya.

Langkah 1 hingga 3, dan beberapa 4, dapat dibuat lebih mudah menggunakan alat-alat seperti Flex dan Bison. (alias. Lex dan Yacc) tetapi menulis sendiri juru bahasa dari awal mungkin merupakan latihan yang paling memberdayakan yang bisa dicapai oleh setiap programmer. Semua tantangan pemrograman lainnya tampak sepele setelah pertemuan ini.

Saran saya adalah mulai dari yang kecil: bahasa yang kecil, dengan tata bahasa yang kecil, dan coba parsing dan jalankan beberapa pernyataan sederhana, kemudian tumbuh dari sana.

Baca ini, dan semoga berhasil!

http://www.iro.umontreal.ca/~felipe/IFT2030-Automne2002/Complements/tinyc.c

http://en.wikipedia.org/wiki/Recursive_descent_parser


2
Anda membuat apa yang saya anggap sebagai kesalahan klasik ketika orang berpikir tentang kompilasi: yaitu meyakini masalahnya adalah tentang penguraian. PARSING SECARA TEKNIS MUDAH; ada teknologi hebat untuk melakukannya. Bagian yang sulit tentang kompilasi adalah analisis semantik, mengoptimalkan pada level tinggi dan rendah dari representasi program, dan pembuatan kode, dengan penekanan yang semakin besar akhir-akhir ini pada kode PARALLEL. Anda meremehkan ini sepenuhnya dalam jawaban Anda: "kompiler akan memiliki fungsi handler untuk menerjemahkan AST ke dalam kode byte". Ada 50 tahun berlalu teori kompiler dan teknik bersembunyi di sana.
Ira Baxter

0

Bidang komputer hanya rumit karena telah memiliki waktu untuk berkembang ke berbagai arah. Pada intinya itu hanya tentang mesin yang menghitung.

Komputer dasar favorit saya adalah Komputer Relai Harry Porter . Ini memberi rasa bagaimana komputer bekerja di tingkat dasar. Kemudian Anda dapat mulai menghargai mengapa hal-hal seperti bahasa dan sistem operasi diperlukan.

Masalahnya, sulit untuk memahami apa pun tanpa memahami apa yang membutuhkannya . Semoga beruntung, dan jangan hanya membaca hal-hal. Lakukan hal-hal.



-1

Buku pengantar yang bagus lainnya adalah "Compilerbau" karya N. Wirth dari 1986 (konstruksi kompiler) yang panjangnya sekitar 100 halaman dan menjelaskan kode singkat yang dirancang dengan baik untuk bahasa mainan PL / 0, termasuk parser, generator kode, dan mesin virtual. Ini juga menunjukkan bagaimana menulis parser yang bertuliskan dalam tata bahasa menjadi parse dalam notasi EBNF. Buku ini dalam bahasa Jerman tetapi saya menulis ringkasan dan menerjemahkan kode ke Python sebagai latihan, lihat http://www.d12k.org/cmplr/w86/intro.html .


-1

Jika Anda tertarik untuk memahami esensi dari bahasa pemrograman, saya sarankan Anda bekerja melalui buku PLAI (http://www.cs.brown.edu/~sk/Publications/Books/ProgLangs/) untuk memahami konsep dan implementasi mereka. Ini juga akan membantu Anda dengan desain bahasa Anda sendiri.


-1

Jika Anda benar-benar tertarik pada kompiler, dan tidak pernah melakukannya sebelumnya, Anda bisa mulai dengan merancang kalkulator untuk menghitung rumus aritmatika (sejenis DSL seperti yang disebutkan Eric). Ada banyak aspek yang perlu Anda pertimbangkan untuk jenis kompiler ini:

  • Nomor yang diizinkan
  • Operator yang diizinkan
  • Prioritas operator
  • Validasi sintaksis
  • Mekanisme pencarian variabel
  • Deteksi siklus
  • Optimasi

Misalnya, Anda memiliki rumus berikut, kalkulator Anda harus dapat menghitung nilai x:

a = 1
b = 2
c = a + b
d = (3 + b) * c
x = a - d / b

Ini bukan kompiler yang sangat sulit untuk memulai, tetapi dapat membuat Anda lebih memikirkan beberapa ide dasar tentang apa itu kompiler, dan juga membantu Anda meningkatkan keterampilan pemrograman Anda, dan mengontrol kualitas kode Anda (ini sebenarnya adalah masalah sempurna yang Pengembangan Test Driven TDD dapat diterapkan untuk meningkatkan kualitas perangkat lunak).

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.