कोड काम कैसे पूरा करता है?


84

संपादकों और IDEs के बहुत सारे कोड पूरा हो गया है। उनमें से कुछ बहुत "बुद्धिमान" हैं अन्य वास्तव में नहीं हैं। मुझे अधिक बुद्धिमान प्रकार में दिलचस्पी है। उदाहरण के लिए, मैंने आईडीई को देखा है कि केवल एक फ़ंक्शन प्रदान करता है यदि यह वर्तमान स्कोप में उपलब्ध है) ख) इसका रिटर्न वैल्यू मान्य है। (उदाहरण के लिए "5 + foo [टैब]" के बाद यह केवल ऐसे फ़ंक्शन प्रदान करता है जो कुछ ऐसा लौटाते हैं जो सही प्रकार के पूर्णांक या चर नामों में जोड़ा जा सकता है।) मैंने यह भी देखा है कि वे अक्सर उपयोग किए जाने वाले या सबसे लंबे विकल्प को आगे रखते हैं। सूची का।

मुझे पता है कि आपको कोड को पार्स करने की आवश्यकता है। लेकिन आमतौर पर वर्तमान कोड को संपादित करते समय यह अमान्य है कि इसमें सिंटैक्स त्रुटियां हैं। जब आप अधूरे होते हैं तो आप किसी चीज़ को पार्स कैसे करते हैं और उसमें त्रुटियाँ हैं?

समय की कमी भी है। यदि सूची के साथ आने में सेकंड लगते हैं तो पूरा होना बेकार है। कभी-कभी पूर्ण एल्गोरिथ्म हजारों वर्गों से संबंधित होता है।

इसके लिए अच्छे एल्गोरिदम और डेटा संरचनाएं क्या हैं?


1
एक अच्छा सवाल। आप कुछ ऐसे ओपन-सोर्स आईडीई के लिए कोड पर एक नज़र डालना चाहते हैं जो इसे लागू करते हैं, जैसे कोड :: ब्लॉक कोड atblocks.org

1
यहाँ C # में कोड कम्पलीशन बनाने का लेख # C में कोड कंप्लीशन बनाना
प्रीतम ज़ोप

जवाबों:


64

मेरी अवास्तविक भाषा सेवा उत्पाद में IntelliSense इंजन जटिल है, लेकिन मैं यहाँ सबसे अच्छा अवलोकन दे सकता हूँ जितना मैं कर सकता हूँ। VS2008 SP1 में C # भाषा सेवा मेरा प्रदर्शन लक्ष्य (अच्छे कारण के लिए) है। यह अभी तक वहाँ नहीं है, लेकिन यह काफी तेज़ / सटीक है कि मैं ctrl + space या उपयोगकर्ता टाइपिंग .(डॉट) टाइप किए बिना एक ही अक्षर टाइप करने के बाद सुरक्षित रूप से सुझाव दे सकता हूं । लोगों को [भाषा सेवाओं पर काम करने] की अधिक जानकारी इस विषय के बारे में मिलती है, मुझे जो बेहतर एंड-यूज़र अनुभव मिलता है, उसे मुझे कभी अपने उत्पादों का उपयोग करना चाहिए। ऐसे कई उत्पाद हैं जिनके साथ काम करने का मेरा दुर्भाग्यपूर्ण अनुभव रहा है जिन्होंने विवरणों पर इतना ध्यान नहीं दिया, और इसके परिणामस्वरूप मैं आईडीई से अधिक लड़ रहा था जितना कि मैं कोडिंग कर रहा था।

