पहली बार C कोड में अपनी भाषा संकलित करने का कोई मतलब नहीं है?


34

खुद की प्रोग्रामिंग भाषा को डिज़ाइन करते समय, यह एक कनवर्टर लिखने के लिए कब समझ में आता है जो स्रोत कोड लेता है और इसे C या C ++ कोड में कनवर्ट करता है ताकि मैं मशीन कोड के साथ समाप्त करने के लिए gcc जैसे मौजूदा संकलक का उपयोग कर सकूं? क्या ऐसी परियोजनाएं हैं जो इस दृष्टिकोण का उपयोग करती हैं?



4
यदि आप पिछले सी को देखते हैं तो आप देखेंगे कि सी # और जावा दोनों भी मध्यवर्ती भाषाओं के लिए संकलित हैं। आपको बहुत से काम फिर से करने से बचाया जाता है जो किसी और ने पहले से ही विधानसभा में सीधे जाने के बजाय एक मध्यवर्ती भाषा को लक्षित करके किया है।
केसी

1
@emodendroket हालांकि, C # और Java एक IL के लिए संकलित किया गया है जो सामान्य रूप से IL के लिए और C # / Java के लिए डिज़ाइन किया गया है, इसलिए कई मायनों में CIL और JVM बाईटेकोड अधिक समझदार और सुविधाजनक हैं क्योंकि एक IL के लिए कभी भी हो सकता है। यह किसी भी मध्यवर्ती भाषा का उपयोग करने के बारे में नहीं है, यह किस मध्यवर्ती भाषा का उपयोग करने के बारे में है।

1
सी कोड उत्पन्न करने वाले कई मुफ्त सॉफ्टवेयर कार्यान्वयन को देखें। और मुझे आशा है कि आप अपनी भाषा के कार्यान्वयन को मुफ्त सॉफ्टवेयर बनाएंगे।
बेसिल स्टारीनेवविच

2
यहाँ @ रॉबर्टहार्वे की टिप्पणी से अद्यतन लिंक दिया गया है: yosefk.com/blog/c-as-an-intermediate-language.html
क्रिश्चियन डीन

जवाबों:


52

C कोड के लिए Tranlating एक बहुत अच्छी तरह से स्थापित आदत है। कक्षाओं के साथ मूल सी (और शुरुआती C ++ कार्यान्वयन, फिर Cfront कहा जाता है ) ने सफलतापूर्वक किया। लिस्प या योजना के कई कार्यान्वयन कि क्या कर रहे हैं, उदाहरण के लिए चिकन योजना , Scheme48 , Bigloo । कुछ लोगों ने प्रोलॉग टू सी का अनुवाद किया । और इसलिए मोजार्ट के कुछ संस्करण आए (और सी को Ocaml बायटेकोड को संकलित करने का प्रयास किया गया है )। J.Pitrat की कृत्रिम बुद्धिमत्ता CAIA प्रणाली भी बूटस्ट्रैप्ड है और इसके सभी C कोड उत्पन्न करती है। जीटीके संबंधित कोड के लिए Vala भी C में अनुवाद करता है। क्विनक की पुस्तक लिस्प इन स्माल पीसेज सी। में अनुवाद के बारे में कुछ अध्याय हैं।

सी में अनुवाद करते समय मुद्दों में से एक पूंछ-पुनरावर्ती कॉल है । सी मानक यह गारंटी नहीं देता है कि एक सी कंपाइलर उन्हें ठीक से अनुवाद कर रहा है ("एक तर्क के साथ कूदें", यानी कॉल स्टैक खाने के बिना ), भले ही कुछ मामलों में, जीसीसी के हाल के संस्करण (या क्लैंग / एलएलवीएम) का अनुकूलन करें। ।

एक और मुद्दा कचरा संग्रह है । कई कार्यान्वयन केवल बोहेम रूढ़िवादी कचरा कलेक्टर (जो सी अनुकूल है ...) का उपयोग करते हैं। यदि आप कलेक्ट कोड को कचरा करना चाहते हैं (जैसे कई लिस्प कार्यान्वयन, जैसे एसबीसीएल) एक बुरा सपना हो सकता है (आप dlcloseपॉज़िक्स पर चाहेंगे )।

