perl6语法,不确定示例中的某些语法

lis*_*tor 16 regex grammar perl6 raku

我还在学习perl6,我正在阅读这个页面上的语法示例:http://examples.perl6.org/categories/parsers/SimpleStrings.html ; 我已多次阅读有关正则表达式的文档,但仍有一些我不理解的语法; 任何人都可以开导我吗?非常感谢你 !!!

token string { <quote> {} <quotebody($<quote>)> $<quote> }
Run Code Online (Sandbox Code Playgroud)

问题1:令牌中的这个"{}"是做什么的?捕获标记为<()>,嵌套结构为tilda'('〜')'; 但是什么是{}?

token quotebody($quote) { ( <escaped($quote)> | <!before $quote> . )* }
Run Code Online (Sandbox Code Playgroud)

问题2a:在<>中转义($ quote)将是一个正则表达式函数,对吗?它需要$ quote作为参数并返回另一个正则表达式?

问题2b:如果我想表示"引用前没有的字符",我应该使用".$!before $ quote>"而不是"<!before $ quote>".??

token escaped($quote) { '\\' ( $quote | '\\' ) } # I think this is a function;
Run Code Online (Sandbox Code Playgroud)

非常感谢你 !!!

lisprog

bri*_*foy 8

{}是一个空代码块.它是语法的程序性(而不是声明性)元素.您可以在其中放置常规的Perl 6代码以使其执行某些操作.

在这种模式下,它正在做另一项工作.它提供了一个序列点,语法引擎知道它需要做各种事情才能继续.这包括填充捕获变量的值(例如$<quote>).模式的下一部分需要确保它$<quote>具有其价值,因此它需要一些东西来确保价值可用.

$<quote>实际上是匹配对象的单个元素访问$/.作为类似哈希的东西,这$/<quote>就是尖括号之间的东西是"关键".Perl 6的喜欢是一个小聪明所以它可以让你离开关/获得$<quote>.其他匹配变量,例如$1类似的快捷方式.

对于您的上一个问题,有助于查看您尝试匹配的一些示例数据.Perl 6 Grammars有许多功能可以匹配平衡文本,这可能使任务变得微不足道.例如,参见Regexp文档中的嵌套结构的Tilde:

 / '(' ~ ')' <expression> /
Run Code Online (Sandbox Code Playgroud)

这是REPL中的一个简短示例.有一个字符串,里面有一些带引号的文字:

$ perl6
To exit type 'exit' or '^D'
> my $s = Q/abcdf "Hello" xyz/
abcdf "Hello" xyz
Run Code Online (Sandbox Code Playgroud)

~在正则表达式是分隔符之间.在结束分隔符之后出现的东西是你期望的东西~:

> $s ~~ m/ '"' ~ '"' .+ /
?"Hello"?
Run Code Online (Sandbox Code Playgroud)

您可以匹配开头的东西并捕获它(现在它已经存在$0),因此您可以使用与结束分隔符完全相同的东西:

