2011-04-11 9 views
8

I İlk baştaDönüştürme Lisp C++

(let ((var 10) 
     (test 12)) 
    (+ 1 1) 
    var) 

, lisp dayalı C++ (şemasının çok küçük bir alt kümesi), ben ifade edelim temsil anlamaya çalışıyorum için derler bir oyuncak dili üzerinde çalışıyorum Tüm exp'leri çalıştırmayı düşündüm, sonra sonuncusunu geri getirdim ama geri dönenler, ifade edip iç içe geçme yeteneğimi öldüreceklerdi, izin vermenin ne için gidileceğini söyleyebilir miyiz?

Ayrıca, kaynak dönüşüm kaynağında bulunan kaynaklara da kısaca değindim, googledim ama tüm elimdeki parmaklar 90 dakikalık şema derleyicisidir.

+0

kullanır yardımcı olabilecek bir blog yazısı olduğunu düşünüyorum daha gelişmiş bir teknik olduğunu Darius Bacon's self-hosting Lisp to C compiler

lambda lifting

, derleme konusunda ve bu bir kapanışla ilgili. Sadece HN'ye gönderildi ve bu soruya geri dönmemi sağladı: http://matt.might.net/articles/closure-conversion/ Tanımladığım naif olandan daha gelişmiş bir teknik ama oldukça açık bir şekilde yazılmış. – spacemanaki

cevap

9

bir yolu lambda olarak tedavi etmektir: Sonra

((lambda (var test) (+ 1 1) var) 10 12) 

bir fonksiyonun ve C karşılık gelen çağrı ++ bu dönüşümü: daha geniş bir bağlamda Yani

int lambda_1(int var, int test) { 
    1 + 1; 
    return var; 
} 

lambda_1(10, 12); 

:

(display (let ((var 10) 
       (test 12)) 
      (+ 1 1) 
      var)) 

olur
display(lambda_1(10, 12)); 