फिर भी एक और मुद्दा प्रथम श्रेणी की निरंतरता और कॉल / सीसी से संबंधित है । लेकिन चालाक चालें संभव हैं (चिकन योजना के अंदर देखें)। कॉल-स्टैक तक पहुँचने के लिए बहुत सारी ट्रिक्स की आवश्यकता होती है (लेकिन GNU बैकट्रेस इत्यादि देखें ...)। ओर्थोगोनल हठ निरंतरता की (ढेर या धागे की यानी) सी में मुश्किल होगा

अपवाद हैंडलिंग अक्सर longjmp आदि के लिए चतुर कॉल का उत्सर्जन करने का मामला है ...

आप (अपने उत्सर्जित सी कोड में) उचित #lineनिर्देश उत्पन्न करना चाह सकते हैं । यह उबाऊ है और बहुत काम लेता है (आप चाहते हैं कि उदाहरण के लिए और अधिक आसानी से gdb-debuggable कोड का उत्पादन करें )।

मेरे पिघल lispy डोमेन विशिष्ट भाषा (अनुकूलित या विस्तार करने के लिए जीसीसी ) सेल्सियस के लिए अनुवाद किया है (वास्तव में गरीब सेल्सियस तक ++ अब)। इसका अपना एक जेनरेशनल कॉपी करने वाला कचरा संग्राहक है। (आप Qish या Ravenbrook MPS से दिलचस्पी ले सकते हैं )। दरअसल, जेनेरिक जीसी हाथ से लिखे सी कोड की तुलना में मशीन जनरेट सी कोड में आसान है (क्योंकि आप अपने राइट-बैरियर और जीसी मशीनरी के लिए अपने सी कोड जनरेटर को दर्जी करेंगे)।

मैं किसी भी भाषा कार्यान्वयन को वास्तविक C ++ कोड में अनुवाद करना नहीं जानता , अर्थात कुछ "संकलन-समय कचरा संग्रह" तकनीक का उपयोग करके C ++ कोड का बहुत सारे STL टेम्प्लेट का उपयोग करके और RAII मुहावरे का सम्मान करना । (कृपया बताएं कि क्या आप एक जानते हैं)।

आज जो मजेदार बात है वह यह है कि (वर्तमान लिनक्स डेस्कटॉप पर) C संकलक काफी तेजी से हो सकता है ताकि C के लिए अनुवादित इंटरएक्टिव टॉप लेवल रीड-इवेल-प्रिंट-लूप को लागू किया जा सके : आप हर उपयोगकर्ता पर C कोड (कुछ सौ पंक्तियाँ) का उत्सर्जन करेंगे सहभागिता, आप forkइसे एक साझा वस्तु में संकलित करेंगे , जिसे आप तब करेंगे dlopen। (एमईएलटी कर रहा है कि सभी तैयार हैं, और यह आमतौर पर काफी तेज है)। यह सब कुछ सेकंड का दसवां हिस्सा हो सकता है और एंड-यूजर्स द्वारा स्वीकार्य हो सकता है।

जब संभव हो, मैं C को अनुवाद करने की सलाह दूंगा, C ++ को नहीं, विशेष रूप से क्योंकि C ++ संकलन धीमा है।

अगर आप अपनी भाषा को लागू कर रहे हैं, तो आप भी (सी कोड उत्सर्जन के बजाय) कुछ पर विचार हो सकता JIT तरह पुस्तकालयों libjit , जीएनयू बिजली , asmjit , या यहाँ तक LLVM या GCCJIT । यदि आप सी में अनुवाद करना चाहते हैं, तो आप कभी-कभी टिनीसीसी का उपयोग कर सकते हैं : यह कोड को धीमा करने के लिए बहुत जल्दी उत्पन्न सी कोड (यहां तक ​​कि मेमोरी में) का संकलन करता है । लेकिन सामान्य तौर पर आप एक वास्तविक सी संकलक द्वारा किए गए अनुकूलन का लाभ उठाना चाहते हैं जैसे जीसीसी

