"连续两个术语"错误

Mah*_*van 7 compiler-errors syntax-error perl6

我正在尝试编写如下的紧凑行,代码是脚本的摘录,该脚本使用动态范围的特殊变量$*IN读取STDIN.你能告诉我如何正确写这条线吗?

这有效

for $*IN.lines() {
    last when "" ;
    say "VERBOSE \"$_ is the string\"";
    $i=$i+1;
}
Run Code Online (Sandbox Code Playgroud)

不起作用

.say "VERBOSE \"$_ is the string\"" for $*IN.lines() last when "";
Run Code Online (Sandbox Code Playgroud)

错误输出:

===SORRY!=== Error while compiling /usr/share/asterisk/agi-bin/agi-t1.p6
Two terms in a row
at /usr/share/asterisk/agi-bin/agi-t1.p6:5
------> .say? "Verbose \"$_\"" for $*IN.lines() last
expecting any of:
  infix
  infix stopper
  statement end
  statement modifier
  statement modifier loop
Run Code Online (Sandbox Code Playgroud)

rai*_*iph 6

错误消息的一般说明

===SORRY!=== Error while compiling ...
Run Code Online (Sandbox Code Playgroud)

当您看到a时SORRY!,您就知道编译器正在与您讨论编译期间发生的问题,甚至在尝试运行代码之前.

Two terms in a row
Run Code Online (Sandbox Code Playgroud)

这是编译器关于什么阻止它编译代码的英文摘要.我们稍后再回来.

------>是编译器说它被你写的东西搞糊涂的方式,并且会在你之后显示你的一些代码------>.

?,一个字的Unicode它的名字是EJECT SYMBOL,插入到你的代码的显示.它插入的点应该有助于解释错误消息.

在这种情况下,它指向.say"VERBOSE...".编译器认为这些是连续的两个术语.

什么是术语?

请考虑以下代码:

start-time + 42
sum(start-time, 42)
Run Code Online (Sandbox Code Playgroud)

术语有点像数学中的术语.两个示例表达式都包含术语start-time42.整体表达start-time + 42也是一个术语.表达式sum(start-time, 42)可以称为sum()术语或sum(...)术语.

术语也有点像自然语言中的名词或名词短语.start-time而且42就像名词一样.start-time + 42并且sum(...)像名词短语,每个都是一个术语.

(顺便说一句,术语,相关对这个问题的意义上说,是不是涉及到解析"终端",它有时也被称为"条款").

到目前为止,您可以猜测如果您尝试编译本节开头的示例代码会发生什么:

Two terms in a row across lines (missing semicolon or comma?)
Run Code Online (Sandbox Code Playgroud)

第一行(start-time + 42)是一个术语.sum(start-time, 42)是另一个术语.除了线端之外,它们之间没有任何东西.Perl 6显然不喜欢连续两个术语,没有在它们之间不是一个术语的东西,而且空格和行末端不计算.

如何避免"连续两个术语"错误?

我在上面的示例中使用的中缀+,postcircumfix ()和中缀等,运算符可以用于操作员位置(术语之前,之后,之间或周围)以形成表达式.(而整体表达本身就是如上所述的术语.)

关键词像for或者last,在关键词位置使用,也没有条款(除非你是够疯狂重新定义它们为条件,在这种情况下,你可能会得到你应得的奇怪的编译错误.:))但是,像运营商,他们必须被放置在正确的位置或编译器可能认为它们是条款.如果你last写错了地方,编译器可能认为last是一个术语.

您的代码存在问题

编译器认为.say(注意末尾的空格)是一个术语,相当于.say().所以它解释你写的.say() "VERBOSE..."是连续两个术语.

(我建议你只是接受这是如此,但是如果你想深入研究方法调用语法的细节以完全理解为什么invocant.foo ( arrgh, arrgh, ... ) ;也是"连续两个术语",请参阅我的答案,其中包含与常规调用相关的各种语法.)

让我们通过更改.sayto say(不带.)来修复代码:

say "VERBOSE \"$_ is the string\"" for $*IN.lines() last when "";
Run Code Online (Sandbox Code Playgroud)

编译器返回另一个"连续两个术语"错误,但现在它指向$*IN.lines()last.

for关键字及其迭代参数必须要么在声明的开头或在语句结束.你最后使用过它们.

但这意味着之后的for是一个术语(它的迭代论证).

$*IN.lines() 可以作为一个术语.

你甚至可以让它成为表达的一部分,例如.for flat $*IN.lines(), $*FOO.lines()从一些其他句柄循环输入行和行.(通过展平两个单独的列表flat创建一个for单独的列表,一个来自$*IN.lines(),另一个来自$*FOO.lines().)

但是你没有构建一个表达式,你只是紧接着$*IN.lines()last.

因为没有中last缀运算符,并且last必须是语句中的第一个单词才能成为last关键字,编译器会将其解释last为一个术语 - 因此它会看到"连续两个术语".

您需要last成为一个语句关键字,它需要在for循环的上下文中.但是你已经在for循环的上下文中有一个语句,即say ...表达式/术语.您需要一些括号或类似的东西来允许您编写多个语句.这是一种方式:

{ last when ""; say "VERBOSE \"$_ is the string\"" } for $*IN.lines();
Run Code Online (Sandbox Code Playgroud)

现在您的代码有效.

最后的调整

我不妨投入一些最后的调整:

( last when ''; say qq[VERBOSE "$_ is the string"]; $i++ ) for lines ;
Run Code Online (Sandbox Code Playgroud)
  • 我已经从切换{...}(...).它不是更紧凑,但它表明,当for写为语句修饰符时(即在语句的末尾而不是在开头),您可以使用parens而不是大括号.本{...}而创建一个词法范围(...)没有; 有时候一个或另一个就是你需要的.

  • 你不需要,$*IN.因为有一个lines等同于的子$*IN.lines().

  • 我已经放弃了()之后,lines因为如果在语句之后lines(或$*IN.lines)之前和结束之前没有参数,则不需要它们.

  • 我用过''而不是""因为我认为如果你不需要插值,那么使用非插值引号是一个好习惯.

  • 我已经使用过,qq[...]因为这意味着你不必"在字符串中转义.

  • 我用过$i++而不是$i=$i+1因为它达到了同样的效果,我觉得它看起来更好.