ANTLR में एक 'अर्थ संबंधी विधेय' क्या है?


103

ANTLR में एक शब्दार्थ विधेय क्या है ?


3
ध्यान दें कि जब से मैं किसी ऐसे व्यक्ति के लिए पोस्ट करने के लिए एक अच्छा ऑनलाइन संसाधन नहीं ढूंढ सका जो यह जानना चाहता था कि एक शब्दार्थ विधेय क्या है, मैंने स्वयं यहां प्रश्न पोस्ट करने का फैसला किया (जिसका मैं जल्द ही खुद भी जवाब दूंगा)।
बार्ट कीर्स

1
ऐसा करने के लिए धन्यवाद; मुझे हमेशा यह पसंद है जब लोग अपने स्वयं के प्रश्नों का उत्तर देते हैं, खासकर यदि वे इस तरह से इसका जवाब देने के लिए विशेष रूप से सवाल पूछते हैं।
डैनियल एच

1
किताब पढ़ी। निश्चित ANTLR 4 संदर्भ के Ch 11 शब्दार्थ विधेय पर है। पुस्तक नहीं है? उसे ले लो! हर डॉलर के लायक।
james.garriss

जवाबों:


169

ANTLR 4

ANTLR 4 में विधेय के लिए, इन स्टैक ओवरफ़्लो Q & A की जाँच करें:


ANTLR 3

एक शब्दार्थ विधेय सादा कोड का उपयोग करके व्याकरण की क्रियाओं पर अतिरिक्त (शब्दार्थ) नियमों को लागू करने का एक तरीका है।

3 प्रकार के शब्दार्थ विधेय हैं:

  • सिमेंटिक विधेय को मान्य करना;
  • gated अर्थ संबंधी भविष्यवाणी;
  • अव्यवस्थित अर्थ की भविष्यवाणी की।

उदाहरण व्याकरण

मान लें कि आपके पास पाठ का एक खंड है, जो केवल कॉमा द्वारा अलग किए गए नंबरों से मिलकर बनता है, जो किसी भी सफेद स्थान को अनदेखा करता है। आप इस इनपुट को यह सुनिश्चित करना चाहते हैं कि संख्याएँ अधिकतम 3 अंकों "लंबी" (अधिकतम 999) पर हों। निम्नलिखित व्याकरण ( Numbers.g) ऐसा काम करेगा:

grammar Numbers;

// entry point of this parser: it parses an input string consisting of at least 
// one number, optionally followed by zero or more comma's and numbers
parse
  :  number (',' number)* EOF
  ;

// matches a number that is between 1 and 3 digits long
number
  :  Digit Digit Digit
  |  Digit Digit
  |  Digit
  ;

// matches a single digit
Digit
  :  '0'..'9'
  ;

// ignore spaces
WhiteSpace
  :  (' ' | '\t' | '\r' | '\n') {skip();}
  ;

परिक्षण

व्याकरण का परीक्षण निम्न वर्ग के साथ किया जा सकता है:

import org.antlr.runtime.*;

public class Main {
    public static void main(String[] args) throws Exception {
        ANTLRStringStream in = new ANTLRStringStream("123, 456, 7   , 89");
        NumbersLexer lexer = new NumbersLexer(in);
        CommonTokenStream tokens = new CommonTokenStream(lexer);
        NumbersParser parser = new NumbersParser(tokens);
        parser.parse();
    }
}

सभी .javaफ़ाइलें संकलित करके और Mainकक्षा चलाकर , लेक्सर और पार्सर उत्पन्न करके इसका परीक्षण करें :

java -cp antlr-3.2.jar org.antlr.Tool Numbers.g
javac -cp antlr-3.2.jar * .java
java -cp।: antlr-3.2.jar मेन

ऐसा करते समय, कंसोल को कुछ भी नहीं मुद्रित किया जाता है, जो इंगित करता है कि कुछ भी गलत नहीं हुआ। बदलने की कोशिश करें:

ANTLRStringStream in = new ANTLRStringStream("123, 456, 7   , 89");

में:

ANTLRStringStream in = new ANTLRStringStream("123, 456, 7777   , 89");

और फिर से परीक्षण करें: आपको स्ट्रिंग के ठीक बाद कंसोल पर दिखाई देने वाली त्रुटि दिखाई देगी 777


शब्दार्थ विधेय

यह हमें शब्दार्थ की भविष्यवाणी करता है। मान लीजिए कि आप 1 और 10 अंकों के बीच की संख्या को पार करना चाहते हैं। एक नियम की तरह:

number
  :  Digit Digit Digit Digit Digit Digit Digit Digit Digit Digit
  |  Digit Digit Digit Digit Digit Digit Digit Digit Digit
     /* ... */
  |  Digit Digit Digit
  |  Digit Digit
  |  Digit
  ;

बोझिल हो जाती। शब्दार्थ विधेय इस तरह के नियम को सरल बनाने में मदद कर सकता है।


1. अर्थ संबंधी विधेय को मान्य करना

एक मान्य शब्दार्थ विधेय एक प्रश्न चिह्न के बाद कोड के एक ब्लॉक से ज्यादा कुछ नहीं है:

RULE { /* a boolean expression in here */ }?

एक वैध शब्दार्थ विधेय का उपयोग करके उपरोक्त समस्या को हल करने के लिए , numberव्याकरण में नियम को बदलें :

