Saya telah membaca beberapa makalah, artikel, dan bagian 4.1.4, bab 4 dari Penyusun: Prinsip, Teknik, dan Peralatan (Edisi ke-2) (alias "The Dragon Book") yang semuanya membahas topik pemulihan kesalahan kompiler sintaksis. Namun, setelah bereksperimen dengan beberapa kompiler modern, saya telah melihat bahwa mereka juga pulih dari kesalahan semantik , serta kesalahan sintaksis.
Saya cukup mengerti dengan baik algoritma dan teknik di balik kompiler yang pulih dari kesalahan yang terkait secara sintaksis, namun saya tidak benar-benar mengerti bagaimana kompiler dapat pulih dari kesalahan semantik.
Saat ini saya menggunakan sedikit variasi pola pengunjung untuk menghasilkan kode dari pohon sintaksis abstrak saya. Pertimbangkan kompiler saya mengkompilasi ekspresi berikut:
1 / (2 * (3 + "4"))
Compiler akan menghasilkan pohon sintaksis abstrak berikut:
op(/)
|
-------
/ \
int(1) op(*)
|
-------
/ \
int(2) op(+)
|
-------
/ \
int(3) str(4)
Tahap pembuatan kode kemudian akan menggunakan pola pengunjung untuk secara rekursif melintasi pohon sintaksis abstrak dan melakukan pengecekan tipe. Pohon sintaksis abstrak akan dilintasi hingga kompiler sampai ke bagian terdalam dari ekspresi; (3 + "4")
. Kompilator kemudian memeriksa setiap sisi ekspresi dan melihat bahwa mereka tidak setara secara semantik. Kompiler memunculkan kesalahan tipe. Di sinilah masalahnya. Apa yang sekarang harus dilakukan oleh kompiler ?
Agar kompilator pulih dari kesalahan ini dan terus mengetik memeriksa bagian luar ekspresi, ia harus mengembalikan beberapa jenis ( int
atau str
) dari mengevaluasi bagian terdalam dari ekspresi, ke bagian terdalam berikutnya dari ekspresi. Tapi itu tidak memiliki tipe untuk kembali . Karena kesalahan tipe terjadi, tidak ada tipe yang dideduksi.
Salah satu solusi yang mungkin saya dalilkan, adalah bahwa jika kesalahan jenis memang terjadi, kesalahan harus dinaikkan, dan nilai khusus yang menandakan bahwa kesalahan jenis terjadi, harus dikembalikan ke panggilan traversal pohon sintaksis abstrak sebelumnya. Jika panggilan traversal sebelumnya menemukan nilai ini, mereka tahu bahwa kesalahan tipe terjadi lebih dalam di pohon sintaksis abstrak, dan harus menghindari mencoba menyimpulkan suatu tipe. Meskipun metode ini tampaknya berhasil, tampaknya sangat tidak efisien. Jika bagian terdalam dari ekspresi jauh di dalam pohon sintaksis abstrak, maka kompiler harus membuat banyak panggilan rekursif hanya untuk menyadari bahwa tidak ada pekerjaan nyata yang dapat dilakukan, dan hanya kembali dari masing-masing.
Apakah metode yang saya jelaskan di atas digunakan (saya ragu). Jika demikian, apakah itu tidak efisien? Jika tidak, apa sebenarnya metode yang digunakan ketika kompiler pulih dari kesalahan semantik?