Raku: कब्जा मार्करों का प्रभाव "उच्च अप" खो जाता है

Aug 15 2020

निम्नलिखित Raku स्क्रिप्ट:

#!/usr/bin/env raku
use v6.d;

grammar MyGrammar
{
    rule TOP { <keyword> '=' <value> }
    token keyword { \w+ }
    token value { <strvalue> | <numvalue> }
    token strvalue { '"' <( <-["]>* )> '"' }
    token numvalue { '-'? \d+ [ '.' \d* ]? }
}

say MyGrammar.parse('foo = 42');
say MyGrammar.parse('bar = "Hello, World!"');

निम्नलिखित आउटपुट है:

「foo = 42」
 keyword => 「foo」
 value => 「42」
  numvalue => 「42」
「bar = "Hello, World!"」
 keyword => 「bar」
 value => 「"Hello, World!"」
  strvalue => 「Hello, World!」

दूसरे मद, ध्यान दें कि के लिए strvalueके रूप में कब्जा बाजारों के साथ इरादा, उद्धरण चिह्नों के बिना स्ट्रिंग मान शामिल है <(... )>। हालांकि, मेरे आश्चर्य के लिए, उद्धरण में शामिल हैं value

क्या इसके चारों ओर एक रास्ता है?

जवाब

6 raiph Aug 15 2020 at 22:30

टीएल; डीआर "कई प्रेषण" का उपयोग करें। [१,२] देखें @ उपयोगकर्ता ०10०१० ९ ० ९ ०१ का उत्तर इस बात की गहन व्याख्या के लिए है कि चीजें जैसी हैं वैसी क्यों हैं। अपने व्याकरण में वास्तव में स्मार्ट परिवर्तन के लिए @ p6steve देखें यदि आप चाहते हैं कि आपका नंबर सिंटेक्स से राकस से मेल खाए।

एक बहु प्रेषण समाधान

क्या इसके चारों ओर एक रास्ता है?

एक तरीका स्पष्ट कई प्रेषण पर स्विच करना है।

वर्तमान में आपके पास एक valueटोकन है जो विशेष रूप से नामित वैरिएंट को कॉल करता है:

    token value { <strvalue> | <numvalue> }

उस के साथ बदलें:

    proto token value {*}

और फिर व्याकरण के अनुसार कई प्रेषण लक्ष्यीकरण नियमों के अनुसार टोकन का नाम बदलें, इसलिए व्याकरण बन जाता है:

grammar MyGrammar
{
    rule TOP { <keyword> '=' <value> }
    token keyword { \w+ }
    proto token value {*}
    token value:str { '"' <( <-["]>* )> '"' }
    token value:num { '-'? \d+ [ '.' \d* ]? }
}

say MyGrammar.parse('foo = 42');
say MyGrammar.parse('bar = "Hello, World!"');

यह प्रदर्शित करता है:

「foo = 42」
 keyword => 「foo」
 value => 「42」
「bar = "Hello, World!"」
 keyword => 「bar」
 value => 「Hello, World!」

यह डिफ़ॉल्ट रूप से अलग-अलग विकल्पों पर कब्जा नहीं करता है। हम "कई प्रेषण" के साथ रह सकते हैं, लेकिन उप-कैप्चर के नामकरण को फिर से शुरू कर सकते हैं:

grammar MyGrammar
{
    rule TOP { <keyword> '=' <value> }
    token keyword { \w+ }
    proto token value { * }
    token value:str { '"' <( $<strvalue>=(<-["]>*) )> '"' } token value:num { $<numvalue>=('-'? \d+ [ '.' \d* ]?) }
}

say MyGrammar.parse('foo = 42');
say MyGrammar.parse('bar = "Hello, World!"');

प्रदर्शित करता है:

「foo = 42」
 keyword => 「foo」
 value => 「42」
  numvalue => 「42」
「bar = "Hello, World!"」
 keyword => 「bar」
 value => 「Hello, World!」
  strvalue => 「Hello, World!」

आश्चर्य

मेरे आश्चर्य के लिए, उद्धरण में शामिल हैं value

मैं भी शुरू में हैरान था। [3]

लेकिन वर्तमान व्यवहार भी मुझे कम से कम निम्नलिखित इंद्रियों में समझ में आता है:

  • मौजूदा व्यवहार में कुछ परिस्थितियों में योग्यता है;

  • यह आश्चर्य की बात नहीं होगी अगर मैं यह उम्मीद कर रहा था, जो मुझे लगता है कि मैंने कुछ अन्य परिस्थितियों में अच्छा किया हो सकता है;

  • यह देखना आसान नहीं है कि यदि कोई व्यक्ति वर्तमान व्यवहार करना चाहता है तो उसे कैसे मिलेगा, लेकिन शुरू में आपसे (और I) अपेक्षा के अनुरूप काम किया गया था;

  • एक उपाय है, जैसा कि ऊपर कवर किया गया है।

फुटनोट

[1] कई प्रेषण का प्रयोग करें [2] है एक समाधान है, लेकिन बहुत जटिल लगता है imo मूल समस्या को देखते हुए। शायद वहाँ एक सरल समाधान है। शायद कोई इसे आपके प्रश्न के दूसरे उत्तर में प्रदान करेगा। यदि नहीं, तो मुझे उम्मीद है कि हमारे पास एक दिन में कम से कम एक बहुत सरल समाधान होगा। हालांकि, मुझे आश्चर्य नहीं होगा अगर हमें कई सालों तक एक नहीं मिलेगा। हमारे पास उपरोक्त समाधान है, और बहुत कुछ करना बाकी है।

[२] जब आपघोषणाकर सकते हैं , कह सकते हैं,method value:foo { ... }और एक विधि लिख सकते हैं (बशर्ते कि ऐसी प्रत्येक विधि एक मैच ऑब्जेक्ट लौटाती है), मुझे नहीं लगता है कि राकोडो सामान्य विधि-विधि प्रेषण तंत्र का उपयोग गैर-विधि नियम विकल्पों के लिए भेजने के लिए करता है, लेकिन इसके बजाय एक एनएफए ।

[३] कुछ लोग तर्क दे सकते हैं कि यह "चाहिए", "कर सकता है", या "होगा" "सबसे अच्छा" होगा यदि राकू ने हमारी अपेक्षा के अनुरूप किया। मुझे लगता है कि मैं अपने सबसे अच्छे विचारों को सोचता हूं अगर मैं आमतौर पर [श | सी | डब्ल्यू] से बचने के लिए बग / सुविधाओं के बारे में सोचता हूं जब तक कि मैं कोई भी लेने के लिए तैयार नहीं हूं और सभी डाउनसाइड्स जो दूसरों को ध्यान में रखते हैं और मदद करने के लिए आवश्यक काम करने के लिए तैयार हैं काम हो गया। तो मैं सिर्फ इतना कहूंगा कि मैं वर्तमान में इसे 10% बग, 90% फ़ीचर के रूप में देख रहा हूं, लेकिन "100% बग या" 100% फ़ीचर को स्विंग कर सकता है, यह इस बात पर निर्भर करता है कि मैं उस व्यवहार को देखना चाहता हूं या नहीं। , और दूसरों के विचार पर निर्भर करता है।

6 user0721090601 Aug 15 2020 at 22:46

<(और )>कब्जा मार्करों केवल एक दिए गए टोकन दिया भीतर काम करते हैं। मूल रूप से, प्रत्येक टोकन एक Matchऑब्जेक्ट देता है जो कहता है "मैंने इंडेक्स एक्स ( .from) से इंडेक्स वाई ( .to) तक मूल स्ट्रिंग का मिलान किया था, जिसे ऑब्जेक्ट्स को स्ट्रिंग करते समय ध्यान में रखा जाता है Match। यही आपके स्ट्रगल टोकन के साथ हो रहा है:

my $text = 'bar = "Hello, World!"'; my $m = MyGrammar.parse: $text; my $start = $m<value><strvalue>.from; # 7 my $end   = $m<value><strvalue>.to; # 20 say $text.substr: $start, $end - $start;  # Hello, World!

आप देखेंगे कि केवल दो नंबर हैं: एक स्टार्ट और फिनिश वैल्यू। यह पुरुषों कि जब आप अपने valueपास टोकन देखते हैं, तो यह एक असंतोषपूर्ण मैच नहीं बना सकता है। तो यह .from6 पर सेट है, और इसके .to21 तक।

इसके चारों ओर दो तरीके हैं: (a) एक एक्शन ऑब्जेक्ट या (b) एक मल्टीटोकन का उपयोग करके। दोनों के अपने फायदे हैं, और इस बात पर निर्भर करता है कि आप इसे एक बड़ी परियोजना में कैसे उपयोग करना चाहते हैं, आप एक या दूसरे के लिए विकल्प चुन सकते हैं।

जब आप तकनीकी रूप से एक व्याकरण के भीतर क्रियाओं को सीधे परिभाषित कर सकते हैं, तो उन्हें एक अलग वर्ग के माध्यम से करना बहुत आसान है। तो हम आपके लिए हो सकते हैं:

class MyActions { 
  method TOP      ($/) { make $<keyword>.made => $<value>.made }
  method keyword  ($/) { make ~$/ }
  method value    ($/) { make ($<numvalue> // $<strvalue>).made } method numvalue ($/) { make +$/ } method strvalue ($/) { make ~$/ }
}

प्रत्येक स्तर makeपर जो भी टोकन शामिल करने के लिए मानों को पास करता है। और संलग्नक टोकन में .madeविधि के माध्यम से उनके मूल्यों तक पहुंच है । यह वास्तव में अच्छा है जब, शुद्ध स्ट्रिंग मानों के साथ काम करने के बजाय, आप उन्हें पहले किसी में संसाधित करना चाहते हैं और एक वस्तु या समान बनाना चाहते हैं।

पार्स करने के लिए, आप बस करें:

my $m = MyGrammar.parse: $text, :actions(MyActions); say $m.made; # bar => Hello, World!

जो वास्तव में एक Pairवस्तु है। आप TOPविधि को संशोधित करके सटीक परिणाम बदल सकते हैं ।

दूसरा तरीका है कि आप चीजों के आसपास काम कर सकते हैं multi token। यह व्याकरण के विकास में काफी सामान्य है, जिसका उपयोग कुछ करने के लिए किया जाता है

token foo { <option-A> | <option-B> }

लेकिन जैसा कि आप एक्शन क्लास से देख सकते हैं, हमें यह देखने और देखने की आवश्यकता है कि वास्तव में किसका मिलान किया गया था। इसके बजाय, अगर विकल्प के साथ स्वीकार्य हो सकता है |, तो आप एक मल्टीटोकन का उपयोग कर सकते हैं:

proto token foo { * }
multi token:sym<A> { ... }
multi token:sym<B> { ... }

जब आप <foo>अपने व्याकरण में उपयोग करते हैं, तो यह दोनों बहु संस्करणों में से किसी एक से मेल खाएगा जैसे कि यह आधार रेखा में था <foo>। इससे भी बेहतर, यदि आप एक एक्शन क्लास का उपयोग कर रहे हैं, तो आप इसी तरह सिर्फ उपयोग कर सकते हैं $<foo>और यह जान सकते हैं कि यह बिना किसी शर्त या अन्य जांच के है।

आपके मामले में, यह इस तरह दिखेगा:

grammar MyGrammar
{
    rule TOP { <keyword> '=' <value> }
    token keyword { \w+ }
    proto token value { * }
    multi token value:sym<str> { '"' <( <-["]>* )> '"' }
    multi token value:sym<num> { '-'? \d+ [ '.' \d* ]? }
}

अब हम उन चीजों तक पहुंच सकते हैं, जैसा कि आप मूल रूप से अपेक्षा कर रहे थे, बिना किसी ऑब्जेक्ट ऑब्जेक्ट का उपयोग किए:

my $text = 'bar = "Hello, World!"';
my $m = MyGrammar.parse: $text;

say $m; # 「bar = "Hello, World!"」 # keyword => 「bar」 # value => 「Hello, World!」 say $m<value>; # 「Hello, World!」

संदर्भ के लिए, आप दोनों तकनीकों को जोड़ सकते हैं। यहां बताया गया है कि अब मैं मल्टी टोकन को दिए गए एक्शन ऑब्जेक्ट को कैसे लिखूंगा:

class MyActions { 
  method TOP            ($/) { make $<keyword>.made => $<value>.made } method keyword ($/) { make ~$/ } method value:sym<str> ($/) { make ~$/ } method value:sym<num> ($/) { make +$/ }
}

जो कि पहले लुक में कुछ ज्यादा ही ग्रैकेबल है।

2 p6steve Aug 16 2020 at 03:13

अपने स्वयं के टोकन मूल्य को रोल करने के बजाय: str & token मूल्य: संख्या जो आप Num (+) और Str (~) मिलान के लिए Regex Boolean जांच का उपयोग करना चाहते हैं - जैसा कि मुझे यहाँ समझाया गया है और यहाँ दस्तावेज किया गया है

token number { \S+ <?{ defined +"$/" }> } token string { \S+ <?{ defined ~"$/" }> }