2017-10-21 63 views
6

grammars不知道是否是爲了做這樣的事情:我想tokens在運行時被定義(在未來 - 從文件中的數據)。所以我寫了一個簡單的測試代碼,並且如預期那樣甚至不會編譯。將數據傳遞到形成語法規則在Perl 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>; 

在Perl 6中做這些事情的最好方法是什麼?

回答

6

要匹配任何一個數組的元素,只寫數組變量的名稱正則表達式(開始用@印記):

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; 

另一種方法是與陣列一個Capture傳遞給args副詞方法.parse的,這將傳給他們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

你採取的方法可能有效,但你犯了三個錯誤。

作用域

詞法變量聲明必須出現在編譯器遇到它們的使用文本方式前:

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聲明符具有完全一樣的效果相同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 +''類型的'tokens'後跟一個結尾,我終於發現,如果沒有回溯並將'token'改爲'regex',它就不會匹配。 –

+1

@evb注意可以寫'regex root {'或'token root {:!ratchet'。他們的意思完全一樣。 – raiph