कब पर्याप्त है, आपको ईबीएनएफ की आवश्यकता कब होती है?
EBNF वास्तव में व्याकरण की शक्ति में बहुत कुछ नहीं जोड़ता है । यह मानक चॉम्स्की के नॉर्मल फॉर्म (CNF) व्याकरण नियमों के ऊपर सिर्फ एक सुविधा / शॉर्टकट नोटेशन / "सिंटैक्टिक शुगर" है। उदाहरण के लिए, EBNF विकल्प:
S --> A | B
आप प्रत्येक वैकल्पिक उत्पादन को अलग से सूचीबद्ध करके CNF में प्राप्त कर सकते हैं:
S --> A // `S` can be `A`,
S --> B // or it can be `B`.
EBNF से वैकल्पिक तत्व:
S --> X?
आप एक अशक्त उत्पादन का उपयोग करके CNF में प्राप्त कर सकते हैं , वह है, जिसे एक खाली स्ट्रिंग द्वारा प्रतिस्थापित किया जा सकता है (यहां सिर्फ खाली उत्पादन द्वारा चिह्नित किया जाता है; अन्य एप्सिलॉन या लैम्ब्डा या क्रॉस सर्कल का उपयोग करते हैं):
S --> B // `S` can be `B`,
B --> X // and `B` can be just `X`,
B --> // or it can be empty.
पिछले एक के B
ऊपर के रूप में एक उत्पादन को "इरेज़र" कहा जाता है, क्योंकि यह अन्य प्रस्तुतियों में जो कुछ भी खड़ा है उसे मिटा सकता है (उत्पाद कुछ और के बजाय एक खाली स्ट्रिंग)।
EBNF से शून्य या अधिक दोहराव:
S --> A*
आप पुनरावर्ती उत्पादन का उपयोग करके इसे रोक सकते हैं , अर्थात, जो स्वयं को इसमें कहीं एम्बेड करता है। इसे दो तरह से किया जा सकता है। पहले एक को पुनरावर्ती छोड़ दिया जाता है (जिसे आमतौर पर बचा जाना चाहिए, क्योंकि शीर्ष-नीचे पुनरावर्ती वंश पार्सर इसे पार नहीं कर सकते हैं):
S --> S A // `S` is just itself ended with `A` (which can be done many times),
S --> // or it can begin with empty-string, which stops the recursion.
यह जानते हुए कि यह सिर्फ एक खाली स्ट्रिंग (अंत में) शून्य या अधिक के बाद उत्पन्न करता A
है, एक ही स्ट्रिंग ( नहीं बल्कि एक ही भाषा! ) का उपयोग कर व्यक्त किया जा सकता सही-प्रत्यावर्तन :
S --> A S // `S` can be `A` followed by itself (which can be done many times),
S --> // or it can be just empty-string end, which stops the recursion.
और जब +
EBNF से एक या अधिक पुनरावृत्ति की बात आती है:
S --> A+
यह पहले से फैक्टरिंग A
करके *
और पहले की तरह उपयोग करके किया जा सकता है :
S --> A A*
जिसे आप CNF में व्यक्त कर सकते हैं, (मैं यहाँ सही पुनरावर्तन का उपयोग करता हूँ; दूसरे को व्यायाम के रूप में जानने की कोशिश करें):
S --> A S // `S` can be one `A` followed by `S` (which stands for more `A`s),
S --> A // or it could be just one single `A`.
यह जानते हुए कि, आप अब एक व्याकरण को एक नियमित अभिव्यक्ति (यानी, नियमित व्याकरण ) के रूप में पहचान सकते हैं, जिसे केवल एकल प्रतीकों में से एक ईबीएनएफ उत्पादन में व्यक्त किया जा सकता है। आम तौर पर, आप नियमित व्याकरण को पहचान सकते हैं जब आप इन के समान प्रस्तुतियों को देखते हैं:
A --> // Empty (nullable) production (AKA erasure).
B --> x // Single terminal symbol.
C --> y D // Simple state change from `C` to `D` when seeing input `y`.
E --> F z // Simple state change from `E` to `F` when seeing input `z`.
G --> G u // Left recursion.
H --> v H // Right recursion.
यही है, केवल खाली तारों, टर्मिनल प्रतीकों, प्रतिस्थापनों और राज्य परिवर्तनों के लिए सरल गैर-टर्मिनलों का उपयोग करना, और पुनरावृत्ति का उपयोग करने के लिए केवल पुनरावृत्ति का उपयोग करना (पुनरावृत्ति, जो सिर्फ रैखिक पुनरावृत्ति है - वह जो शाखा वृक्ष की तरह नहीं है)। इन सबसे ऊपर और कुछ भी उन्नत नहीं है, फिर आप सुनिश्चित करें कि यह एक नियमित वाक्यविन्यास है और आप इसके लिए सिर्फ लेक्सर के साथ जा सकते हैं।
लेकिन जब आपका सिंटैक्स गैर-तुच्छ तरीके से पुनरावृत्ति का उपयोग करता है, तो पेड़-जैसी, स्व-समान, नेस्टेड संरचनाओं का निर्माण करने के लिए, निम्न की तरह:
S --> a S b // `S` can be itself "parenthesized" by `a` and `b` on both sides.
S --> // or it could be (ultimately) empty, which ends recursion.
तब आप आसानी से देख सकते हैं कि यह नियमित अभिव्यक्ति के साथ नहीं किया जा सकता है, क्योंकि आप इसे किसी भी तरह से एक एकल ईबीएनएफ उत्पादन में हल नहीं कर सकते हैं; आप S
अनिश्चित काल के लिए प्रतिस्थापित करने के साथ समाप्त होंगे , जो हमेशा दोनों तरफ एक और a
एस और b
एस जोड़ देगा । लेक्सर्स (अधिक विशेष रूप से: लेक्सर्स द्वारा उपयोग किए जाने वाले परिमित राज्य ऑटोमेटा) को मनमाने ढंग से संख्या (वे परिमित, याद रखें?) के लिए नहीं गिना जा सकता है, इसलिए वे नहीं जानते हैं कि कितने a
एस उन्हें इतने सारे के साथ समान रूप से मैच करने के लिए थे b
। इस तरह के व्याकरणों को संदर्भ-मुक्त व्याकरण (बहुत कम से कम) कहा जाता है , और उन्हें एक पार्सर की आवश्यकता होती है।
प्रसंग-मुक्त व्याकरण पार्स के लिए अच्छी तरह से जाना जाता है, इसलिए वे प्रोग्रामिंग भाषाओं के वाक्यविन्यास का वर्णन करने के लिए व्यापक रूप से उपयोग किए जाते हैं। लेकिन वहाँ अधिक है। कभी-कभी अधिक सामान्य व्याकरण की आवश्यकता होती है - जब आपके पास एक ही समय में, स्वतंत्र रूप से गणना करने के लिए अधिक चीजें होती हैं। उदाहरण के लिए, जब आप एक ऐसी भाषा का वर्णन करना चाहते हैं जहाँ कोई गोल कोष्ठक और वर्ग ब्रेसिज़ का उपयोग कर सकता है, लेकिन उन्हें एक दूसरे के साथ सही ढंग से जोड़ा जाना चाहिए (ब्रेसिज़ के साथ ब्रेसिज़, गोल के साथ गोल)। इस तरह के व्याकरण को संदर्भ-संवेदनशील कहा जाता है । आप इसे पहचान सकते हैं कि इसमें बाईं ओर (तीर से पहले) एक से अधिक प्रतीक हैं। उदाहरण के लिए:
A R B --> A S B
आप नियम लागू करने के लिए बाईं ओर इन अतिरिक्त प्रतीकों को "संदर्भ" के रूप में सोच सकते हैं। वहाँ कुछ पूर्व शर्त हो सकती है, postconditions आदि उदाहरण के लिए, उपर्युक्त नियम विकल्प होगा R
में S
है, लेकिन केवल जब यह के बीच में है A
और B
उन छोड़ रहा है, A
और B
खुद को अपरिवर्तित। इस तरह के वाक्यविन्यास को पार्स करना वास्तव में कठिन है, क्योंकि इसमें एक पूर्ण विकसित ट्यूरिंग मशीन की आवश्यकता होती है। यह एक पूरी कहानी है, इसलिए मैं यहां समाप्त करूंगा।