Bagaimana biasanya komentar diurai?

31

Bagaimana komentar umumnya diperlakukan dalam bahasa pemrograman dan markup? Saya menulis parser untuk beberapa bahasa markup kustom dan ingin mengikuti prinsip paling tidak mengejutkan , jadi saya mencoba menentukan konvensi umum.

Misalnya, haruskah komentar yang tertanam di dalam token 'mengganggu' token atau tidak? Secara umum, adalah sesuatu seperti:

Sys/* comment */tem.out.println()

sah?

Juga, jika bahasanya peka terhadap baris baru, dan komentar menjangkau baris baru, haruskah baris baru dipertimbangkan atau tidak?

stuff stuff /* this is comment
this is still comment */more stuff 

diperlakukan sebagai

stuff stuff more stuff

atau

stuff stuff
more stuff

?

Saya tahu apa yang dilakukan beberapa bahasa tertentu, saya juga tidak mencari pendapat, tetapi saya mencari apakah: apakah ada konsensus umum apa yang secara umum diharapkan oleh mark up sehubungan dengan token dan baris baru?


Konteks khusus saya adalah markup seperti wiki.

Kereta luncur
sumber
Apakah baris baru ada di dalam komentar? Mengapa itu diperlakukan secara berbeda dari karakter lain dalam komentar?
1
@Snowman ada perspektif itu, tetapi di sisi lain jika token 'x' memiliki arti khusus jika token pertama di baris dan tampaknya menjadi token pertama di garis untuk kedua orang yang melihat sumber dan ke parser membaca baris demi baris. Sepertinya dilema jadi saya mengajukan pertanyaan.
Kereta luncur
4
Saya perlu melakukan ini persis dengan spesifikasi beberapa waktu lalu dan menemukan dokumen gcc sebagai sumber yang bagus. Ada beberapa kasus sudut aneh yang mungkin tidak Anda pertimbangkan.
Karl Bielefeldt

Jawaban:

40

Biasanya komentar dipindai (dan dibuang) sebagai bagian dari proses tokenization, tetapi sebelum diuraikan. Sebuah komentar berfungsi seperti pemisah token meskipun tidak ada spasi putih di sekitarnya.

Seperti yang Anda tunjukkan, spesifikasi C secara eksplisit menyatakan bahwa komentar diganti dengan spasi tunggal. Ini hanya spesifikasi-istilah, karena parser dunia nyata tidak akan benar-benar menggantikan apa pun, tetapi hanya akan memindai dan membuang komentar dengan cara yang sama seperti memindai dan membuang karakter spasi. Tapi itu menjelaskan dengan cara sederhana bahwa komentar memisahkan token dengan cara yang sama seperti ruang.

Isi komentar diabaikan, jadi linebreak di dalam komentar multiline tidak berpengaruh. Bahasa yang sensitif terhadap jeda baris (Python dan Visual Basic) biasanya tidak memiliki komentar multiline, tetapi JavaScript adalah satu pengecualian. Sebagai contoh:

return /*
       */ 17

Setara dengan

return 17

tidak

return
17

Komentar baris tunggal mempertahankan jeda baris, yaitu

return // single line comment
    17

setara dengan

return
17

tidak

return 17

Karena komentar dipindai tetapi tidak diuraikan, mereka cenderung tidak bersarang. Begitu

 /*  /* nested comment */ */

adalah kesalahan sintaksis, karena komentar dibuka oleh yang pertama /*dan ditutup oleh yang pertama*/