let içinden let dışındaki sözcüksel değişkenlere erişmek gibi çok daha fazla ayrıntı vardır. C++ sözcük olarak iç içe geçmiş işlevleri içermediğinden (örneğin, Pascal'ın aksine), bu ek bir uygulama gerektirir.

-1

Kaynaktan kaynağa çeviri ile ilgili yardımcı araçlar arıyorsanız, ANTLR'u öneririm. Bu en mükemmeldir. Bununla birlikte, gevşek yazılmış bir dilden (lisp) daha az yazılan bir dile (c) nasıl dönüştürüleceğini düşünmeniz gerekir. Örneğin, sorunuzda, 10'un türü nedir? short mu? int? double? let genişletmek için

+0

Kendi Nesne sistemimi aldım 10 C++ tarafındaki bir int olduğunu biliyorum. Çalışma zamanı sırasında ne olduğunu biliyorum –

4

Yuvalanmış lambda s'yi derlemek için saf bir yaklaşım açıklamaya çalışacağım. Bir lambda içine let genişletme Greg'in açıklama beri çok iyidir, ben hiç let değinilmeyecek.BM, ben let türetilmiş form veya makro ve derhal denilen bir lambda forma genişletilir olduğunu varsayıyoruz.

Lisp veya Scheme işlevlerini doğrudan C veya C++ işlevlerine derleme , diğer posterlerdeki sorunlar nedeniyle zor olacaktır. 'a bağlı olarak, yaklaşan C veya C++ tanınabilir olmayacaktır (hatta çok okunabilir).

Bilgisayar Programlarının Yapılandırılması ve Yorumlanması bittikten sonra bir Lisp-to-C derleyicisi yazdım (bu son uygulamalardan biridir ve aslında SICP bayt kodundan C'ye bir çevirici yazdım ve aldım). Yayınladığı C'nin alt kümesi, Lisp işlevlerini hiçbir şekilde ele almak için C işlevlerini kullanmıyordu. Bunun nedeni, SICP'nin 5. bölümdeki kayıt makinesi dilinin C'den çok daha düşük seviye olmasıdır.

Değerlere adları bağlayan bir tür ortamınız olduğunu varsayarak, bu şekilde çağrılan işlevin özünü tanımlayabilirsiniz: işlevin argümanlara bağlı resmi parametrelerle tanımlandığı ortamı genişletmek ve sonra Bu yeni ortamda fonksiyonun bedenini değerlendirir. sıra çağrılan yordam nesnesi olarak,

SICP derleyici olarak

, çevre global değişkeni tutulur ve bir işlev çağrısı için bağımsız değişken listesi tutan diğer küresel değişken vardır (prosedür nesnesi içeren bir tanımlandığı ortama işaretçi) ve bir işlev döndüğünde atlanacak bir etiket. biçimsel parametreleri ve lambda vücut:

Bir lambda ifade derleme zaman, Eğer derleme sırasında bilen iki sözdizimsel bileşen vardır unutmayın.

bir işlev derlenmektedir

, yayılan kod gibi bir şey bu pseudocode görünür: *env* ve *argl* çevre ve argüman listesi tutan genel değişkenlerdir

some-label 
*env* = definition env of *proc* 
*env* = extend [formals] *argl* *env* 
result of compiling [body] 
... 
jump *continue* 

... ve extend bazı olduğunuortamını 'da [formals] numaralı değerlerle eşleştiren işlev (bu uygun bir C++ işlevi olabilir) işlevi.

derlenmiş kod çalıştırılır Sonra

ve kodunuzda başka bir yere bu lambda bir çağrı var, çağrı kuralı dönüşü koymak, *argl* değişken içine argüman listesi değerlendirerek sonucunu koymaktır etiketi *continue* değişkenine ve ardından some-label'a atlayın.

some-label 
*env* = definition env of *proc* 
*env* = extend [formals-outer] *argl* *env* 
another-label 
*env* = definition env of *proc* 
*env* = extend [formals-inner] *argl* *env* 
result of compiling [body-inner] 
... 
jump *continue* 
rest of result of compiling [body-outer] 
... somewhere in here there might be a jump to another-label 
jump *continue* 

Bunu açıklaması biraz zordur ve ben bulanık iş yaptık eminim: İç içe lambda s durumunda

, yayılan kod böyle bir şey görünecektir onun. SICP'nin 5'inci bölümünü anlatan temel bir sloganı benimsemeyen iyi bir örnek düşünemiyorum. Bu cevabı yazmak için zaman harcadığımdan, onu yayınlayacağım ama umutsuzca kafa karıştırıcı olsaydı çok üzgünüm.

SICP ve Lisp in Small Pieces'u kesinlikle öneririm.

SICP, yeni başlayanlar için meta-sirküler yorumlamanın yanı sıra, yorumlayıcıdaki bir dizi varyantı ve üstünü gizlemeye ve karıştırmaya çalıştığım bir bayt kod derleyicisini de kapsar. Bu sadece son iki bölüm, ilk 3 bölüm de iyi. Bu harika bir kitap. Henüz yapmadıysanız kesinlikle okuyun.

LiSP, Şema'da yazılmış bir dizi tercüman, bayt kodu ve derleyiciyi C'ye derler. Arada olduğumu söyleyebilirim ve güven içinde olduğunu söyleyebilirim. Lisp uygulamasıyla ilgilenmek. Bu noktadan biraz tarihli olabilir, ama benim gibi yeni başlayanlar için hala değerlidir. SICP'den daha gelişmiş olsa da, dikkatli olun. Kafamın üzerinde temelde doğru olan anlamsal semantiklerin ortasında bir bölüm katıyor.

Diğer bazı notlar: Bu blogger makalelerin bir demet yazmış Marc Feeley İşte

+1

+1 bunun sadece 'lambda'/uygulamasına çevirmekten çok daha karmaşık olduğunu vurgulamak için – acfoltzer