मेरी भाषा सेवा में, इसे निम्नलिखित की तरह रखा गया है:

  1. कर्सर पर अभिव्यक्ति प्राप्त करें। यह सदस्य पहुँच अभिव्यक्ति की शुरुआत से पहचानकर्ता के अंत तक चलता है जो कर्सर खत्म हो गया है। सदस्य एक्सेस अभिव्यक्ति आम तौर पर फॉर्म में होती है aa.bb.cc, लेकिन इसमें विधि कॉल भी हो सकती है aa.bb(3+2).cc
  2. कर्सर के आसपास के संदर्भ प्राप्त करें । यह बहुत मुश्किल है, क्योंकि यह हमेशा संकलक (लंबी कहानी) के समान नियमों का पालन नहीं करता है, लेकिन यहां मान लें कि यह करता है। आम तौर पर इसका मतलब यह है कि कर्सर जिस पद्धति / कक्षा में है उसके बारे में कैश्ड जानकारी प्राप्त करें।
  3. संदर्भ ऑब्जेक्ट को लागू करें कहें IDeclarationProvider, जहां आप गुंजाइश में दिखाई देने वाली सभी वस्तुओं GetDeclarations()को प्राप्त करने के लिए कॉल कर सकते हैं IEnumerable<IDeclaration>। मेरे मामले में, इस सूची में स्थानीय / पैरामीटर (यदि एक विधि में), सदस्य (फ़ील्ड और विधियाँ, केवल एक उदाहरण विधि में स्थिर होने पर, और आधार प्रकारों का कोई निजी सदस्य नहीं), ग्लोबल्स (भाषा के प्रकार और स्थिरांक) शामिल हैं। 'पर काम कर रहा हूँ), और खोजशब्द। इस सूची में नाम के साथ एक आइटम होगा aa। # 1 में अभिव्यक्ति का मूल्यांकन करने में पहले कदम के रूप में, हम नाम के साथ संदर्भ गणना से आइटम का चयन करते हैं aa, हमें IDeclarationअगले चरण के लिए देते हैं।
  4. अगला, मैं ऑपरेटर को "सदस्यों" (कुछ अर्थों में) युक्त एक और प्राप्त करने के लिए IDeclarationप्रतिनिधित्व aaकरने के लिए आवेदन करता हूं । चूंकि ऑपरेटर ऑपरेटर से अलग है , इसलिए मैं कॉल करता हूं और ऑब्जेक्ट को सूचीबद्ध ऑपरेटर को सही ढंग से लागू करने की अपेक्षा करता हूं ।IEnumerable<IDeclaration>aa.->declaration.GetMembers(".")IDeclaration
  5. यह तब तक जारी रहता है जब तक मैं हिट नहीं करता cc, जहां घोषणा सूची में नाम के साथ कोई वस्तु हो सकती है या नहींcc । जैसा कि मुझे यकीन है कि आप जागरूक हैं, यदि कई आइटम शुरू होते हैं cc, तो उन्हें भी दिखाई देना चाहिए। मैं इसे अंतिम रूप से लेता है और उपयोगकर्ता को सबसे अधिक उपयोगी जानकारी प्रदान करने के लिए अपने प्रलेखित एल्गोरिथ्म के माध्यम से इसे हल करता हूं ।

यहाँ IntelliSense बैकएंड के लिए कुछ अतिरिक्त नोट्स दिए गए हैं:

  • मैं कार्यान्वयन में LINQ के आलसी मूल्यांकन तंत्र का व्यापक उपयोग करता हूं GetMembers। मेरे कैश में प्रत्येक ऑब्जेक्ट एक फंक्शनल प्रदान करने में सक्षम है जो अपने सदस्यों का मूल्यांकन करता है, इसलिए पेड़ के साथ जटिल क्रियाएं करना तुच्छ के पास है।
  • List<IDeclaration>अपने सदस्यों को रखने वाली प्रत्येक वस्तु के बजाय , मैं एक रखता हूं List<Name>, जहां Nameएक संरचना होती है जिसमें सदस्य का वर्णन करने वाले विशेष रूप से स्वरूपित स्ट्रिंग के हैश होते हैं। एक विशाल कैश है जो ऑब्जेक्ट्स के नाम मैप करता है। इस तरह, जब मैं किसी फ़ाइल को पुन: पार्स करता हूं, तो मैं कैश में से फ़ाइल में घोषित सभी आइटम हटा सकता हूं और इसे अपडेट किए गए सदस्यों के साथ फिर से जमा कर सकता हूं। जिस तरह से फ़ंक्शंस कॉन्फ़िगर किए गए हैं, उसके कारण सभी अभिव्यक्तियां तुरंत नए आइटम का मूल्यांकन करती हैं।

IntelliSense "फ्रंटेंड"

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

  • एक रिडीमिंग फैक्टर है मेरा पार्सर फास्ट है । यह कम प्राथमिकता वाले बैकग्राउंड थ्रेड पर सेल्फ-ऑपरेट करते हुए 150ms में 20000 लाइन सोर्स फाइल का पूरा कैशे अपडेट संभाल सकता है। जब भी यह पार्सर एक खुली फ़ाइल को सफलतापूर्वक (सिंटैक्टिक रूप से) पास करता है, तो फ़ाइल की वर्तमान स्थिति को वैश्विक कैश में ले जाया जाता है।
  • यदि फ़ाइल वाक्यात्मक रूप से सही नहीं है, तो मैं एक ANTLR फ़िल्टर पार्सर का उपयोग करता हूं (लिंक के बारे में खेद है - अधिकांश जानकारी मेलिंग सूची में है या स्रोत को पढ़ने से एकत्र की गई है) फ़ाइल की तलाश में वापस लाने के लिए:
    • चर / क्षेत्र घोषणाएँ।
    • वर्ग / संरचना परिभाषाओं के लिए हस्ताक्षर।
    • विधि परिभाषाओं के लिए हस्ताक्षर।
  • स्थानीय कैश में, क्लास / स्ट्रक्चर / मेथड परिभाषाएं सिग्नेचर से शुरू होती हैं और जब ब्रेस नेस्टिंग लेवल वापस आ जाता है। यदि कोई अन्य विधि घोषणा तक पहुँच गया है (कोई नेस्टिंग विधियों नहीं) तो विधियाँ भी समाप्त हो सकती हैं।
  • स्थानीय कैश में, चर / फ़ील्ड तुरंत पूर्ववर्ती असंगत तत्व से जुड़े होते हैं । यह महत्वपूर्ण क्यों है, इसके एक उदाहरण के लिए नीचे संक्षिप्त कोड स्निपेट देखें।
  • इसके अलावा, उपयोगकर्ता प्रकारों के रूप में, मैं जोड़ा / हटाए गए वर्ण श्रेणियों को चिह्नित करते हुए एक रीमैप तालिका रखता हूं। इसके लिए प्रयोग किया जाता है:
    • यह सुनिश्चित करते हुए कि मैं कर्सर के सही संदर्भ की पहचान कर सकता हूं, क्योंकि पूर्ण पार्स के बीच फ़ाइल में कोई विधि / चाल चल सकती है।
    • यह सुनिश्चित करना कि खुली फाइलों में सही ढंग से घोषणा / परिभाषा / संदर्भ जाना।

