Bir derleyici bir tür hatadan tam olarak nasıl kurtarılır?


10

Derleyiciler: İlkeler, Teknikler ve Araçlar (2. Baskı) (aka "Ejderha Kitabı") başlıklı 4.1.4, bölüm 4'teki birkaç makaleyi, makaleyi okudum . Ancak, birkaç modern derleyiciyi denedikten sonra, semantik hatalardan ve sözdizimsel hatalardan da kurtulduklarını gördüm .

Sözdizimsel olarak ilgili hatalardan kurtarma derleyicilerin arkasındaki algoritmaları ve teknikleri oldukça iyi anlıyorum, ancak bir derleyicinin semantik bir hatadan nasıl kurtulabileceğini tam olarak anlamıyorum.

Şu anda benim soyut sözdizim ağacından kod oluşturmak için ziyaretçi desen hafif bir varyasyon kullanıyorum. Derleyicimin aşağıdaki ifadeleri derlediğini düşünün:

1 / (2 * (3 + "4"))

Derleyici aşağıdaki soyut sözdizimi ağacını oluşturur:

      op(/)
        |
     -------
    /       \ 
 int(1)    op(*)
             |
          -------
         /       \
       int(2)   op(+)
                  |
               -------
              /       \
           int(3)   str(4)

Kod oluşturma aşaması, daha sonra soyut sözdizimi ağacını özyinelemede dolaşmak ve tür denetimi yapmak için ziyaretçi desenini kullanır. Soyut sözdizimi ağacı, derleyici ifadenin en iç kısmına gelene kadar geçecektir; (3 + "4"). Derleyici daha sonra ifadelerin her iki tarafını kontrol eder ve anlamsal olarak eşdeğer olmadığını görür. Derleyici bir tür hatası oluşturur. Sorun burada yatmaktadır. Derleyici şimdi ne yapmalı ?

Derleyici Bu hatadan kurtulmak ve ifadelerin dış kısımlarını kontrol türünü devam etmek için, geri dönmek zorunda kalacak bazı tip ( intveya stretmek, ifade içteki bölümünü değerlendiren itibaren) bir sonraki ifadenin en iç kısmında. Ancak geri dönmek için bir türü yoktur . Bir tür hatası oluştuğundan hiçbir tür çıkarılmadı.

Tahmin ettiğim olası bir çözüm, bir tür hatası meydana gelirse, bir hatanın yükseltilmesi ve bir tür hatasının oluştuğunu belirten özel bir değerin önceki soyut sözdizimi ağacı geçiş çağrılarına döndürülmesi gerektiğidir. Önceki geçiş çağrıları bu değerle karşılaşırsa, soyut sözdizimi ağacında daha derin bir tür hatası oluştuğunu bilirler ve bir tür çıkarmaya çalışmaktan kaçınmalıdırlar. Bu yöntem işe yarıyor gibi görünse de, çok verimsiz görünüyor. Bir ifadenin en iç kısmı soyut sözdizimi ağacının derinliklerinde ise, derleyici yalnızca gerçek bir işin yapılamayacağını anlamak ve her birinden geri dönmek için birçok özyinelemeli çağrı yapmak zorundadır.

Yukarıda tarif ettiğim yöntem kullanıldı mı (şüpheliyim). Eğer öyleyse, verimli değil mi? Değilse, derleyiciler anlamsal hatalardan kurtulduğunda kullanılan yöntemler tam olarak nedir?


3
Bunun ne olduğundan emin ve neden yeterince verimli olduğunu düşünmüyorsunuz? Tür denetlemesi yapmak için, derleyici tüm ağaç yürümek zorunda neyse . Anlamsal bir hata daha derleyicidir ve hata bulunduğunda derleyicinin bir dalı ortadan kaldırmasına izin verir.
telastin

Yanıtlar:


8

Önerdiğiniz fikir aslında doğrudur.

Anahtar, bir AST düğümü tipinin sadece bir kez hesaplanması ve daha sonra saklanmasıdır. Ne zaman tipe ihtiyaç duyulursa, saklanan tipi alır. Çözünürlük bir hatayla sonuçlanırsa, bunun yerine bir hata türü kaydedilir.


3

İlginç bir yaklaşım, hatalar için özel bir türe sahip olmaktır. Böyle bir hatayla ilk karşılaşıldığında, bir tanılama günlüğe kaydedilir ve hata türü, ifadenin türü olarak döndürülür. Bu hata türünün bazı ilginç özellikleri vardır:

  • Üzerinde yapılan herhangi bir işlem başarılı olur (aynı orijinal hatanın neden olduğu bir dizi hata mesajı önlemek için)
  • Hata türünde bir nesne üzerinde gerçekleştirilen herhangi bir işlemin sonucu da hata türüne sahiptir
  • Bir hata türü kod oluşturmaya kadar ulaşırsa, kod oluşturucu kullanımı tespit eder ve başarısız olan kodu üretir (örneğin bir istisna atar, iptal eder veya diliniz için uygun olan her şeyi yapar)

Bu kombinasyonla, gerçekten tür hataları içeren kodu başarıyla derleyebilirsiniz ve bu kod gerçekten kullanılmadığı sürece çalışma zamanı hatası oluşmaz. Bu, örneğin, kodun etkilenmeyen kısımları için birim testleri çalıştırmanıza izin vermek için yararlı olabilir.


Cevabınız için teşekkürler Jules. Yeterince komik, kullandığım kesin yöntem bu. Büyük akıllar benzer düşünür ha? ;-)
Christian Dean

2

Anlamsal bir hata varsa, kullanıcıya bunu gösteren bir derleme hata mesajı verilir.

Bu yapıldıktan sonra, giriş programı hatalı olduğu için derlemeyi iptal etmek uygundur - dilde yasal bir program değildir, bu nedenle reddedilebilir.

Bu oldukça sert olsa da, daha yumuşak alternatifler var. Herhangi bir kod oluşturma ve çıktı dosyası oluşturma işlemini iptal edin, ancak daha fazla hata aramak için bir şeyler yapmaya devam edin.

Örneğin, geçerli ifade ağacı için herhangi bir başka tür analizini iptal edebilir ve sonraki ifadelerden ifadeleri işlemeye devam edebilir.


2

Dilinizin tamsayı eklemeye izin verdiğini ve dizelerin işleçle birleştirilmesine izin verdiğini varsayalım +.

Yana int + stringizin verilmez, değerlendiren +bir hata rapor ediliyor sonuçlanacaktır. Derleyici olabilir sadece dönüş errortürü olarak. Veya daha akıllı olabilir, int + int -> intve string + string -> stringizin verildiği için, "hata, int veya string olabilir" döndürebilir.

Sonra *operatör gelir ve sadece int + intizin verildiğini varsayacağız . Derleyici o karar verebilir +aslında dönmek gerekiyordu intve döndürülen tip *sonra olacağını intherhangi bir hata mesajı olmadan.


Sanırım seni takip ediyorum, @gnasher, ama "" operatörü ile tam olarak ne demek istiyorsun ? Yazım hatası mıydı?
Christian Dean

@ChristianDean, alıntılarda, oluşturulmak yerine Markdown işaretlemesi olarak yorumlanan bir yıldız işareti var.
JakeRobb

Cevaba, akranım incelendiğinde sorunu çözecek bir düzenleme gönderdim.
JakeRobb
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.