在 grammar 中, 有兩個 regex 的變體, rule 和 token。rule 默認不會回溯. rule 與 token 的一個重要區(qū)別就是, rule 這樣的正則采取了 :sigspace 修飾符。 rule 實際上是
regex :ratchet :sigspace { ... }
的簡寫. ratchet 這個單詞的意思是: (防倒轉(zhuǎn)的)棘齒, 意思它是不能回溯的! 而 :sigspace 表明正則中的空白是有意義的, 而 token 實際上是
regex :ratchet { ... }
的簡寫。 所以在 token 中, 若不是顯式的寫上 \s、\h、\n 等空白符號, 其它情況下就好像空白隱身了一樣, 雖然你寫了, 但是編譯器卻視而不見。
use v6;
use Grammar::Debugger;
grammar Token::Rule::Difference {
# 下面三者等價
# rule TOP { [\w+]+ % ' ' | [\d+]+ % ' ' } 等價于
# rule TOP { | [\w+]+ % ' ' | [\d+]+ % ' ' } 等價于
rule TOP { | [\w+]+ % ' '
| [\d+]+ % ' '
}
}
# $=finish.lines 中的每一行末尾都沒有換行符
for $=finish.lines -> $line {
print($line);
say Token::Rule::Difference.parse($line)
}
=finish
token takes whitespace invisible unless with sigspace
rule is a token without sigspace
2015 12 25
2016 01 07
說明在 rule 中, | 左右兩邊的空格會被忽略, 這通常是為了使格式對齊, 看起來不亂。另外 rule 中, 開頭和末尾的空白也會被忽略。
如果每一行都帶有換行符呢?
use v6;
use Grammar::Debugger;
grammar Token::Rule::Difference {
# token TOP { ^ [<line>\n]+ $ }
# token line {
# | [\w+]+ % ' '
# | [\d+]+ % ' '
# }
# 等價于
rule TOP { ^ <wrap>+ $}
token wrap { <line> }
rule line {
[\w+]+ % ' ' | [\d+]+ % <[-\s:]>
}
}
my $str = q:to/EOF/;
token takes whitespace invisible unless with sigspace
rule is a token without sigspace
2015-12-25 12:23
2016-01-07 13:45
EOF
my $parse = Token::Rule::Difference.parse($str);
say $parse;
token vs. rule
When we use rule in place of token, any whitespace after anatom is turned into a non-capturing call to ws
這句話是說, 在 rule 中, 任何跟在原子(atom)后面的空白會變成非捕獲的ws調(diào)用, 即 <.ws>,
rule entry { <key> '=' <value> }
等價于:
token entry { <key> <.ws> '=' <.ws> <value> <.ws> } # .抑制了捕獲
在 grammar 中, 我們繼承了默認的 ws, 但是我們也可以提供自己的 ws:
token ws { \h* } # 匹配水平空白, 不包括換行
rule 中空白的使用:
my $str = "Swift is hard to learn";
my token word { \w+ }
my rule line { <word>+ % [',' ] }
$str ~~ m:g/ <line> /;
逗號附近的方括號保證了 <.ws> 調(diào)用產(chǎn)生的空白作為分割符的一部分。這利用了 <.ws> 的一個特點:
在兩個 \w 之間解釋為 \s+, 其它地方解釋為 \s*。