number
@init { int N = 0; }
  :  (Digit { N++; } )+ { N <= 10 }?
  ;

भागों { int N = 0; }और { N++; }सादे जावा स्टेटमेंट हैं जिनमें से पहला इनिशियलाइज़ किया गया है जब पार्सर numberनियम में "प्रवेश करता है" । वास्तविक विधेय वह है: { N <= 10 }?जो किसी FailedPredicateException भी संख्या को 10 अंकों से अधिक लंबे होने पर पार्सर को फेंकने का कारण बनता है ।

निम्नलिखित का उपयोग करके इसका परीक्षण करें ANTLRStringStream:

// all equal or less than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,1234567890"); 

जो बिना किसी अपवाद के उत्पन्न होता है, जबकि निम्नलिखित एक अपवाद को दर्शाता है:

// '12345678901' is more than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,12345678901");

2. गेटेड शब्दार्थ विधेय

एक गेटेड अर्थ विधेय एक के समान है मान्य अर्थ विधेय , केवल गेटेड संस्करण एक के बजाय एक सिंटैक्स त्रुटि पैदा करता है FailedPredicateException

गेटेड सिमेंटिक विधेय का सिंटैक्स है:

{ /* a boolean expression in here */ }?=> RULE

बजाय का उपयोग करके उपरोक्त समस्या को हल करने गेटेड विधेय 10 अंक करने के लिए संख्या मैच के लिए जब तक आप लिखना होगा:

number
@init { int N = 1; }
  :  ( { N <= 10 }?=> Digit { N++; } )+
  ;

इसे फिर से दोनों के साथ टेस्ट करें:

// all equal or less than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,1234567890"); 

तथा:

// '12345678901' is more than 10 digits
ANTLRStringStream in = new ANTLRStringStream("1,23,12345678901");

और आप आखिरी बार देखेंगे कि कोई त्रुटि है।


3. अर्थ संबंधी विधेय को खारिज करना

अंतिम प्रकार का विधेय एक अव्यवस्थित अर्थपूर्ण विधेय है , जो एक मान्य विधेय ( {boolean-expression}?) की तरह थोड़ा सा दिखता है , लेकिन एक gated शब्दार्थ विधेय की तरह अधिक कार्य करता है (कोई अपवाद नहीं फेंका जाता है जब बूलियन अभिव्यक्ति का मूल्यांकन होता है false)। आप एक नियम की शुरुआत में इसका उपयोग किसी नियम की कुछ संपत्ति की जांच करने के लिए कर सकते हैं और पार्सर मैच को नियम या नहीं कह सकते हैं।

मान लीजिए कि उदाहरण व्याकरण Numberटोकन बनाता है (पार्सर नियम के बजाय एक लेसर नियम) जो 0..999 की सीमा में संख्याओं से मेल खाएगा। अब पार्सर में, आप निम्न और ऊँचाई की संख्या (कम: 0..500, उच्च: 501-999) के बीच अंतर करना चाहेंगे। यह एक अव्यवस्थित अर्थपूर्ण विधेय का उपयोग करके किया जा सकता है जहां आप स्ट्रीम में अगले टोकन का निरीक्षण करते हैं ( input.LT(1)यह जांचने के लिए कि क्या यह कम है या उच्च है।

एक डेमो:

grammar Numbers;

parse
  :  atom (',' atom)* EOF
  ;

atom
  :  low  {System.out.println("low  = " + $low.text);}
  |  high {System.out.println("high = " + $high.text);}
  ;

low
  :  {Integer.valueOf(input.LT(1).getText()) <= 500}? Number
  ;

high
  :  Number
  ;

Number
  :  Digit Digit Digit
  |  Digit Digit
  |  Digit
  ;

fragment Digit
  :  '0'..'9'
  ;

WhiteSpace
  :  (' ' | '\t' | '\r' | '\n') {skip();}
  ;

यदि आप अब स्ट्रिंग को पार्स करते हैं "123, 999, 456, 700, 89, 0", तो आपको निम्न आउटपुट दिखाई देंगे:

low  = 123
high = 999
low  = 456
high = 700
low  = 89
low  = 0

12
यार आपको वास्तव में ANTLR के लिए एक शुरुआती गाइड लिखने पर विचार करना चाहिए: P
यूरी घेंसेव

5
@ बर्ट कियर्स: कृपया ANTLR पर एक पुस्तक लिखें
संतोश सिंह

2
ANTLR v4 के लिए, input.LT(1)है getCurrentToken()अब :-)
जिओ जिया

शानदार ... यह संपूर्ण विवरण और उदाहरण हैं जो डॉक्स में होने चाहिए!
यहेजकेल विक्टर

+1। यह उत्तर द डेफिनिटिव ANTLR 4 रेफरेंस बुक से कहीं बेहतर है। यह उत्तर अच्छे उदाहरणों के साथ अवधारणा पर हाजिर है।
asyncwait

11

मैंने हमेशा अपने गाइड के रूप में wincent.com पर ANTLR के लिए संदर्भ का उपयोग किया है ।


6
हाँ, एक उत्कृष्ट लिंक! लेकिन, जैसा कि आप उल्लेख करते हैं, यह ANTLR के लिए किसी (अपेक्षाकृत) नए के लिए थोड़ा मुश्किल हो सकता है। मुझे उम्मीद है कि मेरा जवाब ANTLR- घास-हॉपर के लिए (थोड़ा) मित्रवत है। :)
बार्ट कीरस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.