2009-05-31 12 views
5

मैं लेक्स और वाईएसीसी (वास्तव में फ्लेक्स और बायसन) के साथ एक कंपाइलर बना रहा हूं। भाषा किसी भी प्रतीक (जैसे सी #) के असीमित आगे संदर्भों की अनुमति देता है। समस्या यह है कि पहचानकर्ता क्या है यह जानने के बिना भाषा को पार्स करना असंभव है।मैं एक कंपाइलर में आगे संदर्भ कैसे कार्यान्वित कर सकता हूं?

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

मुझे दक्षता के बारे में पूरी तरह से परवाह नहीं है (हालांकि यह अभी भी महत्वपूर्ण है), क्योंकि मैं इसे खत्म करने के बाद संकलक को फिर से लिखने जा रहा हूं, लेकिन मैं चाहता हूं कि वह संस्करण तेज़ हो (इसलिए यदि वहां क्या कोई तेज सामान्य तकनीक है जो लेक्स/वाईएसीसी में नहीं की जा सकती है लेकिन हाथ से किया जा सकता है, कृपया उन्हें भी सुझाव दें)। तो अभी, विकास की आसानी सबसे महत्वपूर्ण कारक है।

क्या इस समस्या के लिए कोई अच्छा समाधान है? यह आमतौर पर सी # या जावा जैसी भाषाओं के लिए कंपाइलर्स में कैसे किया जाता है?

उत्तर

7

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

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

संपादित करें: यदि आप देखना चाहते हैं कि यह कैसे किया गया है, तो मोनो सी # कंपाइलर के लिए स्रोत कोड देखें। यह वास्तव में सी या सी ++ की बजाय सी # में लिखा गया है, लेकिन यह जय के .NET पोर्ट का उपयोग करता है जो yacc के समान है।

+0

यह खोजशब्दों के साथ कोई संबंध नहीं है से बाहर बनाने के लिए सक्षम होना चाहिए के रूप में। यह इस तरह है: एबीसी (पैकेज एबी) है। (कक्षा सी), (पैकेज ए)। (कक्षा बी)। (फ़ील्ड बी), या (फील ए)। (फील्ड बी)। (फील्ड सी), आदि। – Zifre

+1

फिर मेरे उत्तर का दूसरा अनुच्छेद लागू होता है। आपको पार्स करने के लिए यह जानने की ज़रूरत नहीं है। इलाज '।' आपके व्याकरण में एक ऑपरेटर के रूप में। आपके एएसटी पास में आप उन्हें प्रतीक तालिका के खिलाफ जांच सकते हैं। – U62

+0

ठीक है, मुझे लगता है कि मुझे केवल एएसटी की बजाय एक पार्स पेड़ बनाना होगा। जैसा कि आपने कहा था कि वे अलग हैं। यदि कोई और बेहतर उत्तर के साथ आता है तो मैं इसे स्वीकार करूंगा, लेकिन मैं वास्तव में ऐसा नहीं करता ... – Zifre

1

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

लेक्सर लिखने के लिए हाथ रखने के लिए; नहीं, एक सामान्य पार्सर उत्पन्न करने के लिए लेक्स का उपयोग करें और केवल हाथ से लिखे गए शिम के माध्यम से इसे पढ़ें जो आपको वापस जाने और कैश से पार्सर को फ़ीड करने के साथ-साथ लेक्स बनाता है।

याक फ़ाइल पर एक पूर्वप्रक्रमक के साथ कई व्याकरण, एक छोटे से मजाक उड़ा और आप उन सब को एक ही मूल स्रोत

+0

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

+0

yacc के साथ एक प्रीप्रोसेसर पुन: यह बिल्कुल सही विचार है। प्रारंभिक बिंदु को स्पष्ट रूप से परिभाषित किए बिना पूर्ण व्याकरण को परिभाषित करें और फिर शुरुआती बिंदु चुनने के लिए फ़ाइल का एक छोटा सा हिस्सा (#include या #define जैसे) को स्वैप करें। ऐसा करने का एक तरीका "रूट :: = मैक्रोरुले" फ़ॉर्म का प्रारंभ नियम होना होगा; और इस संस्करण के लिए जो कुछ भी आप चाहते हैं उसके साथ मैक्रोरुले को प्रतिस्थापित करें। – BCS

संबंधित मुद्दे