2017-10-21 20 views
6

यकीन नहीं है कि नहीं grammars इस तरह के काम करने के लिए होती हैं: मैं चाहता हूँ tokens क्रम में परिभाषित किया जा करने के लिए (भविष्य में - एक फ़ाइल से डेटा के साथ)। तो मैंने एक साधारण परीक्षण कोड लिखा, और उम्मीद के अनुसार यह संकलित भी नहीं होगा।पासिंग डेटा पर्ल 6 में व्याकरण के नियमों के रूप में

grammar Verb { 
    token TOP { 
    <root> 
    <ending> 
    } 
    token root { 
    (\w+) <?{ ~$0 (elem) @root }> 
    } 
    token ending { 
    (\w+) <?{ ~$0 (elem) @ending }> 
    } 
} 

my @root = <go jump play>; 
my @ending = <ing es s ed>; 

my $string = "going"; 
my $match = Verb.parse($string); 
.Str.say for $match<root>; 

पर्ल 6 में ऐसी चीजों को करने का सबसे अच्छा तरीका क्या है?

उत्तर

6

एक सरणी के तत्वों में से किसी से मेल के लिए, बस सरणी चर का नाम लिखने (एक @ sigil से शुरू) regex में:

my @root = <go jump play>; 
say "jumping" ~~/@root /;  # Matches 「jump」 
say "jumping" ~~/@root 'ing' /; # Matches 「jumping」 
आपके उपयोग-मामले में

तो, केवल मुश्किल हिस्सा उस कोड से सरणी को पार कर रहा है जो उन्हें बनाता है (उदाहरण के लिए डेटा फ़ाइलों को पार्स करके), उन्हें आवश्यक व्याकरण टोकन में।

सबसे आसान तरीका शायद उन्हें गतिशील चर (* twigil द्वारा संकेतित) बनाने के लिए किया जाएगा:

grammar Verb { 
    token TOP { 
     <root> 
     <ending> 
    } 
    token root { 
     @*root 
    } 
    token ending { 
     @*ending 
    } 
} 

my @*root = <go jump play>; 
my @*ending = <ing es s ed>; 

my $string = "going"; 
my $match = Verb.parse($string); 

say $match<root>.Str; 

एक और तरीका है विधि .parse की args क्रिया विशेषण, करने के लिए सरणियों के साथ एक Capture पारित करने के लिए किया जाएगा जो उन्हें, token TOP तक पहुंचाया जहां से आप बदले में उन पर उप-नियमों के <foo(...)> या <foo: ...> सिंटैक्स का उपयोग पारित कर सकते हैं होगा:

grammar Verb { 
    token TOP (@known-roots, @known-endings) { 
     <root: @known-roots> 
     <ending: @known-endings> 
    } 
    token root (@known) { 
     @known 
    } 
    token ending (@known) { 
     @known 
    } 
} 

my @root = <go jump play>; 
my @ending = <ing es s ed>; 

my $string = "going"; 
my $match = Verb.parse($string, args => \(@root, @ending)); 

say $match<root>.Str; # go 
+0

वाह, यह पूरी तरह से अद्भुत है, विशेष रूप से एक सरणी मिलान! –

2

जो दृष्टिकोण आप ले रहे थे वह काम कर सकता था लेकिन आपने तीन गलतियां की थीं।

Scoping

शाब्दिक चर घोषणाओं से टेक्स्ट रूप से पहले संकलक उनके उपयोग का सामना करना पड़ता प्रकट करने के लिए की जरूरत है:

my $foo = 42; say $foo; # works 
say $bar; my $bar = 42; # compile time error 

बैकट्रेस

say .parse: 'going' for 

    grammar using-token    {token TOP {   \w+ ing}}, # Nil 
    grammar using-regex-with-ratchet {regex TOP {:ratchet \w+ ing}}, # Nil 
    grammar using-regex    {regex TOP {   \w+ ing}}; # 「going」 

regex declarator के रूप में बिल्कुल वैसा ही प्रभाव पड़ता है token घोषणाकर्ता सिवाय इसके कि यह करने के लिए डिफ़ॉल्ट है backtracking

root टोकन में \w+ का पहला उपयोग पूरे इनपुट 'going' है, जो तब @root के किसी भी तत्व से मिलान करने में विफल रहता है मेल खाता है। और फिर, क्योंकि कोई बैकट्रैकिंग नहीं है, समग्र पार्स तुरंत विफल हो जाता है।

(इसका मतलब यह नहीं है कि आपको regex का उपयोग करने के लिए डिफ़ॉल्ट होना चाहिए। बैकट्रैकिंग पर निर्भर करने से बड़े पैमाने पर पार्सिंग धीमा हो सकती है और इसकी आवश्यकता नहीं होती है।)

डिबगिंग

देखें https://stackoverflow.com/a/19640657/1077672


यह काम करता है:

my @root = <go jump play>; 
my @ending = <ing es s ed>; 

grammar Verb { 
    token TOP { 
    <root> 
    <ending> 
    } 
    regex root { 
    (\w+) <?{ ~$0 (elem) @root }> 
    } 
    token ending { 
    (\w+) <?{ ~$0 (elem) @ending }> 
    } 
} 

my $string = "going"; 
my $match = Verb.parse($string); 

.Str.say for $match<root>; 

आउटपुट:

go 
+1

यह एक महान टिप्पणी है! कई परीक्षणों के बाद आज '\ w +' प्रकार के विभिन्न 'टोकन' के साथ समाप्त होने के बाद, मुझे अंत में पता चला कि यह बैकट्रैकिंग के बिना मेल नहीं खाएगा और 'टोकन' को 'रेगेक्स' में बदल देगा। –

+1

@evb नोट कोई भी 'regex root {'या' टोकन रूट {:! Ratchet 'लिख सकता है। उनका मतलब बिल्कुल वही बात है। – raiph

संबंधित मुद्दे