यदि आप अपनी भाषा में सी का अनुवाद करते हैं, तो पहले मेमोरी में उत्पन्न सी कोड के पूरे एएसटी का निर्माण करना सुनिश्चित करें (यह भी पहले सभी घोषणाओं को उत्पन्न करना आसान बनाता है, फिर सभी परिभाषाएं और फ़ंक्शन कोड)। आप इस तरह से कुछ अनुकूलन / सामान्यीकरण करने में सक्षम होंगे। इसके अलावा, आप कई GCC एक्सटेंशन (जैसे कंप्यूटेड गोटो) में दिलचस्पी ले सकते हैं । आप संभवतः विशाल सी फ़ंक्शन उत्पन्न करने से बचना चाहते हैं - उदाहरण के लिए उत्पन्न सी की एक सौ हजारों लाइन - (आप बेहतर छोटे टुकड़ों में विभाजित करेंगे) क्योंकि सी कंपाइलर का अनुकूलन बहुत बड़े सी फ़ंक्शन (व्यवहार में,) से बहुत नाखुश हैं प्रयोगात्मक,gcc -Oबड़े कार्यों का संकलन समय फ़ंक्शन कोड आकार के वर्ग के लिए आनुपातिक है)। तो अपने उत्पन्न सी कार्यों के आकार को कुछ हज़ार लाइनों तक सीमित करें।

सूचना है कि दोनों बजना (के माध्यम से LLVM ) और जीसीसी (के माध्यम से libgccjit ) सी और सी ++ compilers किसी तरह कुछ आंतरिक इन compilers के लिए अनुकूल अभ्यावेदन फेंकना प्रस्तुत करते हैं, लेकिन ऐसा करने से हो सकता है (या नहीं) उत्सर्जक सी (या सी ++) कोड की तुलना में कठिन हो सकता है, और प्रत्येक संकलक के लिए विशिष्ट है।

यदि C को अनुवादित करने के लिए कोई भाषा डिज़ाइन की जा रही है, तो आप संभवतः अपनी भाषा के साथ C के मिश्रण को उत्पन्न करने के लिए कई तरकीबें (या निर्माण) करना चाहते हैं। मेरा DSL2011 पेपर MELT : एक ट्रांसलेटेड डोमेन विशिष्ट भाषा जो GCC कंपाइलर में एंबेडेड है, आपको उपयोगी संकेत देना चाहिए।


क्या आप "चिकन योजना" की बात कर रहे हैं?
रॉबर्ट हार्वे

1
हाँ.मैंने URL दिया।
बेसिल स्टायरनेविच 17

क्या यह वर्चुअल मशीन बनाने के लिए जावा या किसी चीज़ की तरह अपेक्षाकृत व्यावहारिक है, जो बायटेकोड को C से संकलित करता है, फिर JIT संकलन के लिए gcc का उपयोग करता है? या वे बस सीधे बायटेकोड से विधानसभा तक जाना चाहिए?
Panzercrisis

1
@Panzercrisis अधिकांश JIT कंपाइलर्स को किसी फ़ंक्शन को बदलने और मौजूदा कोड को जंप / ट्रैप डोर से पैच करने जैसी चीजों का समर्थन करने के लिए अपने मशीन कोड बैकएंड की आवश्यकता होती है। इसके अलावा, जीसीसी विशेष रूप से है ... वास्तुकला में जेआईटी संकलन और अन्य उपयोग के मामलों के लिए कम अनुकूल है। हालांकि libgccjit की जाँच करें: gcc.gnu.org/ml/gcc-patches/2013-10/msg00228.html और gcc.gnu.org/wiki/JIT

1
महान अभिविन्यास सामग्री। धन्यवाद!
capr

7

यह समझ में आता है जब पूर्ण मशीन कोड उत्पन्न करने का समय एक सी संकलक का उपयोग करके मशीन कोड में अपने "आईएल" को संकलित करने के एक मध्यवर्ती चरण की असुविधा को दूर करता है।

आमतौर पर डोमेन-विशिष्ट भाषाएं इस तरह से लिखी जाती हैं, एक उच्च स्तरीय प्रणाली का उपयोग उस प्रक्रिया को परिभाषित करने या उसका वर्णन करने के लिए किया जाता है जिसे तब निष्पादन योग्य या डीएल में संकलित किया जाता है। कामकाजी / अच्छी असेंबली के निर्माण में लगने वाला समय C जनरेट करने से बहुत अधिक है, और C प्रदर्शन के लिए असेंबली कोड के काफी करीब है, इसलिए C को जेनरेट करना और C कंपाइलर लेखकों के कौशल का फिर से उपयोग करना अच्छा लगता है। ध्यान दें कि यह सिर्फ संकलन नहीं है, बल्कि अनुकूलन भी है - जो लोग gcc या llvm लिखते हैं, उन्होंने अनुकूलित मशीन कोड बनाने में बहुत समय बिताया है, यह उनकी सारी मेहनत पर लगाम लगाने की कोशिश करेगा।

