İlk önce kendi dilimi C koduna göre derlemek ne zaman olur?


34

Kendi programlama dilini tasarlarken, kaynak kodunu alan ve C veya C ++ koduna dönüştüren bir dönüştürücü yazmak ne zaman anlamlı olur, böylece makine kodunu elde etmek için gcc gibi mevcut bir derleyiciyi kullanabilir miyim? Bu yaklaşımı kullanan projeler var mı?



4
C'ye bakarsanız, C # ve Java'nın her ikisinin de ara dilleri derlediğini göreceksiniz. Doğrudan bir araya gelmek yerine bir ara dili hedefleyerek başkasının yapmış olduğu birçok işi tekrar yapmak zorunda kalmazsınız.
Casey

1
@emodendroket Bununla birlikte, C # ve Java, genel olarak IL ve özel olarak C # / Java için tasarlanan bir IL'yi derler, bu nedenle birçok yönden CIL ve JVM bayt kodu, C'nin olabileceğinden daha duyarlı ve elverişlidir. Herhangi bir ara dili kullanıp kullanmayacağınız değil, hangi ara dili kullanacağınızla ilgili değil.

1
C kodu üreten birkaç ücretsiz yazılım uygulamasına bakın. Umarım dil uygulamanızı özgür yazılım haline getirirsiniz.
Basile Starynkevitch

2
İşte @ RobertHarvey'in yorumundan güncellenmiş bağlantı: yosefk.com/blog/c-as-an-intermediate-language.html .
Christian Dean

Yanıtlar:


52

C koduna geçiş yapmak çok iyi kurulmuş bir alışkanlıktır. Sınıfları olan orijinal C (ve daha sonra Cfront adı verilen ilk C ++ uygulamaları ) bunu başarıyla yaptı. Lisp veya Scheme'in birçok uygulaması bunu yapıyor; örneğin Chicken Scheme , Scheme48 , Bigloo . Bazı insanlar Prolog'u C'ye çevirdi . Ve Mozart'ın bazı versiyonları da oldu (ve Ocaml bytecode'u C'ye derlemeye çalıştım ). J.Pitrat'ın yapay zeka CAIA sistemi de önyüklendi ve C kodunu üretti. Vala ayrıca GTK ile ilgili kod için C'ye çevirir. Queinnec'in kitabı Küçük Parçalarla Lisp C’ye çeviri hakkında bazı bölümler var

C'ye çevirirken ortaya çıkan sorunlardan biri, özyinelemeli çağrılardır . C standart (bir "argümanlarla atlama" için, yani bir C derleyicisi bunları düzgün tercüme olduğunu değil garantisi yok olmadan içinde bile, çağrı yığını yeme) bazı durumlarda, GCC (veya Clang ait / LLVM) son sürümlerini bu optimizasyon yapmak .