JacquesB
sumber
3
Dalam sebagian besar bahasa, komentar sebaris ( /* like this */) dianggap sama dengan spasi kosong tunggal, dan komentar yang diakhiri EOL ( // like this) ke baris kosong.
9000
@ JacquesB jadi saya berpikir untuk memperlakukan komentar sebagai diganti secara keseluruhan dari sumber sebagai ruang nol-lebar , yang tampaknya setara dengan apa yang Anda sarankan.
Kereta luncur
1
@artb, ruang biasa seharusnya bekerja dengan baik, dan terletak di halaman kode ASCII.
John Dvorak
@JanDvorak a space akan memengaruhi tampilan dan menghilangkan pemahaman dan lebih dekat ke semantik "sebuah komentar tidak benar-benar ada". Output rendering primer akan berupa HTML sehingga dalam kasus saya ASCII tidak masalah karena browser mendukung Unicode. Yang mengatakan, saya percaya mandat standar C bahwa komentar diganti dengan satu ruang.
Kereta luncur
1
Beberapa bahasa, terutama Racket, memang memiliki komentar multi-baris bersarang: (define x #| this is #| a sub-comment |# the main comment |# 3) xhasil 3.
wchargin
9

Untuk menjawab pertanyaan:

apakah ada konsensus umum apa yang secara umum diharapkan dengan mark up?

Saya akan mengatakan tidak ada yang akan mengharapkan komentar yang tertanam di dalam token menjadi sah.

Sebagai aturan umum, komentar harus diperlakukan sama dengan spasi putih. Setiap tempat yang akan valid untuk memiliki spasi putih juga harus diizinkan untuk memiliki komentar yang melekat. Satu-satunya pengecualian adalah string:

trace("Hello /*world*/") // should print Hello /*world*/

Akan sangat aneh untuk mendukung komentar di dalam string, dan akan membuat mereka bosan!

Connor Clark
sumber
2
Tidak pernah memikirkan string, itu kasus tepi yang bagus. Pikiran saya saat ini melakukan regex sederhana antara komentar mulai dan berakhir dan menggantinya dengan satu ruang. Itu akan membuat Anda tersandung kasus.
Kereta luncur
3
+1 untuk sedikit tentang melarikan diri string. Meskipun, dalam contoh Anda, saya biasanya berharap untuk mencetak Hello /* world*/!daripada menekan pembatas komentar. Juga, selamat datang di Programer!
8bittree
1
Terima kasih 8bittree! Dan itu benar-benar yang saya maksudkan. Lucunya, saya juga harus lolos dari ** dalam jawaban saya ....
Connor Clark
2
@ArtB secara umum, "parsing by subtitusi" menjadi sangat rumit di jalan dengan kasus tepi dan interaksi dengan fitur lain, dan sebaiknya dihindari sejak awal.
hobbs
7

Dalam bahasa yang tidak sensitif spasi putih, karakter yang diabaikan (yaitu spasi putih atau yang merupakan bagian dari komentar) membatasi token.

Jadi misalnya Sys temada dua token, sedangkan Systemsatu. Kegunaan ini mungkin lebih jelas jika Anda membandingkan new Foo()dan newFoo()salah satunya akan membuat instance Foosementara yang lain menelepon newFoo.

Komentar dapat memainkan peran yang sama dengan menjalankan spasi putih, mis. new/**/Foo()Berfungsi sama dengan new Foo(). Tentu saja ini bisa lebih kompleks, misalnya new /**/ /**/ Foo()atau yang lainnya.

Secara teknis, seharusnya memungkinkan untuk memungkinkan komentar di dalam pengidentifikasi, tetapi saya ragu itu sangat praktis.

Sekarang, bagaimana dengan bahasa sensitif ruang-putih?

Python datang ke pikiran dan memiliki jawaban yang sangat sederhana: tidak ada komentar blok. Anda memulai komentar dengan #dan kemudian parser bekerja persis seolah-olah sisa baris tidak ada tetapi hanya baris baru.

Berbeda dengan itu, giok memungkinkan untuk memblokir komentar , di mana blok berakhir ketika Anda kembali ke tingkat indentasi yang sama. Contoh:

body
  //-
    As much text as you want
    can go here.
  p this is no longer part of the comment

Jadi di bidang ini, saya tidak akan mengatakan Anda bisa mengatakan bagaimana hal-hal biasanya ditangani. Apa yang tampaknya menjadi kesamaan, adalah bahwa komentar selalu berakhir dengan end-of-line, yang berarti bahwa semua komentar bertindak persis sama dengan baris baru.

back2dos
sumber
Hmm, baris baru adalah masalah nyata karena kami menggunakan sintaks HTML \ XML untuk komentar sehingga akan multi-baris.
Kereta luncur
3
@ ArtB Jika Anda menggunakan sintaks HTML / XML, mungkin bijaksana untuk hanya menggunakan perilaku mereka.
8bittree
1
@ 8bittree masuk akal, seharusnya memikirkan itu. Saya akan meninggalkan pertanyaan apa adanya karena akan lebih bermanfaat dengan cara ini.
Kereta luncur
3

Di masa lalu saya telah mengubah komentar menjadi token tunggal sebagai bagian dari analisis leksikal. Hal yang sama berlaku untuk string. Dari sana, hidup itu mudah.

Dalam kasus spesifik parser terakhir yang saya buat, aturan pelarian dilewatkan ke rutin parse tingkat atas. Aturan melarikan diri digunakan untuk menangani token seperti token komentar sejalan dengan tata bahasa inti. Secara umum, token ini dibuang.

Konsekuensi dari melakukannya dengan cara ini adalah bahwa contoh yang Anda posting dengan komentar di tengah pengenal, pengenal tidak akan menjadi pengidentifikasi tunggal - ini adalah perilaku yang diharapkan dalam semua bahasa (dari memori) yang telah saya kerjakan .

Kasus komentar dalam string harus ditangani secara implisit oleh analisis leksikal. Aturan untuk menangani string tidak memiliki minat pada komentar, dan dengan demikian komentar tersebut diperlakukan sebagai konten string. Hal yang sama berlaku untuk string (atau kutipan literal) dalam komentar - string adalah bagian dari komentar, yang secara eksplisit merupakan token tunggal; aturan untuk memproses komentar tidak tertarik pada string.

Saya harap masuk akal / membantu.

pengguna202190
sumber
Jadi, jika Anda memiliki kode seperti console.log(/*a comment containing "quotes" is possible*/ "and a string containing /*slash-star, star-slash*/ is possible"), di mana ada kutipan dalam komentar dan sintaks komentar dalam sebuah string, bagaimana lexer tahu tokenize dengan benar? Bisakah Anda mengedit jawaban Anda, memberikan deskripsi umum tentang kasus-kasus itu?
chharvey
1

Itu tergantung pada tujuan apa yang dimiliki parser Anda. Jika Anda menulis parser untuk membangun pohon parse untuk dikompilasi daripada komentar tidak memiliki nilai semantik selain berpotensi memisahkan token (misalnya metode / komentar / (/ komentar /)). Dalam hal ini, itu diperlakukan seperti ruang.

Jika parser Anda adalah bagian dari transpiler yang menerjemahkan satu bahasa sumber ke bahasa sumber lain atau jika parser Anda adalah preprosesor yang mengambil unit kompilasi dalam bahasa sumber, mem-parsing-nya, memodifikasinya dan menulis versi yang diubah kembali dalam bahasa sumber yang sama, komentar seperti hal lain menjadi sangat penting.

Juga jika Anda memiliki informasi meta dalam komentar dan Anda terutama memperhatikan komentar seperti ketika membuat API-dokumentasi seperti JavaDoc, komentar tiba-tiba sangat penting.

Di sini komentar sering dilampirkan pada token itu sendiri. Jika Anda menemukan komentar, Anda melampirkannya sebagai komentar token. Karena token dapat memiliki beberapa token sebelum dan sesudah, itu lagi tujuan-tergantung bagaimana menangani komentar tersebut.

Gagasan membubuhi tanda non-komentar dengan memiliki komentar adalah untuk menghapus komentar dari tata bahasa sama sekali.

Setelah Anda memiliki pohon parse, AST mulai membongkar komentar yang mewakili setiap token dengan AST-Element-nya sendiri tetapi dilampirkan ke AST-Element lain di samping berisi-hubungan yang biasa. Ide yang bagus adalah memeriksa semua implementasi parser / AST untuk bahasa sumber yang tersedia di IDE open-source.

Salah satu implementasi yang sangat baik adalah infrastruktur kompiler Eclipse untuk bahasa Java. Mereka menyimpan komentar selama tokenization dan mewakili komentar dalam AST - sejauh yang saya ingat. Juga, implementasi parser / AST ini mempertahankan pemformatan.

Martin Kersten
sumber