এএনটিএলআরতে "টুকরা" বলতে কী বোঝায়?


104

খণ্ডটি এএনটিএলআর এর অর্থ কী ?

আমি উভয় নিয়ম দেখেছি:

fragment DIGIT : '0'..'9';

এবং

DIGIT : '0'..'9';

পার্থক্য কি?

উত্তর:


115

একটি খণ্ড কিছুটা ইনলাইন ফাংশনের অনুরূপ: এটি ব্যাকরণকে আরও পাঠযোগ্য এবং বজায় রাখা সহজ করে তোলে।

কোনও খণ্ডকে কখনই টোকেন হিসাবে গণনা করা হবে না, এটি কেবলমাত্র একটি ব্যাকরণকে সহজতর করে তোলে।

বিবেচনা:

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" এর সাথে মিল রেখে তা নির্বিশেষে।

আইটেম 3 দেখুন


43
আপনি fragmentএএনটিএলআর এর অর্থ সম্পর্কে ঠিক বলেছেন । তবে আপনি যে উদাহরণটি দিয়েছেন তা একটি দরিদ্র: আপনি কোনও লেক্সারকে একটি NUMBERটোকেন তৈরি করতে চান না যা একটি হেক্স, দশমিক বা অষ্টাল সংখ্যা হতে পারে। এর অর্থ হ'ল আপনাকে NUMBERএকটি উত্পাদনের (পার্সার বিধি) টোকেনটি পরীক্ষা করতে হবে । আপনি ভাল lexer উপস্থিত করুক পারে INT, OCTএবং HEXটোকেন এবং একটি প্রকাশনা নিয়ম তৈরি করুন: number : INT | OCT | HEX;। যেমন একটি উদাহরণে, একটি DIGITএকটি টুকরা হতে পারে যা টোকেন INTএবং ব্যবহার করবে HEX
বার্ট কায়ার্স

10
মনে রাখবেন যে "দরিদ্র" কিছুটা কঠোর মনে হতে পারে, তবে আমি এর চেয়ে ভাল শব্দটি খুঁজে পেলাম না ... দুঃখিত! :)
বার্ট কায়ার্স

4
আপনি কঠোর শব্দ করছেন না .. আপনি ঠিক এবং সোজা ছিল!
অ্যাসিঙ্কয়েট

4
গুরুত্বপূর্ণভাবে, খণ্ডগুলি কেবলমাত্র অন্যান্য লেক্সার টোকেনগুলি সংজ্ঞায়িত করতে অন্যান্য লেক্সারের নিয়মে ব্যবহার করার উদ্দেশ্যে। খণ্ডগুলি ব্যাকরণ (পার্সার) বিধিগুলিতে ব্যবহার করার উদ্দেশ্যে নয়।
ডিজেবি

4
@ বার্টকায়ার্স: আপনি কি আরও ভাল উত্তর সহ একটি নতুন উত্তর তৈরি করতে পারে?
ডেভিড নিউকম্ব

18

সংজ্ঞাবদ্ধ 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 নিয়মগুলি স্পষ্টভাবে ব্যবহার করা যাবে না।


11

সংজ্ঞাযুক্ত এএনটিএলআর 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 (?)


কেস 1 এবং কেস 2/3 এর মধ্যে পার্থক্য?

  1. লেক্সারের নিয়ম সমান
  2. কেস 1 এর প্রতিটি RULE1 / 2/3 এর একটি ক্যাপচারিং গ্রুপ, রেজেক্সের মতো: (এক্স)
  3. কেস 3 এর প্রত্যেকটি RULE1 / 2/3 একটি রেজিেক্স :(?: এক্স এর মতো) একটি নন-ক্যাপচারিং গ্রুপ X এখানে চিত্র বর্ণনা লিখুন



আসুন একটি কংক্রিট উদাহরণ দেখুন।

গোল: চিহ্নিত [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()


কেস 1 এবং ফলাফল:

বর্ণমালা.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


কেস 2/3 এবং ফলাফল:

বর্ণমালা.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>)

আপনি কি "ক্যাপচারিং গ্রুপ" এবং "নন-ক্যাপচারিং গ্রুপ" অংশগুলি দেখেছেন ?




এর কংক্রিট উদাহরণ 2 দেখুন।

লক্ষ্য: অষ্টাল / দশমিক / হেক্সাডেসিমাল সংখ্যা সনাক্ত করুন

ইনপুট.টেক্সট

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>)

8

এই ব্লগ পোস্টটিতে একটি স্পষ্ট উদাহরণ রয়েছে যেখানে fragmentউল্লেখযোগ্য পার্থক্য রয়েছে:

grammar number;  

number: INT;  
DIGIT : '0'..'9';  
INT   :  DIGIT+;

ব্যাকরণটি '42' স্বীকৃতি দেবে তবে '7' নয়। আপনি অঙ্কটি একটি টুকরো টুকরো করে তৈরি করতে পারেন (বা আইএনটির পরে ডিজিট সরিয়ে নিয়ে যাবেন)।


4
এখানে সমস্যাটি কীওয়ার্ডের অনুপস্থিতি নয় fragment, তবে লেক্সারের নিয়মের ক্রম।
ব্ল্যাকব্রেন 16

আমি "ফিক্স" শব্দটি ব্যবহার করেছি, তবে বিষয়টি কোনও সমস্যা সমাধানের নয়। আমি এখানে এই উদাহরণটি যুক্ত করেছি কারণ, আমার কাছে, কীওয়ার্ড খণ্ডটি ব্যবহার করার সময় আসলে কী পরিবর্তিত হয় তার এটি সবচেয়ে সহায়ক এবং সাধারণ উদাহরণ ।
ভেসাল

4
আমি কেবল যুক্তি দিচ্ছি যে টুকরো টোকেন সংজ্ঞায়িত না করে টুকরো টুকরাকটি সংজ্ঞা দেয় না, কারণ খণ্ডিত DIGITটুকরা হিসাবে ঘোষণার INTফলে সমস্যার সমাধান হয় INT। আমি আপনার সাথে একমত হই যে এটি অর্থবহ উদাহরণ, তবে (ইমো) কেবলমাত্র যারা ইতিমধ্যে fragmentকীওয়ার্ডটির অর্থ কী তা জানেন । আমি প্রথমবারের জন্য টুকরো টুকরোটির সঠিক ব্যবহার খুঁজে বের করার চেষ্টা করছে এমন ব্যক্তির জন্য এটি কিছুটা বিভ্রান্তিকর বলে মনে করি।
ব্ল্যাকব্রেন

4
সুতরাং যখন আমি এটি শিখছিলাম, আমি উপরেরগুলির মতো প্রচুর উদাহরণ দেখেছি, তবে কেন এটির জন্য অতিরিক্ত কীওয়ার্ডের প্রয়োজন হবে তা আমি খুব একটা দেখতে পাইনি। বাস্তবে এটি "তাদের নিজস্ব টোকেন" না বোঝার অর্থ আমি বুঝতে পারি নি। এখন, আমি আসল প্রশ্নের সঠিক উত্তরটি কী হবে তা আমি আসলে নিশ্চিত নই। আমি গৃহীত উত্তরের সাথে কেন সন্তুষ্ট নই তার উপরে আমি একটি মন্তব্য যুক্ত করব।
ভেসাল
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.