Diğer bir konu çöp toplamadır . Bazı uygulamalar sadece Boehm muhafazakar çöp toplayıcısını kullanır (ki bu C dostudur ...). Çöp toplamak istiyorsanız (bir kaç Lisp uygulamasının yaptığı gibi, örneğin SBCL gibi) bir kabus olabilir ( dlclosePosix'te istersiniz ).

Yine bir başka konu ise birinci sınıf süreklilik ve çağrı / cc ile ilgilenmektir . Ancak akıllı hileler mümkündür (Tavuk Şeması'nın içine bakın). Çağrı yığınına erişmek bir çok püf noktası gerektirebilir (ancak GNU backtrace , vb. Bakınız ). Sürekliliğin ortogonal kalıcılığı (örneğin yığınlar veya iplikler) C'de zor olacaktır.

İstisnaların ele alınması çoğu zaman longjmp vb.

(Verilmiş C kodunuzda) uygun #linedirektifler oluşturmak isteyebilirsiniz . Bu çok sıkıcı ve çok çalışma gerektiriyor (örneğin, daha kolay bir şekilde gdbhata ayıklama kodu üretmesini isteyeceksiniz).

Benim ERİME lispy alanı belirli bir dil (özelleştirmek veya genişletmek için GCC ) (şimdi ++ aslında fakir C) C çevrilmiştir. Kendi nesillerce kopyalayan çöp toplayıcı var. ( Qish veya Ravenbrook MPS tarafından ilginizi çekebilir ). Aslında, nesilsel GC, makine tarafından üretilen C kodunda elle yazılmış C kodundan daha kolaydır (çünkü C kodu üretecinizi yazma engeliniz ve GC makineniz için uyarlarsınız).

Orijinal C ++ koduna çeviren herhangi bir dil uygulamasını bilmiyorum , yani birçok STL şablonu kullanarak ve RAII deyimini dikkate alarak C ++ kodunu yayınlamak için bazı "derleme zamanı çöp toplama" tekniğini kullanarak . (Bir tanıyorsanız lütfen söyleyin).

Bugün komik olan, (mevcut Linux masaüstlerinde) C derleyicilerinin C'ye çevrilmiş etkileşimli bir üst düzey okuma-değerlendirme-baskı döngüsünü uygulamak için yeterince hızlı olabileceği : her kullanıcı için C kodu (birkaç yüz satır) göndereceksiniz etkileşim, forkdaha sonra yapacağınız paylaşılan bir nesneye derleyeceksiniz dlopen. (MELT bunu hazırlar ve genellikle yeterince hızlıdır). Bütün bunlar saniyenin onda birini alabilir ve son kullanıcılar tarafından kabul edilebilir.

Mümkün olduğunda, özellikle C ++ derlemesi yavaş olduğu için C ++ 'a değil, C ++' a çevrilmesini tavsiye ederim.

Dilinizi uyguluyorsanız , libjit , GNU yıldırım , asmjit ve hatta LLVM veya GCCJIT gibi bazı JIT kütüphanelerini de (C kodu yaymak yerine) düşünebilirsiniz . C'ye çevirmek istiyorsanız, bazen tinycc kullanabilirsiniz : makine kodunu yavaşlatmak için üretilen C kodunu (bellekte bile) çok hızlı bir şekilde derler . Ancak genel olarak GCC gibi gerçek bir C derleyicisi tarafından yapılan optimizasyonlardan yararlanmak istiyorsunuz.

Dilinizi C'ye çevirirseniz , önce üretilen C kodunun tüm AST'sini bellekte oluşturduğunuzdan emin olun (bu, önce tüm bildirimleri, sonra tüm tanımları ve işlev kodunu oluşturmayı da kolaylaştırır). Bu şekilde bazı optimizasyonlar / normalizasyonlar yapabileceksiniz. Ayrıca, çeşitli GCC uzantılarıyla (örneğin bilgisayarlı goto'lar) ilgilenebilirsiniz. Muhtemelen büyük C fonksiyonları oluşturmaktan kaçınmak isteyeceksiniz - örneğin yüzbinlerce üretilen C satırı - (onları daha küçük parçalara ayırmanız daha iyi olacaktır) çünkü C derleyicileri optimize etmek çok büyük C fonksiyonlarından çok mutsuzdur (pratikte ve deneysel,gcc -Obüyük fonksiyonların derleme zamanı, fonksiyon kod büyüklüğünün karesiyle orantılıdır). Bu nedenle, oluşturulan C işlevlerinin boyutunu her biri birkaç bin satırla sınırlayın.

Hem Clang ( LLVM aracılığıyla ) hem de GCC ( libgccjit aracılığıyla ) C & C ++ derleyicilerinin, bu derleyiciler için uygun bazı iç gösterimler yayınlayacak bir yol sunduğuna dikkat edin, ancak bunu yapmak C (veya C ++) kodunu yayınlamaktan daha zor olabilir; ve her derleyiciye özgüdür.

C'ye çevrilecek bir dil tasarlıyorsanız, muhtemelen kendi dilinizle bir C karışımı oluşturmak için birkaç püf nokta (veya yapı) kullanmak istersiniz. DSL2011 makalem MELT: GCC Derleyicisine Gömülü Çevrilmiş Çevreye Özel Bir Dil size faydalı ipuçları vermelidir.


"Tavuk Şeması" mı kastediyorsunuz?
Robert Harvey,

1
Evet, URL’yi verdim.
Basile Starynkevitch

Java veya başka bir şey gibi sanal bir makine yapmak, bytecode'u C'ye derlemek ve ardından JIT derlemesi için gcc kullanmak pratik midir? Yoksa doğrudan bytecode'dan montaja mı gitmeliler?
Panzercrisis

1
@Panzercrisis Çoğu JIT derleyicisi, bir fonksiyonun değiştirilmesi ve mevcut kodu bir atlama / tuzak kapısı ile yamalama gibi şeyleri desteklemek için makine kodlarının arka uçlarını gerektirir. Bunun dışında, gcc özellikle ... JIT derlemesi ve diğer kullanım durumlarına mimari olarak daha az uygundur. Ancak libgccjit'i inceleyin: gcc.gnu.org/ml/gcc-patches/2013-10/msg00228.html ve gcc.gnu.org/wiki/JIT

1
Mükemmel oryantasyon malzemesi. Teşekkürler!
capr

7

Tam makine kodu oluşturma zamanının, bir "C" derleyicisi kullanarak "IL" kodunuzu makine koduna derleme ara adımına sahip olmanın zorluğundan ağır basması anlamlıdır.

Genellikle etki alanına özgü diller bu şekilde yazılır, daha sonra çalıştırılabilir veya dll olarak derlenen bir işlemi tanımlamak veya tanımlamak için çok yüksek düzeyde bir sistem kullanılır. Çalışma / iyi montaj üretmek için harcanan zaman C oluşturmaktan çok daha büyüktür ve C performans için montaj koduna oldukça yakındır, bu nedenle C oluşturmak ve C derleyici yazarlarının becerilerini yeniden kullanmak iyi bir anlam ifade eder. Bunun sadece derleme olmadığını, aynı zamanda optimizasyonun da yapıldığını unutmayın - gcc veya llvm yazan adamlar optimize edilmiş makine kodu yapmak için çok zaman harcadılar, tüm sıkı çalışmalarını yeniden icat etmeye çalışmak çok zor olurdu.

IIRC'nin dili nötr olduğu LLVM'nin derleyici arka ucunu yeniden kullanmak daha kabul edilebilir olabilir, bu nedenle C kodu yerine LLVM komutları oluşturursunuz.


Kütüphaneler de bunu düşünmek için oldukça zorlayıcı bir neden gibi görünüyor.
Casey

"IL’niz" derken neyi kastediyorsunuz? Soyut Bir Sözdizimi Ağacı?
Robert Harvey,

@RobertHarvey hayır, C kodunu kastediyorum. OP'lerde bu, kendi yüksek seviye dili ve makine kodu arasında bulunan bir Ara Dildir. Ben birçok insan tarafından kullanılan IL değil (örneğin, Microsoft’un .NET
IL’si

2

Makine kodu üretmek için bir derleyici yazmak, C üreten bir yazıcıdan çok daha zor olmayabilir (bazı durumlarda daha kolay olabilir), ancak makine kodu üreten bir derleyici yalnızca belirli platformlarda çalıştırılabilir programlar üretebilir. yazıldı; aksine, C kodunu üreten bir derleyici, üretilen kodun desteklemesi için tasarlanmış bir C lehçesi kullanan herhangi bir platform için program üretebilir. Pek çok durumda, tamamen taşınabilir ve C standardı tarafından garanti edilmeyen herhangi bir davranış kullanmadan istenildiği şekilde davranacak olan C kodunu yazmanın mümkün olabileceğini, ancak platform garantili davranışlara dayanan kodun çok daha hızlı çalışabileceğini unutmayın. bu garantileri veren platformlarda, verilmeyen kodlardan daha.

Örneğin, bir dilin UInt32keyfi olarak hizalanmış UInt8[], büyük-endian tarzında yorumlanan dört ardışık bayttan bir özelliği verme özelliğini desteklediğini varsayalım . Bazı derleyicilerde, kod şu şekilde yazılabilir:

uint32_t dat = *(__packed uint32_t*)p;
return (dat >> 24) | (dat >> 8) | ((uint32_t)dat << 8) | ((uint32_t)dat << 24));

ve derleyicinin bir sözcük yükleme işlemi yapmasını ve bunu bir ters-by-kelime talimatı ile takip etmesini sağlayın. Bununla birlikte bazı derleyiciler __packed değiştiricisini desteklemeyecek ve yokluğunda işe yaramayacak kod üretecektir.

Alternatif olarak, kod şu şekilde yazılabilir:

return dat[3] | ((uint16_t)dat[2] << 8) | ((uint32_t)dat[1] << 16) | ((uint32_t)dat[0] << 24);

böyle bir kod, herhangi bir platformda, CHAR_BITS8 olmayan yerlerde bile (kaynak verinin her sekiz okunun ayrı bir dizi öğesinde bitmiş olduğu varsayılarak) çalışmalıdır, ancak bu tür kodlar, taşınabilir olmayanlarınki kadar hızlı çalışmayabilir eski destekleyen platformlarda sürüm.

Taşınabilirliğin çoğu zaman bu kodun türevleri ve benzer yapılarla oldukça liberal olmasını gerektirdiğini unutmayın. Örneğin, iki adet 32 ​​bit işaretsiz tamsayıyı çarpmak ve sonucun alt 32 bitini vermek isteyen kod, taşınabilirlik için şu şekilde yazılmalıdır:

uint32_t result = 1u*x*y;

Bu olmadan 1u, INT_BITS'nin 33 ila 64 arasında değiştiği bir sistemdeki bir derleyici, x ve y'nin ürünü 2.147.483.647'den büyükse ve bazı derleyiciler bu fırsatlardan yararlanmaya yatkınsa, istedikleri her şeyi yasal olarak yapabilirdi.


1

Yukarıda bazı mükemmel cevaplarınız var, ancak bir yorumda "Neden öncelikle kendi programlama dilini oluşturmak istiyorsun?" Sorusunu "esasen öğrenme amaçlı olurdu" sorusuyla cevapladınız. m farklı bir açıdan cevap vereceğim.

Sözcük kodunu, sözdizimini ve sözdizimi hakkında daha fazla bilgi edinmek istiyorsanız, kaynak kodunu alan ve C veya C ++ koduna dönüştüren bir dönüştürücü yazmak mantıklı olur, böylece makine kodu ile bitmek için gcc gibi mevcut bir derleyiciyi kullanabilirsiniz Semantik analiz, kod üretme ve optimizasyon hakkında öğrendiğinizden daha fazlası!

Kendi makine kod üreticinizi yazmak, özellikle ilgilendiğiniz şey değilse, C kodunu derleyerek kaçınabileceğiniz çok önemli bir eserdir!

Ancak, eğer derleme programına dahilseniz ve kodu en düşük seviyede optimize etmenin zorluklarından etkilenirseniz, o zaman elbette, öğrenme deneyimi için kendinize bir kod oluşturucu yazın!


-7

Windows kullanıyorsanız, hangi İşletim Sistemini kullandığınıza bağlı olarak, kodunuzu ara dile çeviren Microsoft IL (Orta Dil) vardır, bu nedenle makine koduna derlenmesi zaman almaz. Veya Linux kullanıyorsanız, bunun için ayrı bir derleyici var.

Sorunuza geri dönersek, kendi dilinizi tasarlarken bunun için ayrı bir derleyici veya tercüman bulundurmanız gerekir, çünkü makine yüksek seviyede bir dil bilmez. Makine için kullanışlı olması için kodunuz makine kodunda derlenmelidir


2
Your code should be compiled into machine code to make it useful for machine- Derleyiciniz çıktı olarak c kodu oluşturduysa, makine kodunu üretmek için c kodunu ac derleyicisine koyabilirsiniz, değil mi?
Robert Harvey,

Evet. çünkü makine c dilinde değil
Tayyab Gulsher Vohra

2
Sağ. Bu nedenle, “Makine dilini veya bayt kodunu doğrudan yayınlamak yerine, c yayımlamanın ve ac derleyicisini kullanmanın ne zaman bir anlamı olur?” Sorusudur.
Robert Harvey

aslında "C ya da C ++ koduna dönüştürmesini" istediği programlama dilini tasarlamasını istiyor. Bu yüzden neden kendi derleyicinizi tasarlıyorsanız, neden c derleyicisini veya c ++ 'yı kullanmanız gerektiğini açıklıyorum. eğer yeterince
zekiysen

8
Soruyu anladığını sanmıyorum. Bakınız yosefk.com/blog/c-as-an-intermediate-language.html
Robert Harvey
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.