यह LLVM के संकलक बैकएंड का उपयोग करने के लिए अधिक स्वीकार्य हो सकता है जो IIRC भाषा तटस्थ है, इसलिए आप C कोड के बजाय LLVM निर्देश उत्पन्न करते हैं।


पुस्तकालयों की तरह लगता है कि यह भी एक बहुत सम्मोहक कारण हैं।
केसी

जब आप "अपने 'आईएल' कहते हैं, तो आप किस बारे में बात कर रहे हैं? एक सार सिंटेक्स ट्री?
रॉबर्ट हार्वे

@RobertHarvey नहीं, मेरा मतलब है सी कोड। ओपी के मामले में, यह अपनी उच्च-स्तरीय भाषा और मशीन कोड के बीच एक मध्यवर्ती भाषा है। मैंने इसे इस विचार के प्रयास के लिए उद्धृत किया है कि इसका आईएल नहीं है जैसा कि कई लोगों द्वारा उपयोग किया जाता है (उदाहरण के लिए Microsoft का .NET IL)
gbjbaanb

2

मशीन कोड का उत्पादन करने के लिए एक कंपाइलर लिखना एक सी लिखने वाले की तुलना में अधिक कठिन नहीं हो सकता है (जो कुछ मामलों में यह आसान हो सकता है) सी का उत्पादन करता है, लेकिन एक कंपाइलर जो मशीन कोड का उत्पादन करता है वह केवल विशेष प्लेटफॉर्म पर रन करने योग्य प्रोग्राम का उत्पादन करने में सक्षम होगा जिसके लिए यह लिखा था; एक संकलक, जो इसके विपरीत सी कोड का उत्पादन करता है, किसी भी प्लेटफ़ॉर्म के लिए प्रोग्राम का उत्पादन करने में सक्षम हो सकता है जो सी की एक बोली का उपयोग करता है जिसे उत्पन्न कोड का समर्थन करने के लिए डिज़ाइन किया गया है। ध्यान दें कि कई मामलों में सी कोड लिखना संभव हो सकता है जो पूरी तरह से पोर्टेबल है और जो सी मानक द्वारा गारंटीकृत व्यवहार के बिना किसी भी व्यवहार का उपयोग किए बिना वांछित व्यवहार करेगा, लेकिन जो कोड प्लेटफॉर्म-गारंटीकृत व्यवहारों पर निर्भर करता है वह बहुत तेजी से चलाने में सक्षम हो सकता है। उन प्लेटफार्मों पर जो कोड की तुलना में उन गारंटियों को बनाते हैं जो नहीं करते हैं।

उदाहरण के लिए, मान लीजिए कि एक भाषा बड़े-एंडियन फैशन में व्याख्या UInt32की गई एक मनमाने ढंग से गठबंधन की लगातार चार बाइट्स से उपज की सुविधा का समर्थन करती है UInt8[]। कुछ संकलक पर, कोई इस प्रकार कोड लिख सकता है:

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

और कंपाइलर एक वर्ड-लोड ऑपरेशन उत्पन्न करता है, जिसके बाद एक रिवर्स-बाइट्स-इन-वर्ड निर्देश होता है। हालाँकि, कुछ संकलक, __ पैक किए गए संशोधक का समर्थन नहीं करेंगे और इसके अभाव में ऐसा कोड उत्पन्न करेंगे जो काम नहीं करेगा।

वैकल्पिक रूप से, कोई इस रूप में कोड लिख सकता है:

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

इस तरह के कोड को किसी भी प्लेटफ़ॉर्म पर काम करना चाहिए, यहां तक ​​कि जहां CHAR_BITS8 नहीं है (यह मानते हुए कि स्रोत डेटा के प्रत्येक ऑक्टेट एक अलग सरणी तत्व में समाप्त हो गया है), लेकिन इस तरह के कोड संभवतः गैर-पोर्टेबल के रूप में तेजी से नहीं चल सकते हैं पूर्व का समर्थन करने वाले प्लेटफार्मों पर संस्करण।

ध्यान दें कि पोर्टेबिलिटी के लिए अक्सर यह आवश्यक होता है कि कोड टाइपकास्ट और समान निर्माणों के साथ बेहद उदार हो। उदाहरण के लिए, कोड जो दो 32-बिट अहस्ताक्षरित पूर्णांक को गुणा करना चाहता है और परिणाम के निचले 32 बिट्स को पोर्टेबिलिटी के लिए लिखा जाना चाहिए:

uint32_t result = 1u*x*y;

