Kami memiliki banyak bahasa pemrograman. Setiap bahasa diuraikan dan sintaks diperiksa sebelum diterjemahkan ke dalam kode sehingga pohon sintaksis abstrak (AST) dibangun.
Kami memiliki pohon sintaksis abstrak ini, mengapa kita tidak menyimpan struktur sintaksis ini alih-alih kode sumber (atau di sebelah kode sumber)?
Dengan menggunakan AST, bukannya kode sumber. Setiap programmer dalam sebuah tim dapat membuat serial pohon ini ke bahasa apa pun yang mereka inginkan (dengan tata bahasa bebas konteks yang sesuai) dan mengurai kembali ke AST ketika mereka selesai. Jadi ini akan menghilangkan perdebatan tentang pertanyaan gaya pengkodean (di mana menempatkan {dan}, di mana meletakkan spasi, lekukan, dll.)
Apa pro dan kontra dari pendekatan ini?
language-agnostic
Calmarius
sumber
sumber
Jawaban:
Spasi dan Komentar
Umumnya AST tidak termasuk spasi, terminator garis, dan komentar.
Pemformatan Bermakna
Anda benar bahwa dalam kebanyakan kasus ini adalah positif (menghilangkan pemformatan perang suci), ada banyak kasus di mana pemformatan kode asli menyampaikan beberapa makna, seperti dalam string literal multi-line dan "kode paragraf" (memisahkan paragraf pernyataan dengan baris kosong).
Kode yang tidak bisa dikompilasi
Sementara banyak parser sangat tangguh terhadap sintaks yang hilang, kode dengan kesalahan sering menghasilkan pohon sintaks yang sangat aneh, yang bagus dan bagus sampai pada titik di mana pengguna memuat ulang file. Pernah membuat kesalahan dalam IDE Anda dan tiba-tiba seluruh file memiliki "squigglies"? Bayangkan bagaimana itu akan dimuat ulang dalam bahasa lain.
Mungkin pengguna tidak melakukan kode yang tidak dapat dipecahkan, tetapi mereka tentu saja perlu menyimpan secara lokal.
Tidak ada dua bahasa yang cocok dengan sempurna
Seperti yang telah ditunjukkan orang lain, hampir tidak ada dua bahasa yang memiliki paritas fitur yang sempurna. Yang paling dekat yang dapat saya pikirkan adalah VB dan C #, atau JavaScript dan CoffeeScript, tetapi meskipun demikian VB memiliki fitur seperti XML Literals yang tidak memiliki padanan yang setara dalam C #, dan konversi JavaScript ke CoffeeScript dapat menghasilkan banyak literal JavaScript.
Pengalaman pribadi:Dalam aplikasi perangkat lunak yang saya tulis, kita sebenarnya perlu melakukan ini, karena pengguna diharapkan untuk memasukkan ekspresi "bahasa Inggris biasa" yang dikonversi ke JS di latar belakang. Kami dianggap hanya menyimpan versi JS, tetapi tidak menemukan cara yang dapat diterima untuk melakukan hal itu sehingga dapat dimuat dan dibongkar dengan benar, sehingga kami akhirnya selalu menyimpan teks pengguna dan versi JS, serta bendera yang menunjukkan jika "plain english "Versi terurai sempurna atau tidak.
sumber
Memang, itu ide yang masuk akal. Microsoft memiliki proyek penelitian pada 1990-an untuk melakukan hal itu .
Beberapa skenario muncul dalam pikiran.
Yang pertama agak sepele; seperti yang Anda katakan, Anda bisa membuat AST dirender ke dalam tampilan yang berbeda tergantung pada preferensi programmer yang berbeda untuk hal-hal seperti spasi dan sebagainya. Tetapi menyimpan AST terlalu banyak untuk skenario itu; cukup tulis sendiri printer cantik. Ketika Anda memuat file ke editor Anda, jalankan printer cantik untuk memasukkannya ke dalam format yang Anda sukai, dan kembali ke format asli ketika Anda menyimpannya.
Yang kedua lebih menarik. Jika Anda dapat menyimpan pohon sintaksis abstrak maka perubahan kode menjadi tidak tekstual melainkan sintaksis. Refactor di mana kode dipindahkan menjadi lebih mudah dimengerti. Sisi buruknya tentu saja bahwa menulis algoritma pohon-diff tidak sepele dan sering harus dilakukan berdasarkan per-bahasa. Teks diff berfungsi untuk hampir semua bahasa.
Yang ketiga lebih seperti apa yang Simonyi bayangkan untuk Intentional Programming: bahwa konsep dasar yang umum untuk bahasa pemrograman adalah apa yang diserialisasi, dan kemudian Anda memiliki pandangan berbeda tentang konsep-konsep yang diberikan dalam bahasa yang berbeda. Meskipun ide yang indah, fakta jeleknya adalah bahwa bahasa cukup berbeda dalam perinciannya sehingga pendekatan penyebut-umum-rendah tidak benar-benar berfungsi.
Jadi, singkatnya, ini adalah ide yang bagus tetapi ini merupakan pekerjaan ekstra yang sangat besar untuk manfaat yang relatif kecil. Itu sebabnya hampir tidak ada yang melakukannya.
sumber
Anda bisa berpendapat bahwa ini adalah kode byte apa yang ada di .NET. Program reflektor Infact redgate menerjemahkan kode byte kembali ke berbagai bahasa pemrograman .NET.
Namun, ada masalah. Sintaks adalah spesifik bahasa sebanyak ada hal-hal yang dapat Anda wakili pada satu bahasa yang tidak memiliki representasi dalam bahasa lain. Ini terjadi di .NET dengan C ++ menjadi satu-satunya bahasa .NET yang memiliki akses ke semua 7 tingkat akses.
Di luar lingkungan .NET itu menjadi jauh lebih rumit. Setiap bahasa kemudian mulai memiliki set sendiri perpustakaan terkait. Tidak mungkin untuk mencerminkan sintaksis generik dalam C dan Java yang mencerminkan eksekusi instruksi yang sama ketika mereka memecahkan masalah simular dengan cara yang sangat berbeda.
sumber
Saya agak menyukai beberapa ide Anda, tetapi Anda terlalu banyak memperkirakan betapa mudahnya menerjemahkan bahasa ke bahasa. Jika semudah itu, Anda bahkan tidak perlu menyimpan AST, karena Anda selalu dapat menguraikan bahasa X ke dalam AST kemudian beralih dari AST ke bahasa Y.
Namun, saya berharap spesifikasi kompiler berpikir lebih banyak tentang mengekspos beberapa AST melalui beberapa jenis API. Hal-hal seperti pemrograman berorientasi aspek, refactoring, dan analisis program statis dapat diimplementasikan melalui API seperti itu, tanpa pelaksana kemampuan tersebut harus mengulang begitu banyak pekerjaan yang sudah dilaksanakan oleh penulis kompiler.
Sungguh aneh seberapa sering struktur data programmer untuk mewakili suatu program adalah sebagai kumpulan file yang berisi string.
sumber
Saya pikir poin yang paling menonjol adalah:
Tidak ada manfaatnya. Anda mengatakan bahwa itu berarti semua orang bisa menggunakan bahasa hewan peliharaan mereka. Tapi itu tidak benar - menggunakan representasi sintaksis pohon akan menghilangkan perbedaan sintaksis saja, tetapi bukan yang semantik. Ia bekerja sampai batas tertentu untuk bahasa yang sangat mirip - seperti VB dan C #, atau Java dan Scala. Tetapi bahkan tidak ada di sana sepenuhnya.
Itu bermasalah. Anda telah memperoleh kebebasan bahasa, tetapi Anda kehilangan kebebasan alat. Anda tidak lagi dapat membaca dan mengedit kode dalam editor teks, atau bahkan IDE apa pun - Anda bergantung pada alat khusus yang berbicara dengan perwakilan AST Anda untuk membaca dan mengedit kode. Tidak ada yang didapat di sini.
Untuk mengilustrasikan poin terakhir ini, lihat RealBasic, yang merupakan implementasi eksklusif dari dialek BASIC yang kuat. Untuk sementara waktu, sepertinya bahasa itu bisa lepas landas, tapi itu sepenuhnya tergantung pada vendor, sampai-sampai Anda hanya bisa melihat kode dalam IDE mereka karena disimpan dalam format non-teks eksklusif. Kesalahan besar .
sumber
astyle
atau UnniversalIndent. Tidak perlu untuk format biner misterius.Saya pikir, jika Anda menyimpan teks dan AST, maka Anda belum benar-benar menambahkan sesuatu yang bermanfaat, karena teks sudah ada dalam satu bahasa, dan AST dapat dengan cepat direkonstruksi dari teks.
Di sisi lain, jika Anda hanya menyimpan AST, Anda kehilangan hal-hal seperti komentar yang tidak dapat dipulihkan.
sumber
Saya percaya idenya menarik dalam teori tetapi tidak terlalu praktis karena bahasa pemrograman yang berbeda mendukung konstruksi yang berbeda yang tidak memiliki padanan dalam bahasa lain.
Misalnya, X ++ memiliki pernyataan 'saat pilih' yang tidak dapat ditulis dalam C # tanpa banyak kode tambahan (kelas tambahan, logika tambahan, dll). http://msdn.microsoft.com/en-us/library/aa558063.aspx
Apa yang saya katakan di sini adalah bahwa banyak bahasa memiliki gula sintaksis yang diterjemahkan dalam blok besar kode bahasa yang sama atau bahkan elemen yang tidak ada sama sekali dalam bahasa lain. Berikut adalah contoh mengapa pendekatan AST tidak akan berfungsi:
Bahasa X memiliki kata kunci K yang diterjemahkan, dalam AST dalam 4 pernyataan: S1, S2, S3 dan S4. AST sekarang diterjemahkan dalam bahasa Y dan seorang programmer mengubah S2. Sekarang apa yang terjadi dengan terjemahan kembali ke X? Kode ini diterjemahkan sebagai 4 pernyataan, bukan satu kata kunci ...
Argumen terakhir yang menentang pendekatan AST adalah fungsi platform: apa yang terjadi ketika suatu fungsi tertanam dalam platform? Seperti .NET's Environment.GetEnvironmentVariable. Bagaimana Anda menerjemahkannya?
sumber
Ada sistem yang dibangun di sekitar gagasan ini: JetBrains MPS . Editor sedikit aneh, atau hanya berbeda, tetapi secara umum itu bukan masalah besar. Masalah terbesar adalah, baik, bahwa tidak teks lagi, sehingga Anda tidak dapat menggunakan salah satu alat berbasis teks normal - editor lain,
grep
,sed
, menggabungkan dan diff alat, dllsumber
Sebenarnya ada beberapa produk, umumnya dikenal sebagai "meja kerja bahasa" yang menyimpan AST dan menyajikan, dalam editor mereka, "proyeksi" AST kembali ke bahasa tertentu. Seperti yang dikatakan @ sk-logic, MPS JetBrains adalah salah satu sistem tersebut. Yang lainnya adalah Intentional Workbench Software Intentional.
Potensi meja kerja bahasa tampaknya sangat tinggi, terutama di bidang bahasa khusus domain, karena Anda dapat membuat proyeksi khusus domain. Sebagai contoh, demo sengaja DSL yang berkaitan dengan listrik yang diproyeksikan sebagai diagram sirkuit - jauh lebih mudah dan lebih akurat bagi pakar domain untuk berdiskusi dan mengkritik daripada sirkuit yang dijelaskan dalam bahasa pemrograman berbasis teks.
Dalam praktiknya, meja kerja bahasa lambat untuk dipahami karena, selain dari pekerjaan DSL, pengembang mungkin lebih suka bekerja dalam bahasa pemrograman yang umum dan umum. Jika dibandingkan head-to-head dengan editor teks atau IDE pemrograman, meja kerja bahasa memiliki banyak overhead dan keuntungan mereka hampir tidak jelas. Tak satu pun dari meja kerja bahasa yang saya lihat memiliki boot yang terikat pada titik di mana mereka dapat dengan mudah memperluas IDE mereka sendiri - yaitu, jika meja kerja bahasa bagus untuk produktivitas, mengapa alat workbench bahasa tidak menjadi lebih baik -dan-lebih baik dengan laju lebih cepat dan lebih cepat?
sumber
Anda telah membaca pikiran saya.
Ketika saya mengambil kursus kompiler, beberapa tahun yang lalu, saya menemukan bahwa jika Anda mengambil AST dan membuat serial, dengan notasi awalan alih-alih notasi infiks biasa, dan menggunakan tanda kurung untuk membatasi seluruh pernyataan, Anda mendapatkan Lisp. Sementara saya belajar tentang Skema (dialek Lisp) dalam studi sarjana saya, saya tidak pernah benar-benar mendapatkan penghargaan untuk itu. Saya benar-benar mendapatkan apresiasi untuk Lisp dan dialeknya, sebagai hasil dari kursus itu.
Masalah dengan apa yang Anda usulkan:
sulit / lambat untuk menyusun AST dalam lingkungan grafis. Lagipula, kebanyakan dari kita bisa mengetik lebih cepat daripada menggerakkan mouse. Namun, pertanyaan yang muncul adalah "bagaimana Anda menulis kode program dengan tablet?" Mengetik pada tablet lambat / rumit, dibandingkan dengan keyboard / laptop dengan keyboard perangkat keras. Jika Anda dapat membuat AST dengan menyeret dan menjatuhkan komponen dari palet ke atas kanvas pada layar yang besar, pemrograman perangkat layar sentuh pada tablet dapat menjadi hal yang nyata.
sedikit / tidak ada alat kami yang ada mendukung ini. Kami memiliki puluhan tahun pengembangan untuk menciptakan IDE yang semakin kompleks dan editor yang semakin cerdas. Kami memiliki semua alat ini untuk memformat ulang teks, membandingkan teks, mencari teks. Di mana alat yang dapat melakukan hal yang setara dengan pencarian ekspresi reguler di pohon? Atau beda dua pohon? Semua hal ini mudah dilakukan dengan teks. Tapi mereka hanya bisa membandingkan kata-katanya. Ubah nama variabel, sehingga kata-katanya berbeda tetapi makna semantiknya sama, dan alat-alat yang berbeda itu mengalami masalah. Alat-alat seperti itu, dikembangkan untuk beroperasi pada AST dan bukan teks, akan memungkinkan Anda untuk lebih dekat dengan membandingkan makna semantik. Itu akan menjadi Hal yang Baik.
sementara mengubah kode sumber program menjadi AST relatif dipahami dengan baik (kami memiliki kompiler dan penerjemah, bukan?), mengubah AST menjadi kode program tidak begitu dipahami dengan baik. Mengalikan dua bilangan prima untuk mendapatkan bilangan komposit yang besar relatif mudah tetapi memfaktorkan bilangan komposit yang besar kembali ke bilangan prima jauh lebih sulit; di situlah kita dengan parsing vs AST dekompilasi. Di situlah perbedaan antar bahasa menjadi masalah. Bahkan dalam bahasa tertentu, ada beberapa cara untuk mendekompilasi AST. Iterasi melalui kumpulan objek dan mendapatkan semacam hasil, misalnya. Gunakan for for, iterasi melalui array? Itu akan kompak dan cepat, tetapi ada batasan. Gunakan semacam Iterator, beroperasi pada Koleksi? Koleksi itu bisa berukuran variabel, yang menambah fleksibilitas dengan mengorbankan kecepatan (mungkin). Peta / Kurangi? Lebih kompleks, tetapi secara implisit diparalelkan. Dan itu hanya untuk Java, tergantung pada preferensi Anda.
Pada waktunya, upaya pengembangan akan dikeluarkan dan kami akan mengembangkan menggunakan layar sentuh dan AST. Mengetik akan menjadi kurang dari keharusan. Saya melihat itu sebagai perkembangan logis dari tempat kita berada, melihat bagaimana kita menggunakan komputer, hari ini, itu akan menyelesaikan # 1.
Kami sudah bekerja dengan pohon. Lisp hanyalah AST serial. XML (dan HTML, dengan ekstensi) hanyalah pohon serial. Untuk melakukan pencarian, kami sudah memiliki beberapa prototipe: XPath dan CSS (masing-masing untuk XML dan HTML). Ketika alat grafis dibuat yang memungkinkan kami membuat pemilih dan pengubah gaya CSS, kami akan menyelesaikan bagian # 2. Ketika penyeleksi tersebut dapat diperluas untuk mendukung regex, kami akan lebih dekat. Masih mencari alat diff grafis yang bagus untuk membandingkan dua dokumen XML atau HTML. Ketika orang mengembangkan alat-alat itu, # 2 akan dapat dipecahkan. Orang-orang sudah mengerjakan hal-hal seperti itu; mereka belum ada di sana.
Satu-satunya cara saya dapat melihat untuk mendekompilasi ASTs ke bahasa pemrograman teks akan menjadi sesuatu yang mencari tujuan. Jika saya memodifikasi kode yang ada, tujuannya mungkin dapat dicapai dengan suatu algoritma yang membuat kode saya yang dimodifikasi sedekat mungkin dengan kode awal (minimal textual diff). Jika saya menulis kode dari awal, tujuannya mungkin kode terkecil, paling ketat (kemungkinan untuk perulangan). Atau mungkin kode yang diparalelkan seefisien mungkin (kemungkinan peta / pengurangan atau sesuatu yang melibatkan CSP). Jadi, AST yang sama dapat menghasilkan kode yang sangat berbeda, bahkan dalam bahasa yang sama, berdasarkan pada bagaimana tujuan ditetapkan. Mengembangkan sistem seperti itu akan menyelesaikan # 3. Ini akan menjadi kompleks secara komputasional, artinya kita mungkin perlu semacam pengaturan client-server,
sumber
Jika maksud Anda adalah untuk menghilangkan perdebatan tentang memformat gaya, maka mungkin yang Anda inginkan adalah editor yang membaca dalam file sumber, memformatnya ke preferensi pribadi Anda untuk tampilan dan pengeditan, tetapi ketika menyimpannya, memformat ulang ke gaya yang dipilih tim menggunakan.
Sangat mudah jika Anda menggunakan editor seperti Emacs . Mengubah gaya pemformatan seluruh file adalah pekerjaan perintah tiga.
Anda juga harus dapat membuat kait untuk secara otomatis mengubah file ke gaya Anda saat memuat, dan mengubahnya menjadi gaya tim saat menyimpan.
sumber
Sulit untuk membaca dan memodifikasi AST, alih-alih kode sumber.
Namun, beberapa alat terkait kompiler memungkinkan untuk menggunakan AST. Java bytecode dan .NET Intermediate code berfungsi mirip dengan AST.
sumber
itu ide yang bagus; tetapi AST masing-masing bahasa berbeda dari yang lain.
satu-satunya pengecualian yang saya tahu adalah untuk VB.NET dan C #, di mana microsoft berpendapat bahwa mereka "bahasa yang sama persis dengan sintaks yang berbeda". Bahkan bahasa .NET lainnya (IronPython, F #, apa pun) berbeda pada tingkat AST.
Hal yang sama dengan bahasa JVM, mereka semua menargetkan bytecode yang sama, tetapi konstruk bahasanya berbeda, menjadikannya bahasa yang berbeda dan AST yang berbeda.
Bahkan bahasa 'lapisan tipis', seperti CoffeScript dan Xtend berbagi banyak teori tentang bahasa yang mendasari (JavaScript dan Java, masing-masing); tetapi memperkenalkan konsep tingkat tinggi yang (atau harus) dipertahankan di tingkat AST.
jika Xtend dapat direkonstruksi dari Java AST, saya pikir itu akan didefinisikan sebagai 'uncompiler' Java-to-Xtend yang secara ajaib membuat abstraksi level yang lebih tinggi dari kode Java yang ada, bukan begitu?
sumber