Turunkan ekspresi reguler untuk C-style / ** / komentar

8

Saya sedang mengerjakan parser untuk bahasa gaya-C, dan untuk parser itu saya perlu ekspresi reguler yang cocok dengan gaya-C / ** / komentar. Sekarang, saya telah menemukan ungkapan ini di web:

/\*([^\*]*\*+[^\*/])*([^\*]*\*+|[^\*]*\*/

Namun, seperti yang Anda lihat, ini adalah ekspresi yang agak berantakan, dan saya tidak tahu apakah itu benar-benar cocok dengan apa yang saya inginkan.

Adakah cara yang berbeda untuk (secara ketat) mendefinisikan ekspresi reguler yang mudah diperiksa dengan tangan bahwa mereka benar-benar benar, dan kemudian dapat dikonversi ('dapat dikompilasi') ke ekspresi reguler di atas?

Alex ten Brink
sumber
2
Perhatikan bahwa pendekatan ini akan mencegah komentar bersarang. Jika Anda membuat parser besar-besaran, Anda mungkin ingin mempertimbangkan parsing komentar blokir "dengan benar". tidak hanya itu menjadi lebih jelas, Anda juga dapat membaca meta-data terstruktur dari komentar jika Anda mau.
Raphael
Apakah fragmen yang (!\*)dimaksudkan? Maksud Anda notasi yang lebih umum [^*]? Dan apa (!*|!/)?
Gilles 'SO- stop being evil'
@Gilles: Saya sudah memperbarui ekspresi. (! * |! /) dimaksudkan untuk menjadi sesuatu yang bukan * atau /.
Alex ten Brink
@Raphael, di komentar C jangan bersarang .
vonbrand
@vonbrand: "C-style" tidak terlalu spesifik, jadi menyebutkan bahwa "peningkatan alami" tidak mungkin adalah titik yang valid.
frafl

Jawaban:

6

Saya dapat memikirkan empat cara:

  1. Tentukan automaton untuk bahasa yang Anda minati. Konversi ekspresi reguler menjadi automaton (menggunakan turunan Brzozowski). Periksa apakah kedua automata menerima bahasa yang sama (tentukan dan perkecil atau gunakan argumen bisimulasi).

  2. Tulis banyak kasus uji dan terapkan ekspresi reguler Anda ke sana.

  3. Ubah otomat yang didefinisikan dalam poin 1 ke ekspresi reguler, menggunakan teknik standar.

  4. Kombinasi di atas.

Dave Clarke
sumber
5

Jika Anda ingin memastikan bahwa Anda menguraikan komentar C, Anda harus berhadapan dengan model Anda dengan spesifikasi C. C99 §6.4.9 mendefinisikan sintaks komentar sebagai berikut:

1. Kecuali dalam konstanta karakter, string literal, atau komentar, karakter /* memperkenalkan komentar. Isi dari komentar semacam itu hanya diperiksa untuk mengidentifikasi karakter multibyte dan untuk menemukan karakter */yang menghentikannya.

2. Kecuali dalam konstanta karakter, string literal, atau komentar, karakter //memperkenalkan komentar yang mencakup semua karakter multibyte hingga, tetapi tidak termasuk, karakter baris baru berikutnya. Isi dari komentar semacam itu hanya diperiksa untuk mengidentifikasi karakter multibyte dan untuk menemukan karakter baris baru yang berakhir.

Ini adalah prosa bahasa Inggris, bukan definisi formal, tetapi ada interpretasi yang cukup jelas dalam hal robot hingga nondeterministic finite (NFA) yang menggunakan komentar:

  • Dari kondisi awal, /diikuti oleh *memasuki kondisi komentar di-multiline, dan /diikuti oleh /memasuki kondisi komentar di-baris-tunggal.
  • Dari status in-multiline-comment, *diikuti oleh /memasuki status post-comment.
  • Dari status in-single-line-comment, baris baru memasuki status pasca-komentar.
  • Karakter lain mana pun tidak mengubah keadaan.

Perhatikan bahwa untuk mengetahui apakah kondisi awal berlaku, Anda harus melakukan sedikit lebih banyak analisis untuk mendeteksi string dan karakter literal.

Setelah memiliki NFA, Anda dapat menggunakan teknik standar untuk membangun ekspresi reguler (Saya tidak melihatnya di artikel Wikipedia, tetapi harus dibahas dalam buku teks).

Jika Anda sudah memiliki ekspresi reguler dan ingin mengujinya, Anda dapat membandingkan bahasa yang dihasilkan dengan yang dari NFA yang disimpulkan dari spesifikasi bahasa: kesetaraan bahasa biasa dapat ditentukan. Salah satu cara untuk memutuskan kesetaraan adalah dengan membangun otomat deterministik minimal untuk masing-masing; jika bahasanya setara, DFA minimal adalah isomorfik.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Pencarian di Google Books memberikan referensi ini untuk algoritme Kleene: books.google.co.uk/...
rgrig
0

Jika Anda menulis parser, hal-hal semacam ini ditangani oleh penganalisa leksikal. Dan di sana Anda dapat mengekspresikan ini dengan ekspresi reguler, atau (seperti flexcontoh yang saya lihat tunjukkan) "lepas ke bahasa yang mendasarinya" dan selesaikan pekerjaan di sana. Yaitu, melihat /*hanya melompat ke depan sampai Anda menemukan */(DFA untuk ini mudah untuk membangun, dan dari sana sebuah fragmen C mudah untuk ditulis).

vonbrand
sumber