पिछले अनुभाग के लिए कोड स्निपेट:

class A
{
    int x; // linked to A

    void foo() // linked to A
    {
        int local; // linked to foo()

    // foo() ends here because bar() is starting
    void bar() // linked to A
    {
        int local2; // linked to bar()
    }

    int y; // linked again to A

मुझे लगा कि मैं इस लेआउट के साथ लागू किए गए IntelliSense सुविधाओं की एक सूची जोड़ दूंगा। प्रत्येक के चित्र यहां स्थित हैं।

  • स्वत: पूर्ण
  • उपकरण युक्तियाँ
  • विधि टिप्स
  • क्लास व्यू
  • कोड परिभाषा विंडो
  • कॉल ब्राउज़र (VS 2010 आखिरकार इसे C # में जोड़ता है)
  • शब्दार्थ सभी संदर्भ खोजें

यह बहुत धन्यवाद है। मैंने कभी केस सेंसिटिव पूर्वाग्रह के बारे में नहीं सोचा था। मुझे विशेष रूप से पसंद है कि आप बेमेल ब्रेसिज़ से निपट सकते हैं।
स्ट्रीबिका

15

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

जब आप एक वर्ण टाइप करते हैं, तो यह ट्राइ में एक पथ पर चलता है। एक विशेष त्रिगुण के वंशज सभी संभव पूर्णताएं हैं। IDE को केवल उन लोगों द्वारा फ़िल्टर करने की आवश्यकता होती है जो वर्तमान संदर्भ में समझ में आते हैं, लेकिन इसे केवल उतना ही गणना करने की आवश्यकता है जितना कि टैब-पूर्ण पॉप-अप विंडो में प्रदर्शित किया जा सकता है।

अधिक उन्नत टैब-समापन के लिए अधिक जटिल त्रि की आवश्यकता होती है। उदाहरण के लिए, विज़ुअल असिस्ट एक्स में एक विशेषता है जिसके तहत आपको केवल CamelCase प्रतीकों के कैपिटल अक्षरों को टाइप करने की आवश्यकता है - उदाहरण के लिए, यदि आप SFN टाइप करते हैं, तो यह आपको SomeFunctionNameटैब-पूर्ण विंडो में प्रतीक दिखाता है ।

तीनों (या अन्य डेटा संरचनाओं) की गणना करने के लिए आपके प्रोजेक्ट में सभी प्रतीकों की सूची प्राप्त करने के लिए आपके सभी कोड को पार्स करने की आवश्यकता होती है। विजुअल स्टूडियो ने इसे अपने इंटेलीसेन डेटाबेस में संग्रहीत किया है.ncb संग्रहीत किया है फाइल जो आपके प्रोजेक्ट के साथ संग्रहीत है, ताकि इसे हर बार जब भी आप बंद करें और अपनी परियोजना को फिर से खोलना पड़े, तो उसे वापस नहीं करना पड़े। पहली बार जब आप एक बड़ी परियोजना खोलते हैं (कहते हैं, एक तुम सिर्फ फार्म स्रोत नियंत्रण को सिंक करते हो), वीएस सब कुछ पार्स करने और डेटाबेस उत्पन्न करने के लिए समय लेगा।

मुझे नहीं पता कि यह वृद्धिशील परिवर्तनों को कैसे संभालता है। जैसा कि आपने कहा, जब आप कोड लिख रहे होते हैं, तो यह 90% समय का अमान्य सिंटैक्स होता है, और जब भी आप बेकार होते हैं, तो बहुत कम लाभ के लिए अपने सीपीयू पर एक बड़ा कर लगाते हैं, खासकर यदि आप एक हेडर फ़ाइल को संशोधित कर रहे हैं जिसमें शामिल हैं स्रोत फ़ाइलों की एक बड़ी संख्या।

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


तीनों वास्तव में एक अच्छा विचार है। वृद्धिशील परिवर्तनों के लिए यह संभव है कि पहले फ़ाइल को फिर से पार्स करने की कोशिश करें जब वह काम नहीं करता है जो वर्तमान लाइन की अनदेखी करता है और जब वह काम नहीं करता है तो संलग्न {{}} ब्लॉक को अनदेखा करें। यदि अन्य सभी विफल रहता है तो अंतिम डेटाबेस का उपयोग करें।
स्ट्रीबिका

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.