मैं धीरे-धीरे अपनी डिग्री खत्म करने के लिए काम कर रहा हूं, और यह सेमेस्टर कंपाइलर्स 101 है। हम ड्रैगन बुक का उपयोग कर रहे हैं । शीघ्र ही पाठ्यक्रम में और हम लेक्सिकल विश्लेषण के बारे में बात कर रहे हैं और यह कैसे नियत परिमित ऑटोमेटा (इसके बाद, डीएफए) के माध्यम से लागू किया जा सकता है। अपने विभिन्न लेक्सर राज्यों को सेट करें, उनके बीच संक्रमण को परिभाषित करें, आदि।
लेकिन प्रोफेसर और पुस्तक दोनों ने उन्हें संक्रमण तालिकाओं के माध्यम से लागू करने का प्रस्ताव दिया, जो एक विशाल 2d सरणी (एक आयाम के रूप में विभिन्न गैर-टर्मिनल राज्यों, और दूसरे के रूप में संभव इनपुट प्रतीकों) और टर्मिनलों के सभी को संभालने के लिए एक स्विच स्टेटमेंट की राशि है। यदि गैर-टर्मिनल स्थिति में संक्रमण तालिकाओं के लिए प्रेषण।
सिद्धांत सभी अच्छी तरह से और अच्छा है, लेकिन किसी के रूप में जो दशकों के लिए कोड लिखा है, कार्यान्वयन निष्फल है। यह परीक्षण योग्य नहीं है, यह बनाए रखने योग्य नहीं है, यह पठनीय नहीं है, और यह एक दर्द है और एक आधा के माध्यम से डिबग करने के लिए है। इससे भी बदतर, मैं यह नहीं देख सकता कि यदि भाषा यूटीएफ सक्षम है तो यह कैसे दूर से व्यावहारिक होगा। गैर-टर्मिनल राज्य में एक लाख या तो संक्रमण तालिका प्रविष्टियाँ होने से जल्दबाज़ी में अनहोनी हो जाती है।
तो सौदा क्या है? विषय पर निश्चित पुस्तक इस तरह से करने के लिए क्यों कह रही है?
क्या फ़ंक्शन कॉल का ओवरहेड वास्तव में इतना है? क्या यह कुछ ऐसा है जो अच्छी तरह से काम करता है या आवश्यक है जब व्याकरण समय से पहले (नियमित अभिव्यक्ति?) नहीं जाना जाता है? या शायद कुछ ऐसा जो सभी मामलों को संभालता है, भले ही अधिक विशिष्ट समाधान अधिक विशिष्ट व्याकरण के लिए बेहतर काम करेंगे?
( ध्यान दें: संभव डुप्लिकेट " क्यों एक विशाल स्विच स्टेटमेंट के बजाय एक ओओ दृष्टिकोण का उपयोग करें? " करीब है, लेकिन मुझे ओओ के बारे में परवाह नहीं है। स्टैंडअलोन कार्यों के साथ एक कार्यात्मक दृष्टिकोण या यहां तक कि सैनर अनिवार्य दृष्टिकोण ठीक होगा।)
और उदाहरण के लिए, एक ऐसी भाषा पर विचार करें जिसमें केवल पहचानकर्ता हों, और वे पहचानकर्ता हों [a-zA-Z]+
। DFA कार्यान्वयन में, आपको कुछ ऐसा मिलेगा:
private enum State
{
Error = -1,
Start = 0,
IdentifierInProgress = 1,
IdentifierDone = 2
}
private static State[][] transition = new State[][]{
///* Start */ new State[]{ State.Error, State.Error (repeat until 'A'), State.IdentifierInProgress, ...
///* IdentifierInProgress */ new State[]{ State.IdentifierDone, State.IdentifierDone (repeat until 'A'), State.IdentifierInProgress, ...
///* etc. */
};
public static string NextToken(string input, int startIndex)
{
State currentState = State.Start;
int currentIndex = startIndex;
while (currentIndex < input.Length)
{
switch (currentState)
{
case State.Error:
// Whatever, example
throw new NotImplementedException();
case State.IdentifierDone:
return input.Substring(startIndex, currentIndex - startIndex);
default:
currentState = transition[(int)currentState][input[currentIndex]];
currentIndex++;
break;
}
}
return String.Empty;
}
(हालांकि कुछ ऐसा है जो फ़ाइल के अंत को सही ढंग से संभाल लेगा)
मेरी अपेक्षा के अनुसार:
public static string NextToken(string input, int startIndex)
{
int currentIndex = startIndex;
while (currentIndex < startIndex && IsLetter(input[currentIndex]))
{
currentIndex++;
}
return input.Substring(startIndex, currentIndex - startIndex);
}
public static bool IsLetter(char c)
{
return ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'));
}
NextToken
DFA की शुरुआत से कई गंतव्यों के होने के बाद, अपने स्वयं के फंक्शन में कोड के साथ ।