খণ্ডটি এএনটিএলআর এর অর্থ কী ?
আমি উভয় নিয়ম দেখেছি:
fragment DIGIT : '0'..'9';
এবং
DIGIT : '0'..'9';
পার্থক্য কি?
খণ্ডটি এএনটিএলআর এর অর্থ কী ?
আমি উভয় নিয়ম দেখেছি:
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')+;
এই উদাহরণস্বরূপ, একটি সংখ্যার সাথে মিলে যাওয়া লেশারের সাথে সর্বদা একটি নম্বর ফিরিয়ে দেবে, "1234", "0xab12", বা "0777" এর সাথে মিল রেখে তা নির্বিশেষে।
সংজ্ঞাবদ্ধ Antlr4 রেফারেন্স বই অনুসারে:
খণ্ডের সাথে উপসর্গযুক্ত বিধিগুলি কেবলমাত্র অন্যান্য লেক্সারের বিধি থেকে বলা যেতে পারে; তারা তাদের নিজস্ব টোকেন হয় না।
আসলে এগুলি আপনার ব্যাকরণগুলির পাঠযোগ্যতার উন্নতি করবে।
এই উদাহরণটি দেখুন:
STRING : '"' (ESC | ~["\\])* '"' ;
fragment ESC : '\\' (["\\/bfnrt] | UNICODE) ;
fragment UNICODE : 'u' HEX HEX HEX HEX ;
fragment HEX : [0-9a-fA-F] ;
STRING হ'ল ইএসসির মতো টুকরো রুল ব্যবহার করে একটি লেসচার nic ESC এবং UNICODE এবং HEX নিয়মগুলি স্পষ্টভাবে ব্যবহার করা যাবে না।
সংজ্ঞাযুক্ত এএনটিএলআর 4 রেফারেন্স (পৃষ্ঠা 106) :
খণ্ডের সাথে উপসর্গযুক্ত বিধিগুলি কেবলমাত্র অন্যান্য লেক্সারের বিধি থেকে বলা যেতে পারে; তারা তাদের নিজস্ব টোকেন হয় না।
কেস 1: (আমার যদি RULE1, RULE2, RULE3 সত্তা বা গোষ্ঠী তথ্য প্রয়োজন হয়)
rule0 : RULE1 | RULE2 | RULE3 ;
RULE1 : [A-C]+ ;
RULE2 : [DEF]+ ;
RULE3 : ('G'|'H'|'I')+ ;
কেস 2: (আমি যদি 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]+
টোকেন
ইনপুট.টেক্সট
ABBCCCDDDDEEEEE ABCDE
FFGGHHIIJJKK FGHIJK
ABCDEFGHIJKL
মেইন.পি
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 (কেস 1)
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 (কেস 2)
grammar Alphabet;
content : (RULE0|ANYCHAR)* EOF;
RULE0 : [A-C]+ | [DEF]+ | ('G'|'H'|'I')+ ;
ANYCHAR : . -> skip;
বর্ণমালা.g4 (কেস 3)
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>)
আপনি কি "ক্যাপচারিং গ্রুপ" এবং "নন-ক্যাপচারিং গ্রুপ" অংশগুলি দেখেছেন ?
লক্ষ্য: অষ্টাল / দশমিক / হেক্সাডেসিমাল সংখ্যা সনাক্ত করুন
ইনপুট.টেক্সট
0
123
1~9999
001~077
0xFF, 0x01, 0xabc123
নাম্বার ৪
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
: .
;
মেইন.পি
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' নয়। আপনি অঙ্কটি একটি টুকরো টুকরো করে তৈরি করতে পারেন (বা আইএনটির পরে ডিজিট সরিয়ে নিয়ে যাবেন)।
fragment
, তবে লেক্সারের নিয়মের ক্রম।
DIGIT
টুকরা হিসাবে ঘোষণার INT
ফলে সমস্যার সমাধান হয় INT
। আমি আপনার সাথে একমত হই যে এটি অর্থবহ উদাহরণ, তবে (ইমো) কেবলমাত্র যারা ইতিমধ্যে fragment
কীওয়ার্ডটির অর্থ কী তা জানেন । আমি প্রথমবারের জন্য টুকরো টুকরোটির সঠিক ব্যবহার খুঁজে বের করার চেষ্টা করছে এমন ব্যক্তির জন্য এটি কিছুটা বিভ্রান্তিকর বলে মনে করি।
fragment
এএনটিএলআর এর অর্থ সম্পর্কে ঠিক বলেছেন । তবে আপনি যে উদাহরণটি দিয়েছেন তা একটি দরিদ্র: আপনি কোনও লেক্সারকে একটিNUMBER
টোকেন তৈরি করতে চান না যা একটি হেক্স, দশমিক বা অষ্টাল সংখ্যা হতে পারে। এর অর্থ হ'ল আপনাকেNUMBER
একটি উত্পাদনের (পার্সার বিধি) টোকেনটি পরীক্ষা করতে হবে । আপনি ভাল lexer উপস্থিত করুক পারেINT
,OCT
এবংHEX
টোকেন এবং একটি প্রকাশনা নিয়ম তৈরি করুন:number : INT | OCT | HEX;
। যেমন একটি উদাহরণে, একটিDIGIT
একটি টুকরা হতে পারে যা টোকেনINT
এবং ব্যবহার করবেHEX
।