उसके बिना 1u, एक सिस्टम पर एक कंपाइलर जहां INT_BITS 33 से 64 तक होता था, वैध रूप से ऐसा कुछ भी कर सकता था, अगर x और y का उत्पाद 2,147,483,647 से बड़ा था, और कुछ कंपाइलर्स ऐसे अवसरों का लाभ उठाने के लिए प्रवण हैं।


1

आपके पास ऊपर कुछ उत्कृष्ट उत्तर हैं लेकिन यह देखते हुए कि, एक टिप्पणी में, आपने इस सवाल का जवाब दिया कि "आप पहली बार में अपनी खुद की एक प्रोग्रामिंग भाषा क्यों बनाना चाहते हैं?" के साथ "यह मुख्य रूप से सीखने के उद्देश्य के लिए होगा," मैं ' मैं एक अलग कोण से जवाब देने जा रहा हूं।

यह एक कनवर्टर लिखने के लिए समझ में आता है जो स्रोत कोड लेता है और इसे C या C ++ कोड में परिवर्तित करता है, ताकि आप मशीन कोड के साथ समाप्त करने के लिए gcc जैसे मौजूदा संकलक का उपयोग कर सकें, यदि आप lexical, वाक्यविन्यास के बारे में सीखने में अधिक रुचि रखते हैं कोड पीढ़ी और अनुकूलन के बारे में सीखने की तुलना में आप शब्दार्थ विश्लेषण!

अपना खुद का मशीन कोड जनरेटर लिखना एक बहुत ही महत्वपूर्ण काम है जिसे आप सी कोड के संकलन से बचा सकते हैं, यदि यह वह नहीं है जो आप मुख्य रूप से करते हैं!

यदि, हालांकि, आप असेंबली प्रोग्राम में हैं और सबसे निचले स्तर पर कोड के अनुकूलन की चुनौतियों से मोहित हैं, तो हर तरह से, सीखने के अनुभव के लिए खुद को एक कोड जनरेटर लिखें!


-7

यह इस बात पर निर्भर करता है कि यदि आप विंडोज का उपयोग कर रहे हैं तो आप किस ऑपरेटिंग सिस्टम का उपयोग कर रहे हैं, एक Microsoft IL (इंटरमीडिएट भाषा) है जो आपके कोड को मध्यवर्ती भाषा में परिवर्तित करता है ताकि मशीन कोड में संकलित होने में समय न लगे। या यदि आप लिनक्स का उपयोग कर रहे हैं तो उसके लिए एक अलग संकलक है

अपने सवाल पर वापस आना तब है जब आप अपनी भाषा डिज़ाइन करते समय आपके पास इसके लिए एक अलग संकलक या दुभाषिया होना चाहिए क्योंकि मशीन उच्च स्तरीय भाषा नहीं जानती है। मशीन के लिए उपयोगी बनाने के लिए आपके कोड को मशीन कोड में संकलित किया जाना चाहिए


2
Your code should be compiled into machine code to make it useful for machine- यदि आपके संकलक ने आउटपुट के रूप में c कोड का उत्पादन किया है, तो आप मशीन कोड का उत्पादन करने के लिए c कोड को ac संकलक में डाल सकते हैं, है ना?
रॉबर्ट हार्वे

हाँ। क्योंकि मशीन सी भाषा नहीं है
तैयब गुलशेर वोहरा

2
सही। तो सवाल यह था कि "मशीन भाषा या बाइट को सीधे छोड़ने के बजाए, सी कंपाइल और एसी कंपाइलर का उपयोग करना कब समझ में आता है?"
रॉबर्ट हार्वे

वास्तव में वह अपनी प्रोग्रामिंग भाषा डिजाइन करने के लिए कह रहा है जिसमें वह पूछ रहा है कि "इसे C या C ++ कोड में कनवर्ट करता है"। इसलिए मैं आपको यह समझा रहा हूं कि यदि आपकी अपनी प्रोग्रामिंग भाषा डिजाइन कर रही है तो आपको सी कंपाइलर या सी ++ का उपयोग क्यों करना चाहिए। यदि आप पर्याप्त बुद्धिमान हैं तो आपको अपना खुद का डिजाइन करना चाहिए
तैयब गुलशेर वोहरा

8
मुझे नहीं लगता कि आप प्रश्न को समझते हैं। देखें yosefk.com/blog/c-as-an-intermediate-language.html
रॉबर्ट हार्वे
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.