> $s ~~ m/ (<["']>) ~ $0 .+ /
?"Hello"?
 0 => ?"?
Run Code Online (Sandbox Code Playgroud)

对于那个特定的例子,我认为有一种更简单的方法.匹配转义的报价或任何非报价而不是环顾四周的任何字符.这不像心灵弯曲那样.


rai*_*iph 6

TL; DR @briandfoy提供了一个易于理解的答案.但这里有龙,他没有提到.还有漂亮的蝴蝶.这个答案很深入.

问题1:{}令牌中的这个是什么?

这是代码块1,2,3,4.

它是一个空的,并且纯粹插入以强制$<quote>in quotebody($<quote>)来评估<quote>正则表达式开头捕获的值.

为什么原因$<quote>包含正确的值没有一个代码块的插入是与"匹配变量的出版物"一个Rakudo Perl 6的编译器的限制或缺陷.

Rakudo的"出版"匹配变量

Moritz Lenz在Rakudo错误报告中指出"除非认为有必要,否则正则表达式引擎不会发布匹配变量".

通过"正则表达式引擎",他指的是NQP中的正则表达式/语法引擎,它是Rakudo Perl 6编译器的一部分.3

通过"匹配变量",他表示存储匹配结果捕获的变量:

  • 所述当前匹配变量 $/ ;

  • 所述编号的子匹配变量$0,$1等;

  • 命名的表单子匹配变量$<foo>.

通过"发布",他意味着正则表达式/语法引擎做了所需的事情,因此任何提及正则表达式中的任何变量(一个令牌也是正则表达式)都会评估它们应该具有的值.拥有他们.在给定的正则表达式中,匹配变量应该包含一个Match对象,对象对应于在处理该正则表达式的任何给定阶段为它们捕获的对象,或者Nil如果没有捕获任何内容.

通过"认为必要",他意味着正则表达式/语法引擎在匹配过程中的每个步骤之后对是否值得进行发布工作做出保守的调用."保守"是指引擎经常避免发布,因为它减慢了速度并且通常是不必要的.不幸的是它是什么时候发布有时过于乐观真正必要的.因此,程序员有时需要通过显式插入代码块来强制发布匹配变量(以及其他变量的其他技术5)进行干预.随着时间的推移,正则表达式/语法引擎可能会在这方面有所改进,从而减少了需要手动干预的情况.如果您希望帮助我们取得进展,请创建与您相关的现有相关错误的测试用例.

"出版" $<quote>的价值

命名捕获$<quote>就是这里的例子.

据我所知,所有子匹配变量在没有周围构造的情况下直接写入正则表达式时正确引用其捕获的值.这有效:

my regex quote { <['"]> }
say so '"aa"' ~~ / <quote> aa $<quote> /; # True
Run Code Online (Sandbox Code Playgroud)

我认为6 $<quote>得到了正确的值,因为它被解析为正则表达式俚语构造.4

相反,如果{}从中删除

token string { <quote> {} <quotebody($<quote>)> $<quote> }
Run Code Online (Sandbox Code Playgroud)

然后$<quote>in quotebody($<quote>)包含开头捕获的值<quote>.

我认为这是因为$<quote>在这种情况下解析为主要的俚语构造.

问题2a:escaped($quote)里面<>会是一个正则表达式函数,对吧?它需要$quote作为一个论点

这是一个很好的初步近似值.

更具体地说,该形式的正则表达式原子<foo(...)>是该方法的 调用foo.

所有的正则表达式-是否与申报token,regex,rule,/.../或任何其他形式-是方法.但随着声明的方法method不是正则表达式:

say Method ~~ Regex; # False
say WHAT token { . } # (Regex)
say Regex ~~ Method; # True
say / . / ~~ Method; # True
Run Code Online (Sandbox Code Playgroud)

<escaped($quote)>遇到正则表达式原子,正则表达式/语法引擎不知道或不关心,如果escaped是正则表达式或没有,也没有关于法派的正则表达式或语法中的细节.它只调用方法调度,将调用剂设置Match为由封闭正则表达式构造的对象.

该调用将控制权交给运行该方法的任何操作.通常情况下,正则表达式/语法引擎只是递归地回调自身,因为通常它是一个正则表达式调用另一个正则表达式的问题.但并不一定如此.

并返回另一个正则表达式

不,表单的正则表达式原子<escaped($quote)>不会返回另一个正则表达式.

相反,它调用一个将/应该返回一个Match对象的方法.

如果调用的方法是正则表达式,P6将确保正则表达式Match自动生成并填充对象.

如果调用的方法不是正则表达式而是普通方法,那么方法的代码应该手动创建并返回一个Match对象.Moritz在回答SO问题时展示了一个例子我可以在方法中更改Perl 6俚语吗?.

Match对象返回到驱动正则表达式匹配/语法分析的"正则表达式/语法引擎".3

然后引擎根据结果决定下一步做什么:

  • 如果匹配成功,则引擎更新与调用正则表达式相对应的整体匹配对象.更新可以包括将返回的Match对象保存为调用正则表达式的子匹配捕获.这就是匹配/解析的构建方式.

  • 如果匹配不成功,引擎可能会回溯,撤消之前的更新; 因此,随着匹配的进行,解析树可以动态地增长和缩小.

问题2b:如果我想表明"引用之前没有的字符",我应该使用. <!before $quote>而不是<!before $quote> .??

是.

但这不是quotebody正则表达式所需要的,如果这就是你所说的.

在后一个主题中,在@ briandfoy的回答中,他建议使用"匹配......任何不是引用的东西"构造而不是做出负面展望(<!before $quote>).他的观点是,匹配"不是引用"比"我们不是在引用之前?然后匹配任何字符"更容易理解.

但是,当报价是一个变量,其值被设置为开头报价的捕获时,这绝不是直截了当的.这种复杂性是由于Rakudo的错误造成的.我已经找到了我认为最简单的方法,但认为最好坚持使用<!before $quote> .除非/直到这些长期存在的Rakudo错误得到修复.

token escaped($quote) { '\\' ( $quote | '\\' ) } # I think this is a function;

它是一个令牌,它是一个Regex,它是一个Method,它是Routine:

say token { . } ~~ Regex;   # True
say Regex       ~~ Method;  # True
say Method      ~~ Routine; # True
Run Code Online (Sandbox Code Playgroud)

{ ... }正则表达式的正文中的代码(在这个例子中代码是孤立.token { . },这是一个与单个字符匹配的正则表达式原子)写在P6正则表达式"俚语"中,而在正文中使用的代码一个method例程写在主P6"俚语"中.4

运用 ~

正则表达式代字号(~)算子是专门为那种在这个问题是关于示例解析的设计.它读起来更好,因为它可以立即识别并保持开始和结束报价在一起.更重要的是,它可以在发生故障时提供人类可理解的错误消息,因为它可以说明它正在寻找什么结束分隔符.

但是,如果在正则表达式~运算符(在其两侧)旁边的正则表达式(带或不带代码)中插入代码块,则必须考虑一个关键的问题.除非您特别希望代字块将代码块视为自己的原子,否则您需要对代码块进行分组.例如:

token foo { <quote> ~ $<quote> {} <quotebody($<quote>) }
Run Code Online (Sandbox Code Playgroud)

将匹配一对<quote>s 之间没有任何东西.(然后尝试匹配<quotebody...>.)

相比之下,这是一种stringString::Simple::Grammar语法中复制令牌的匹配行为的方法:

token string { <quote> ~ $<quote> [ {} <quotebody($<quote>) ] }
Run Code Online (Sandbox Code Playgroud)

脚注

1 2002年,拉里·沃尔写道:"正则表达式调用Perl代码就像Perl代码调用正则表达式一样容易." .计算机科学家指出,您不能在传统的正则表达式中使用过程代码.但Perls很久以前就转向了非传统的正则表达式,而P6已经得出了合乎逻辑的结论 - {...}只需在正则表达式中插入任意过程代码即可.语言设计和正则表达式/语法引擎实现3确保正则表达式中的传统样式纯粹声明性区域被识别,因此正式的正则表达式理论和优化可以应用于它们,但是也可以插入任意的常规过程代码.简单用途包括匹配逻辑调试.但天空是极限.

2正则表达式的第一个程序元素(如果有的话)终止正则表达式的"声明性前缀".插入空代码块({})的一个常见原因是,当为正则表达式中给定的最长交替提供所需的匹配语义时,故意终止正则表达式的声明性前缀.(但这不是将其包含在您试图理解的令牌中的原因.)

3松散地说,NQP中的正则表达式/语法引擎是P6 到P5的PCRE.

一个关键的区别是正则表达式语言及其相关的正则表达式/语法引擎,以及它与之合作的主要语言(在Rakudo的情况下是Perl 6)是控制方式的共同等同.这是Larry Wall最初2002年关于正则表达式与"富语言"之间整合的愿景的实现.每种语言/运行时都可以调用另一种语言/运行时通过高级FFI进行通信.因此,他们可以表现为,可以表现为,甚至是单一的合作语言系统和合作的运行时间.

(P6设计使得所有语言都可以通过两个互补的P6 FFI以"丰富"的方式进行明确设计或改造,以便以"丰富"的方式进行协作:元模型FFI 6模型和/或C调用约定FFI NativeCall.)

4 P6语言实际上是一起使用的子语言(即俚语)的集合.当您正在阅读或编写P6代码时,您正在阅读或编写源代码,这些源代码以一个俚语开头,但其他部分中写有部分.文件中的第一行使用主俚语.让我们说这类似于英语.正则表达式是用另一个俚语写的; 让我们说这就像西班牙语.所以在的情况下,语法String::Simple::Grammar,代码英语(的开始use v6;语句),然后递归到西班牙(后{rule TOP {),即^ <string> $位,然后返回了成英文(注释开始# Note ...).然后它重新恢复为西班牙语<quote> {} <quotebody($<quote>)> $<quote>,在西班牙语中间,在{}代码块中,它再次递归到另一个级别的英语.这是英语中的西班牙语英语.当然,代码块是空的,所以它就像用英语写任何东西,然后立即回到西班牙语,但重要的是要理解这种语言/运行时间的递归堆叠是P6如何工作,两者都是单一的整体语言/运行时以及与其他非P6语言/运行时合作.

5我在这个脚注的末尾列出了几个错误,在应用两个潜在改进的过程中.(两者都在briandfoy的答案和这一个中提到.)两个"改进"是~构造的使用,而不是使用"非引用"构造<!before foo> ..最后的结果,再加上相关的错误:

grammar String::Simple::Grammar {
  rule TOP {^ <string> $}
  token string {
    :my $*not-quote;
    <quote> ~ $<quote>
    [
      { $*not-quote = "<-[$<quote>]>" }
      <quotebody($<quote>)>
    ]
  }
  token quote { '"' | "'" }
  token quotebody($quote) { ( <escaped($quote)> | <$*not-quote> )* }
  token escaped($quote) { '\\' ( $quote | '\\' ) }
}
Run Code Online (Sandbox Code Playgroud)

如果有人知道更简单的方法,我很乐意在下面的评论中听到它.

我最终在RT bugs数据库中搜索所有正则表达式错误.我知道这不是bug数据库,但我认为我注意以下几点是合理的.Aiui前两个直接与匹配变量的发布问题相互作用.

6这个问题和我的回答将我推到了对P6雄心勃勃和复杂方面的理解的外在极限.我计划很快就能更深入地了解nqp与完整P6之间的精确相互作用,以及正则俚语和主要俚语之间的切换,如上文脚注所述.(我的希望目前很大程度上取决于刚刚购买了commaide.)如果/当我有一些结果时,我会更新这个答案.