ANTLR में टुकड़े का क्या मतलब है?
मैंने दोनों नियम देखे हैं:
fragment DIGIT : '0'..'9';
तथा
DIGIT : '0'..'9';
अंतर क्या है?
ANTLR में टुकड़े का क्या मतलब है?
मैंने दोनों नियम देखे हैं:
fragment DIGIT : '0'..'9';
तथा
DIGIT : '0'..'9';
अंतर क्या है?
जवाबों:
एक टुकड़ा कुछ इनलाइन फ़ंक्शन के समान है: यह व्याकरण को अधिक पठनीय और बनाए रखने में आसान बनाता है।
एक टुकड़े को एक टोकन के रूप में कभी नहीं गिना जाएगा, यह केवल एक व्याकरण को सरल बनाने का कार्य करता है।
विचार करें:
NUMBER: DIGITS | OCTAL_DIGITS | HEX_DIGITS;
fragment DIGITS: '1'..'9' '0'..'9'*;
fragment OCTAL_DIGITS: '0' '0'..'7'+;
fragment HEX_DIGITS: '0x' ('0'..'9' | 'a'..'f' | 'A'..'F')+;
इस उदाहरण में, एक NUMBER से मिलान करना हमेशा लीकर को एक NUMBER लौटाएगा, भले ही वह "1234", "0xab12", या "0777" से मेल खाता हो।
निश्चित Antlr4 संदर्भ पुस्तक के अनुसार:
टुकड़े के साथ उपसर्ग वाले नियम केवल अन्य लेसर नियमों से कहे जा सकते हैं; वे अपने आप में टोकन नहीं हैं।
वास्तव में वे आपके व्याकरण की पठनीयता में सुधार करेंगे।
इस उदाहरण को देखें:
STRING : '"' (ESC | ~["\\])* '"' ;
fragment ESC : '\\' (["\\/bfnrt] | UNICODE) ;
fragment UNICODE : 'u' HEX HEX HEX HEX ;
fragment HEX : [0-9a-fA-F] ;
STRING ईएससी की तरह खंडन नियम का उपयोग करने वाला एक लेसर है। यूनिकोड का उपयोग Esc नियम में किया जाता है और Hexic का उपयोग यूनिकोड टुकड़ा नियम में किया जाता है। ESC और UNICODE और HEX नियमों का स्पष्ट रूप से उपयोग नहीं किया जा सकता है।
निश्चित ANTLR 4 संदर्भ (पृष्ठ 106) L
टुकड़े के साथ उपसर्ग वाले नियम केवल अन्य लेसर नियमों से कहे जा सकते हैं; वे अपने आप में टोकन नहीं हैं।
Case1: (मैं RULE1 जरूरत है, RULE2, RULE3 संस्थाओं या समूह की जानकारी)
rule0 : RULE1 | RULE2 | RULE3 ;
RULE1 : [A-C]+ ;
RULE2 : [DEF]+ ;
RULE3 : ('G'|'H'|'I')+ ;
Case2: (अगर मुझे RULE1, RULE2, RULE3 की परवाह नहीं है, तो मैं सिर्फ RULE0 पर ध्यान केंद्रित करता हूं)
RULE0 : [A-C]+ | [DEF]+ | ('G'|'H'|'I')+ ;
// RULE0 is a terminal node.
// You can't name it 'rule0', or you will get syntax errors:
// 'A-C' came as a complete surprise to me while matching alternative
// 'DEF' came as a complete surprise to me while matching alternative
केस 3: ( केस 2 के बराबर है, यह केस 2 से अधिक पठनीय है)
RULE0 : RULE1 | RULE2 | RULE3 ;
fragment RULE1 : [A-C]+ ;
fragment RULE2 : [DEF]+ ;
fragment RULE3 : ('G'|'H'|'I')+ ;
// You can't name it 'rule0', or you will get warnings:
// warning(125): implicit definition of token RULE1 in parser
// warning(125): implicit definition of token RULE2 in parser
// warning(125): implicit definition of token RULE3 in parser
// and failed to capture rule0 content (?)
लक्ष्य: पहचान [ABC]+
, [DEF]+
, [GHI]+
टोकन
input.txt
ABBCCCDDDDEEEEE ABCDE
FFGGHHIIJJKK FGHIJK
ABCDEFGHIJKL
Main.py
import sys
from antlr4 import *
from AlphabetLexer import AlphabetLexer
from AlphabetParser import AlphabetParser
from AlphabetListener import AlphabetListener
class MyListener(AlphabetListener):
# Exit a parse tree produced by AlphabetParser#content.
def exitContent(self, ctx:AlphabetParser.ContentContext):
pass
# (For Case1 Only) enable it when testing Case1
# Exit a parse tree produced by AlphabetParser#rule0.
def exitRule0(self, ctx:AlphabetParser.Rule0Context):
print(ctx.getText())
# end-of-class
def main():
file_name = sys.argv[1]
input = FileStream(file_name)
lexer = AlphabetLexer(input)
stream = CommonTokenStream(lexer)
parser = AlphabetParser(stream)
tree = parser.content()
print(tree.toStringTree(recog=parser))
listener = MyListener()
walker = ParseTreeWalker()
walker.walk(listener, tree)
# end-of-def
main()
वर्णमाला .g4 (Case1)
grammar Alphabet;
content : (rule0|ANYCHAR)* EOF;
rule0 : RULE1 | RULE2 | RULE3 ;
RULE1 : [A-C]+ ;
RULE2 : [DEF]+ ;
RULE3 : ('G'|'H'|'I')+ ;
ANYCHAR : . -> skip;
परिणाम:
# Input data (for reference)
# ABBCCCDDDDEEEEE ABCDE
# FFGGHHIIJJKK FGHIJK
# ABCDEFGHIJKL
$ python3 Main.py input.txt
(content (rule0 ABBCCC) (rule0 DDDDEEEEE) (rule0 ABC) (rule0 DE) (rule0 FF) (rule0 GGHHII) (rule0 F) (rule0 GHI) (rule0 ABC) (rule0 DEF) (rule0 GHI) <EOF>)
ABBCCC
DDDDEEEEE
ABC
DE
FF
GGHHII
F
GHI
ABC
DEF
GHI
वर्णमाला .g4 (Case2)
grammar Alphabet;
content : (RULE0|ANYCHAR)* EOF;
RULE0 : [A-C]+ | [DEF]+ | ('G'|'H'|'I')+ ;
ANYCHAR : . -> skip;
वर्णमाला .g4 (Case3)
grammar Alphabet;
content : (RULE0|ANYCHAR)* EOF;
RULE0 : RULE1 | RULE2 | RULE3 ;
fragment RULE1 : [A-C]+ ;
fragment RULE2 : [DEF]+ ;
fragment RULE3 : ('G'|'H'|'I')+ ;
ANYCHAR : . -> skip;
परिणाम:
# Input data (for reference)
# ABBCCCDDDDEEEEE ABCDE
# FFGGHHIIJJKK FGHIJK
# ABCDEFGHIJKL
$ python3 Main.py input.txt
(content ABBCCC DDDDEEEEE ABC DE FF GGHHII F GHI ABC DEF GHI <EOF>)
क्या आपने "कैप्चरिंग ग्रुप्स" और "नॉन-कैप्चरिंग ग्रुप्स" पार्ट्स देखे हैं ?
लक्ष्य: ओक्टल / दशमलव / हेक्साडेसिमल संख्याओं की पहचान करें
input.txt
0
123
1~9999
001~077
0xFF, 0x01, 0xabc123
Number.g4
grammar Number;
content
: (number|ANY_CHAR)* EOF
;
number
: DECIMAL_NUMBER
| OCTAL_NUMBER
| HEXADECIMAL_NUMBER
;
DECIMAL_NUMBER
: [1-9][0-9]*
| '0'
;
OCTAL_NUMBER
: '0' '0'..'9'+
;
HEXADECIMAL_NUMBER
: '0x'[0-9A-Fa-f]+
;
ANY_CHAR
: .
;
Main.py
import sys
from antlr4 import *
from NumberLexer import NumberLexer
from NumberParser import NumberParser
from NumberListener import NumberListener
class Listener(NumberListener):
# Exit a parse tree produced by NumberParser#Number.
def exitNumber(self, ctx:NumberParser.NumberContext):
print('%8s, dec: %-8s, oct: %-8s, hex: %-8s' % (ctx.getText(),
ctx.DECIMAL_NUMBER(), ctx.OCTAL_NUMBER(), ctx.HEXADECIMAL_NUMBER()))
# end-of-def
# end-of-class
def main():
input = FileStream(sys.argv[1])
lexer = NumberLexer(input)
stream = CommonTokenStream(lexer)
parser = NumberParser(stream)
tree = parser.content()
print(tree.toStringTree(recog=parser))
listener = Listener()
walker = ParseTreeWalker()
walker.walk(listener, tree)
# end-of-def
main()
परिणाम:
# Input data (for reference)
# 0
# 123
# 1~9999
# 001~077
# 0xFF, 0x01, 0xabc123
$ python3 Main.py input.txt
(content (number 0) \n (number 123) \n (number 1) ~ (number 9999) \n (number 001) ~ (number 077) \n (number 0xFF) , (number 0x01) , (number 0xabc123) \n <EOF>)
0, dec: 0 , oct: None , hex: None
123, dec: 123 , oct: None , hex: None
1, dec: 1 , oct: None , hex: None
9999, dec: 9999 , oct: None , hex: None
001, dec: None , oct: 001 , hex: None
077, dec: None , oct: 077 , hex: None
0xFF, dec: None , oct: None , hex: 0xFF
0x01, dec: None , oct: None , hex: 0x01
0xabc123, dec: None , oct: None , hex: 0xabc123
आप के लिए संशोधक 'टुकड़ा' जोड़ देते हैं तो DECIMAL_NUMBER
, OCTAL_NUMBER
, HEXADECIMAL_NUMBER
, आप नंबर संस्थाओं पर कब्जा करने में सक्षम नहीं होगा (क्योंकि वे टोकन अब और नहीं हैं)। और परिणाम होगा:
$ python3 Main.py input.txt
(content 0 \n 1 2 3 \n 1 ~ 9 9 9 9 \n 0 0 1 ~ 0 7 7 \n 0 x F F , 0 x 0 1 , 0 x a b c 1 2 3 \n <EOF>)
इस ब्लॉग पोस्ट का एक बहुत ही स्पष्ट उदाहरण है जहां fragment
एक महत्वपूर्ण अंतर है:
grammar number;
number: INT;
DIGIT : '0'..'9';
INT : DIGIT+;
व्याकरण '42' को मान्यता देगा लेकिन '7' को नहीं। आप इसे अंक को एक टुकड़ा बनाकर (या INT के बाद DIGIT को स्थानांतरित करके) ठीक कर सकते हैं।
fragment
, लेकिन लेक्सर नियमों का क्रम है।
DIGIT
का एक टुकड़ा के रूप में घोषित INT
करना सिर्फ इसलिए समस्या है क्योंकि टुकड़े टोकन को परिभाषित नहीं करते हैं, इस प्रकार INT
पहला शाब्दिक नियम बनाते हैं । मैं आपसे सहमत हूं कि यह एक सार्थक उदाहरण है लेकिन (imo) केवल उनके लिए जो पहले से ही जानते हैं कि fragment
कीवर्ड का क्या मतलब है। मुझे यह किसी के लिए भ्रामक लगता है जो पहली बार टुकड़ों के सही उपयोग का पता लगाने की कोशिश कर रहा है।
fragment
ANTLR में क्या मतलब है के बारे में सही हैं । लेकिन जो उदाहरण आप देते हैं वह एक खराब है: आप एक लेक्सर को एकNUMBER
टोकन का उत्पादन करने के लिए नहीं चाहते हैं जो एक हेक्स, दशमलव या अष्टक संख्या हो सकती है। इसका मतलब है कि आपकोNUMBER
उत्पादन (पार्सर नियम) में टोकन का निरीक्षण करना होगा । बेहतर होगा कि तुम lexer उपज दे सकता हैINT
,OCT
औरHEX
टोकन और एक उत्पादन नियम बनाएं:number : INT | OCT | HEX;
। इस तरह के एक उदाहरण में, एकDIGIT
टुकड़ा हो सकता है जिसका उपयोग टोकनINT
और द्वारा किया जाएगाHEX
।