Raku 编程/语法
正则表达式本身很有用,但有限制。重用正则表达式可能很困难,将它们分组到逻辑块中也很困难,并且从一个块继承正则表达式非常困难。这就是语法发挥作用的地方。语法与正则表达式之间的关系,就像类与数据和代码例程之间的关系。语法允许正则表达式像编程语言的普通一等公民一样行事,并利用类系统的强大功能。语法可以像类一样继承和重载。事实上,Raku 语法本身可以被修改,以便在运行时向语言添加新功能。我们将在后面看到这些示例。
语法被分解为称为规则、标记和原型的组件。标记就像我们已经见过的正则表达式。规则就像子例程,因为它们可以调用其他规则或标记。原型就像默认的多子例程,它们定义了一个可以被覆盖的规则原型。
标记是不回溯的正则表达式,这意味着如果表达式的一部分已匹配,则即使它阻止表达式更大的一部分匹配,这部分也不会被改变。虽然这牺牲了正则表达式的一些灵活性,但它允许以更高效的方式创建更复杂的解析器。
token number {
\d+ ['.' \d+]?
}
规则是将标记和其他规则组合在一起的方式。所有规则都将被赋予名称,并且可以使用< >
尖括号引用同一语法中的其他规则或标记。与标记一样,它们也不回溯,但它们内部的空格将按字面解释,而不是被忽略。
rule URL {
<protocol>'://'<address>
}
此规则匹配一个 URL 字符串,其中包含像 "ftp" 或 "https" 这样的协议名称,后面跟着文字符号 "://",然后是一个表示地址的字符串。此规则依赖于两个子规则,<protocol>
和 <address>
。它们可以定义为标记或规则,只要它们在同一个语法中。
grammar URL {
rule TOP {
<protocol>'://'<address>
}
token protocol {
'http'|'https'|'ftp'|'file'
}
rule address {
<subdomain>'.'<domain>'.'<tld>
}
...
}
原型定义了一种规则或标记类型。例如,我们可以定义一个原型标记 <protocol>
,然后定义几个表示不同协议的标记。在一个标记中,我们可以将它的名称引用为 <sym>
grammar URL {
rule TOP {
<protocol>'://'<address>
}
proto token protocol {*}
token protocol:sym<http> {
<sym>
}
token protocol:sym<https> {
<sym>
}
token protocol:sym<ftp> {
<sym>
}
token protocol:sym<ftps> {
<sym>
}
...
}
这相当于说
token protocol {
<http> | <https> | <ftp> | <ftps>
}
token http {
http
}
...
但是更具可扩展性,允许以后指定协议类型。例如,如果我们想定义一种新的 URL
类型,它也支持 "spdy" 协议,我们可以使用
grammar URL::WithSPDY is URL {
token protocol:sym<spdy> {
<sym>
}
}
一旦我们拥有了上面定义的语法,我们就可以使用 .parse
方法来匹配它
my Str $mystring = "http://www.wikibooks.org";
if URL.parse($mystring) {
#if it matches a URL, do something
}
匹配对象是一种特殊的 数据类型,它表示语法的解析状态。当前的匹配对象存储在特殊变量 $/
中。
通过将语法与解析器操作类组合,可以将语法转换为交互式解析器。当语法匹配某些规则时,可以使用当前匹配对象调用相应的操作方法。