Sebuah polyglot adalah sebuah program yang dapat dijalankan dalam 2 atau lebih bahasa pemrograman yang berbeda.
Apa tips umum yang Anda miliki untuk membuat polyglots, atau memilih bahasa yang mudah untuk menulis polyglots untuk tugas tertentu?
Silakan kirim kiat yang dapat diterapkan di sebagian besar situasi. Yaitu mereka seharusnya tidak hanya bekerja di polyglots dari dua bahasa tertentu. (Anda bisa mengirim jawaban untuk pertanyaan polyglot jika Anda memiliki tip yang terlalu spesifik.) Tetapi Anda dapat memperkenalkan fitur-fitur bahasa yang membuatnya mudah digunakan dengan banyak bahasa, atau mudah ditambahkan ke polyglot yang ada.
Silakan kirim satu tip per jawaban. Dan jangan ragu untuk menyarankan edit jika tip khusus bahasa juga berlaku untuk bahasa lain.
Memecah dan menaklukkan
Saat Anda menulis polyglot dalam sejumlah besar bahasa, Anda tidak akan serta merta dapat langsung memisahkan semua kontrol bahasa dari satu sama lain. Jadi, Anda perlu "true polyglot" beberapa bahasa untuk jangka waktu yang lama, memungkinkan kode yang sama dijalankan di masing-masing bahasa. Ada dua aturan utama yang perlu diingat saat Anda melakukan ini:
Aliran kontrol dalam dua bahasa apa pun harus sangat mirip, atau sangat berbeda . Mencoba menangani sejumlah besar aliran kontrol yang disisipkan adalah resep untuk menjadi bingung dan membuat program Anda sulit untuk dimodifikasi. Sebagai gantinya, Anda harus membatasi jumlah pekerjaan yang harus Anda lakukan dengan memastikan bahwa semua program yang ada di tempat yang sama ada untuk alasan yang sama dan dengan senang hati dapat dijalankan secara paralel selama Anda membutuhkannya. Sementara itu, jika suatu bahasa sangat berbeda dari yang lain, Anda ingin pelaksanaannya pindah ke lokasi yang sangat berbeda sesegera mungkin, sehingga Anda tidak perlu mencoba membuat kode Anda sesuai dengan dua model sintaksis yang berbeda sekaligus.
Cari peluang untuk memisahkan satu bahasa, atau sekelompok bahasa yang mirip, dari satu sama lain. Bekerja dari kelompok yang lebih besar ke kelompok yang lebih kecil. Setelah Anda memiliki sekelompok bahasa yang serupa semuanya pada titik tertentu dalam program, Anda harus membaginya di beberapa titik. Pada awal program, Anda mungkin ingin, katakanlah, ingin memisahkan bahasa yang digunakan
#
sebagai penanda komentar dari bahasa yang menggunakan beberapa penanda komentar lainnya. Kemudian, mungkin Anda memiliki titik di mana semua bahasa menggunakanf(x)
sintaks untuk panggilan fungsi, memisahkan perintah dengan titik koma, dan memiliki kesamaan sintaksis yang serupa. Pada titik itu, Anda bisa menggunakan sesuatu yang jauh lebih spesifik-bahasa untuk membaginya, misalnya fakta bahwa Ruby dan Perl tidak memproses urutan pelarian dalam''
string, tetapi Python dan JavaScript melakukannya.Secara umum, alur logis program Anda harus berakhir sebagai pohon, berulang kali dipecah menjadi kelompok bahasa yang lebih mirip satu sama lain. Ini menempatkan sebagian besar kesulitan dalam menulis polyglot tepat di awal, sebelum split pertama. Saat aliran kontrol berkembang semakin banyak, dan bahasa yang berjalan pada titik tertentu semakin mirip, tugas Anda menjadi lebih mudah karena Anda dapat menggunakan sintaksis yang lebih maju tanpa menyebabkan bahasa yang terlibat dengan sintaks-kesalahan.
Contoh yang baik adalah himpunan {JavaScript, Ruby, Perl, Python 3}; semua bahasa ini menerima panggilan fungsi dengan tanda kurung dan dapat memisahkan pernyataan dengan titik koma. Mereka semua juga mendukung
eval
pernyataan, yang secara efektif memungkinkan Anda melakukan kontrol aliran dengan cara yang portabel. (Perl adalah yang terbaik dari bahasa-bahasa ini untuk memisahkan diri dari grup lebih awal, karena ia memiliki sintaks yang berbeda untuk variabel dari yang lain.)sumber
Sembunyikan kode di dalam string literal
Dalam sebagian besar bahasa, string literal sendiri tidak melakukan apa-apa, atau melakukan sesuatu yang dapat dengan mudah dibalik (seperti mendorong string ke stack). Sintaks literal string juga relatif tidak standar, terutama untuk sintaksis alternatif yang digunakan banyak bahasa untuk menangani string dengan baris baru yang disematkan; misalnya, Python memiliki
""" ... """
, Perl memilikiq( ... )
, dan Lua[[ ... ]]
.Ada dua kegunaan utama ini. Pertama adalah untuk memungkinkan Anda melakukan interleave bagian-bagian yang dimaksudkan untuk bahasa yang berbeda melalui memulai string di akhir bagian pertama satu bahasa dan melanjutkannya di awal bagian kedua: itu seharusnya cukup mudah untuk menghindari penutupan string yang tidak sengaja karena variasi dari pembatas string di antara berbagai bahasa. Yang lain adalah bahwa banyak pembatas string kebetulan bermakna sebagai perintah dalam bahasa lain (seringkali lebih dari penanda komentar), sehingga Anda dapat melakukan sesuatu seperti
x = [[4] ]
, yang merupakan tugas tidak berbahaya dalam bahasa yang menggunakan notasi JSON untuk daftar, tetapi yang dimulai string dalam Lua (dan dengan demikian memungkinkan Anda untuk membagi kode Lua dari yang lain, mengingat bahwa itu secara efektif "melompat" ke yang berikutnya]]
).sumber
Mengakhiri program
Anda dapat mengakhiri program secara tiba-tiba dalam satu bahasa sehingga akan mengabaikan kode dalam bahasa lain.
Jadi pada dasarnya format ini bisa digunakan
di mana
end_program_in_languageN
perintah untuk mengakhiri program.Misalnya, dalam jawaban saya dalam Apa yang akan Anda bawa untuk Thanksgiving? , Saya mengakhiri program di Dip, dan kemudian saya menulis kode untuk bahasa lain, V, sehingga penerjemah Dip akan mengabaikannya.
Tetapi kemudian, tidak semua bahasa memiliki perintah yang dapat mengakhiri program begitu saja. Namun, jika bahasa seperti itu memiliki fitur, itu harus digunakan dengan bijak.
Seperti yang disarankan oleh @LuisMendo, Anda dapat membuat kesalahan (jika diizinkan) untuk mengakhiri program jika bahasa tersebut belum memiliki builtin "end program".
sumber
Variabel atau kode di dalam string literal
Literal string yang dikutip ganda sebagian besar tidak berbahaya dalam banyak bahasa. Tetapi dalam beberapa bahasa mereka juga bisa berisi kode.
Di Bash, Anda dapat menggunakan
`...`
(itu tidak mengakhiri program):Di Tcl, Anda dapat menggunakan
[...]
:Di PHP, Anda dapat menggunakan
${...}
(ini menghasilkan kesalahan dalam Bash sehingga harus muncul setelah kode Bash):Di Ruby, Anda dapat menggunakan
#{...}
:Mungkin juga ada yang lain.
Tata bahasa ini tidak kompatibel. Itu berarti Anda dapat meletakkan semua kode bahasa-bahasa ini dalam satu string di lokasi yang tidak berbahaya. Dan itu hanya akan mengabaikan kode yang tidak dikenal dalam bahasa lain dan menafsirkannya sebagai konten string.
Dalam banyak kasus, Anda juga dapat dengan mudah berkomentar karakter kutipan ganda di sana dan membuat polyglot yang lebih tradisional.
sumber
Aliasing variabel
Ini mungkin salah satu trik paling penting (IMO) yang paling penting untuk digunakan, terutama karena dapat menjangkau banyak bahasa.
Contoh:
Ini akan bekerja tidak hanya dalam Javascript, tetapi juga Python, Ruby, dll. Lebih banyak contoh nanti ketika saya memikirkan beberapa yang lain. Tentu saja, saran komentar / suntingan pos dipersilakan.
sumber
alert
keprint
dalam Python (hanya 3) karena sintaksis komentar JS//
,, dapat dengan mudah dikerjakan menjadi program Python, sementara Python#
tidak dapat dikerjakan ke dalam JS.#
komentar berbasisTip ini adalah bagian dari simbol komentar Eksploit dan Blockquotes dalam setidaknya satu bahasa
Saat membuat polyglots dengan banyak bahasa, terutama bahasa yang siap-produksi dan bukan esolang, akan berguna untuk melihat bahasa-bahasa yang digunakan
#
dalam komentar blok atau single-line.#
, dan ada banyak variasi dalam karakter yang mengikuti#
.#
sebagai komentar garis, yang berarti bahwa sesuatu yang dapat memulai blok komentar dalam satu bahasa hanyalah komentar biasa di bahasa lain, sehingga mudah untuk dimasukkan.Berikut daftar ringkasan singkat bahasa yang digunakan
#
dalam komentar blok (tidak lengkap):Untuk lebih banyak contoh, lihat Kode Rosetta .
Berikut ini contoh cepat dan mudah, sebagai demonstrasi:
sumber
#- ... -#
.Perbedaan operator aritmatika
Untuk bahasa yang serupa atau poliglot sederhana, kadang-kadang berguna untuk mencari perbedaan dalam bagaimana bahasa melakukan aritmatika. Ini karena sebagian besar (non-esoterik) bahasa memiliki operator aritmatika infiks dan aritmatika dapat menjadi cara cepat dan mudah untuk memperkenalkan perbedaan.
Sebagai contoh:
^
bitwise XOR dalam beberapa bahasa dan eksponensial dalam bahasa lain/
adalah pembagian integer dalam beberapa bahasa dan divisi floating point dalam bahasa lain-1/2
ada-1
dalam beberapa bahasa (bulat ke bawah) dan0
dalam bahasa lain (bulat ke nol)-1%2
ada-1
dalam beberapa bahasa dan1
lainnya--x
adalah no-op dalam beberapa bahasa (negasi ganda) dan pra-pengurangan dalam bahasa lain1/0
memberikan tak terhingga dalam beberapa bahasa dan kesalahan dalam yang lain1<<64
memberi 0 dalam beberapa bahasa (overflow) dan36893488147419103232
lainnyasumber
x=1;["JS","Python"][--x]
, yang mengembalikan nama bahasa yang digunakan (antara JS dan Python).Gunakan Brainfuck
Hampir semua implementasi BF membuang karakter yang tidak
+-<>[].,
, yang kebetulan menguntungkan kita!BF mungkin adalah salah satu bahasa yang paling mudah digunakan untuk menjadi polyglot karena fitur ini, selama Anda menulis bagian BF terlebih dahulu. Setelah kode BF Anda ditulis, itu hanya masalah pemodelan kode apa pun yang Anda miliki di sekitar struktur BF.
Berikut ini contoh yang sangat sederhana:
Peningkatan dan charcode-output ini cukup banyak "selamanya" (tergantung pada pengaturan runtime). Sekarang jika Anda ingin menulis sepotong kode acak, katakanlah, di JS, Anda bisa melakukannya:
Perhatikan bagaimana JS dicetak di sekitar BF.
Pastikan untuk mengetahui bahwa ini bekerja paling baik jika Anda benar-benar mulai dengan BF; lebih sulit untuk memulai dengan bahasa lain dan mencoba menggabungkan BF.
sumber
[]
diperlukan.x=>
mengubah sel, yang dalam hal ini tidak masalah, tetapi hanya ingin mengatakanGunakan bahasa yang sebagian besar karakternya tidak penting
Ini adalah generalisasi poin Mama Fun Roll tentang BF . Esolang yang mengabaikan sebagian besar karakter sangat berguna dalam polyglots. Juga berguna: esolang di mana sejumlah besar karakter dipertukarkan. Beberapa contoh:
()[]{}<>
. (@
terkadang menyebabkan kesalahan ketika penerjemah mencoba menguraikannya sebagai awal dari bendera debug.)sumber
@
kesalahan itu.exec('''...\t\n\40''')
Waspadai Komentar Blok Bersarang
Terkadang beberapa bahasa akan menggunakan sintaksis yang sama untuk memblokir komentar, yang lebih sering daripada bukan pemecah kesepakatan untuk membuat polyglot dengan dua bahasa. Namun sangat jarang, salah satu bahasa akan memungkinkan komentar blok bersarang, yang dapat disalahgunakan untuk membuat jalur kode terpisah.
Sebagai contoh, pertimbangkan polyglot ini:
Nim dan Lily keduanya menggunakan
#[
dan]#
untuk memulai dan mengakhiri komentar blokir, tetapi hanya Nim yang memungkinkan komentar blokir bersarang.Lily menganggap yang kedua
#[
sebagai bagian dari komentar blok tunggal dan yang pertama]#
sebagai mengakhiri komentar blok. (#
Pernyataan cetak Lily berikut ini adalah komentar garis yang menyembunyikan kode Nim.)Nim sebagai alternatif, melihat
#[]#
komentar blok sebagai bersarang (meskipun kosong) danprint("Lily")#
sebagai komentar blok luar.sumber
Tidak yakin apakah ini diperhitungkan, tetapi ...
Gunakan garis shebang untuk mengubah semuanya menjadi
perl
program yang validMenurut jawaban ini dan dokumentasi Perl, jika Anda meneruskan file apa pun yang dimulai dengan baris shebang
perl
, ia memanggil program yang sesuai untuk menjalankannya. Misalnya, inidieksekusi oleh juru bahasa Python jika Anda menelepon
perl filename.py
.sumber
perl
, itu tidak menjadi program Perl.perl
"? Kedengarannya seperti meme philosoraptor yang baik ...Panggil fungsi yang tidak ada, lalu keluar saat mengevaluasi argumen mereka
Banyak bahasa pemrograman yang dapat menguraikan pengidentifikasi acak diikuti oleh sepasang tanda kurung dengan ekspresi di dalam:
Terkadang, bentuk pengidentifikasi yang dimaksud mungkin diperbaiki, karena diperlukan untuk memberikan kode ke bahasa lain yang Anda gunakan. Itu mungkin pada awalnya tampaknya menimbulkan masalah, jika pengidentifikasi tidak sesuai dengan fungsi yang sebenarnya dimiliki bahasa tersebut.
Namun, banyak bahasa pemrograman akan mengevaluasi argumen fungsi sebelum memeriksa untuk melihat apakah fungsi itu sendiri benar-benar ada (misalnya Lua), dan karenanya Anda dapat menggunakan konstruksi semacam ini; yang Anda butuhkan adalah keluar dari program di suatu tempat di dalam argumen fungsi.
Berikut ini contohnya, dc / Lua polyglot:
c2pq
adalah program dc untuk mencetak 2 dan keluar; Lua melihat ini sebagai nama fungsi, tetapi Lua dapat dicegah dari kesalahan dengan menempatkan perintah keluar dalam argumennya. Keuntungan besar konstruksi ini adalah bahwa tidak seperti tugas (c2pq =
), itu tidak secara otomatis tidak sesuai dengan bahasa di mana nama variabel dimulai dengan sigil; sintaks nama fungsi jauh lebih konsisten di semua bahasa daripada sintaksis nama variabel.sumber