“连续两个词”错误 [英] "Two terms in a row" error

查看:74
本文介绍了“连续两个词”错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试编写一个紧凑的行,如下所示,该代码是脚本的摘录,该脚本使用动态范围的特殊变量$ * IN读取STDIN。



这行得通

  for $ * IN.lines(){
最后一个时;
说 VERBOSE \ $ _是字符串\;
$ i = $ i + 1;
}



不起作用



  .say VERBOSE \ $ _是字符串\ for $ * IN.lines()最后当; 

错误输出:

  ===对不起!===编译/usr/share/asterisk/agi-bin/agi-t1.p6时出错
/ usr /处连续两个术语
share /星号/agi-bin/agi-t1.p6:5
------> .say⏏ Verbose \ $ _ \ for $ * IN.lines()最后
期望以下任何一个:
infix
infix stopper
语句结束
语句修饰符
语句修饰符循环


解决方案

错误消息的一般说明


  === SORRY!===编译时出错... 

当您看到 SORRY!时,您就知道编译器正在与您讨论发生的问题

 连续两个术语

这是编译器的英语摘要,说明停止其编译代码的原因。


------> 是编译器的说法,即被您所写的内容弄糊涂了,它会在 ------> 之后显示一些代码。


(Unicode名称为 EJECT SYMBOL 的字符)插入到代码显示中。插入的点应有助于解释错误消息。


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


什么是术语?


请考虑以下代码:

 开始时间+ 42 
总和(开始时间42)

术语有点像数学术语。这两个示例表达式都包含术语开始时间 42 。整个表达式开始时间+ 42 也是一个术语。表达式 sum(start-time,42)可以称为 sum()项或 sum(...)术语。


术语也有点像自然语言中的名词或名词短语开始时间 42 就像名词一样,因此是术语。 开始时间+ 42 sum(...)就像名词短语,每个短语也是一个术语

(顺便说一句,在与此问题相关的意义上,术语与解析终端有时并不相关,终端有时也称为术语。 )


现在,您可能可以猜测如果尝试编译本节开头的示例代码会发生什么:

 连续两行(缺少分号或逗号?)

第一行(开始时间+ 42 )是一个术语。 sum(start-time,42)是另一个术语。除行尾外,它们之间什么也没有。 Perl 6显然不希望连续使用两个术语,而在它们之间没有非术语,并且空格和行尾不算在内。


如何避免出现两个连续术语


运算符,例如中缀 + ,后缀()和我在以上示例中使用的infix 可以在运算符位置(术语前后,之间或周围)使用以形成表达式。 (然后,整个表达式本身就是上述术语了。)


诸如 for last 用作关键字位置,它们也是 not 术语(除非您疯狂地将其重新定义为术语,在这种情况下,您可能会得到应有的奇怪的编译错误。 :))但是,像运算符一样,它们必须放置在正确的位置,否则编译器可能会认为它们是术语。如果在错误的地方写了 last ,编译器可能会认为 last 是一个术语。


代码问题


编译器认为 .say (请注意末尾的空格)是一个项,相当于 .say()。因此,它将解释您写为 .say() VERBOSE ... 的内容,这是连续两个术语。


(我建议您只是接受这种说法,但是如果您想深入研究方法调用语法的细节,以完全理解为什么 invocant.foo(arrgh,arrgh,...); 也是连续两个术语,请参见我的回答,其中涉及与例程调用相关的各种语法。 )


通过将 .say 更改为 say (而不使用):

 说 VERBOSE \ $ _是字符串\ $ * IN.lines()表示最后的。 

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


for 关键字及其迭代参数必须在语句的开头或语句的结尾。


但这意味着 for 之后是一个术语(其迭代参数)。 。


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


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


但是您没有构建表达式,只是紧随 last $ * IN.lines() $ c>。


因为没有 last 中缀运算符和 last 必须是语句中的第一个单词,它才是 last 关键字,编译器会将 last 解释为一个字词-这样就可以看到连续两个字词。


您需要 last 作为语句关键字并且必须在 for 循环的上下文中。但是,您已经在 for 循环的上下文中有了一条语句,即 say ... 表达式/术语。您需要一些方括号或类似内容以允许您编写多个语句。这是一种方法:

  {最后是时;说 VERBOSE \ $ _是字符串 \。 } for $ * IN.lines(); 

现在您的代码有效。


最终调整


我不妨作一些最后的调整:

 (最后是''时;说qq [VERBOSE $ _ is行的字符串]; $ i ++); 



  • 我已从 {... } (...)。它不是更紧凑,但是它表明,当 for 写为语句修饰符时(即,在语句的末尾而不是在开始时),可以使用括号而不是大括号。 )。 {...} 创建词法作用域,而(...)不会;在某些情况下,一个或另一个正是您所需要的。



  • 您不需要 $ * IN。,因为有一个 lines 子项等效于 $ * IN.lines()



  • 我在之后删除了(),因为如果(或 $ * IN.lines )和语句结尾之前。



  • 我用过''而不是 ,因为如果不需要插值,我认为使用非插值是一个好习惯。



  • 我使用了 qq [...] ,因为这意味着您不必逃避字符串中的



  • 我用过 $ i ++ 而不是 $ i = $ i + 1 ,因为它达到相同的效果,而且我认为它读起来更好。




I am trying to write a compact line as below, the code is an extract from a script that reads STDIN by using the dynamically scoped special variable $*IN. Can you please advise how to write this line correctly?

This works

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

does not work

.say "VERBOSE \"$_ is the string\"" for $*IN.lines() last when "";

error output:

===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

解决方案

A generic explanation of the error message

===SORRY!=== Error while compiling ...

When you see a SORRY!, then you know the compiler is talking to you about a problem that happened during compilation, even before there was an attempt to run your code.

Two terms in a row

This is the compiler's English summary of about what stopped it compiling your code. We'll return to it later.

The ------> is the compiler's way of saying that it was confused by what you've written and it's going to display some of your code after the ------>.

The , a character whose Unicode name is EJECT SYMBOL, is inserted into the display of your code. The point it's inserted should help in interpreting the error message.

In this case it points between .say and "VERBOSE...". The compiler thinks those are two terms in a row.

What is a term?

Consider the following code:

start-time + 42
sum(start-time, 42)

Terms are somewhat like terms in mathematics. Both the example expressions include the terms start-time and 42. The overall expression start-time + 42 is also a term. The expression sum(start-time, 42) might be called the sum() term or sum(...) term.

Terms are also somewhat like nouns or noun phrases in natural language. start-time and 42 are like nouns, hence terms. start-time + 42 and sum(...) are like noun phrases, each of which is also a term.

(Btw, terms, in the sense relevant to this question, are not related to parsing "terminals" which are sometimes called "terms".)

By now you might be able to guess what happens if you try to compile the example code this section began with:

Two terms in a row across lines (missing semicolon or comma?)

The first line (start-time + 42) is a term. sum(start-time, 42) is another term. And there's nothing between them except a line end. Perl 6 clearly doesn't like two terms in a row without something that's not a term in between them and whitespace and line ends don't count.

How can one avoid the "Two terms in a row" error?

Operators like the infix +, postcircumfix (), and infix , that I used in the above examples can be used in operator positions (before, after, in between, or around, terms) to form expressions. (And the overall expressions are then themselves terms as explained above.)

Keywords like for or last, used in keyword position, are also not terms (unless you are crazy enough to redefine them as terms, in which case you'll likely get the weird compilation errors you deserve. :)) But, like operators, they must be placed in the right position or the compiler might think they're terms. If you write last in the wrong place, the compiler might think last is a term.

The problem with your code

The compiler considers .say (note the space at the end) to be a term, equivalent to .say(). So it interprets what you wrote as .say() "VERBOSE..." which is two terms in a row.

(I recommend you just accept that this is so but if you wish to dig into the minutia of method calling syntax to fully understand why invocant.foo ( arrgh, arrgh, ... ) ; is also "Two terms in a row", see my answer covering various syntaxes related to routine calls.)

Let's fix your code by changing the .say to say (without the .):

say "VERBOSE \"$_ is the string\"" for $*IN.lines() last when "";

The compiler returns another "Two terms in a row" error but now it points between $*IN.lines() and last.

The for keyword and its iteration argument have to be either at the start of a statement or at the end of a statement. You've used them at the end.

But that means that what comes after the for is a term (its iteration argument).

$*IN.lines() can work as a term.

You could even have it be part of an expression, eg. for flat $*IN.lines(), $*FOO.lines() to loop over both input lines and lines from some other handle. (The flat creates a single list for the for to loop over by flattening the two individual lists, one from $*IN.lines(), the other from $*FOO.lines().)

But you didn't build an expression, you just immediately followed $*IN.lines() with last.

Because there isn't a last infix operator and last must be the first word in a statement for it to be the last keyword, the compiler interprets the last as a term -- and so it sees "Two terms in a row".

You need the last to be a statement keyword and it needs to be in the context of the for loop. But you already have a statement in the context of the for loop, namely the say ... expression/term. You need some brackets or similar to allow you to write multiple statements. Here's one way:

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

Now your code works.

Final tweaks

I might as well throw in a couple final tweaks:

( last when ''; say qq[VERBOSE "$_ is the string"]; $i++ ) for lines ;

  • I've switched from {...} to (...). It's not more compact but it shows that you can use parens rather than braces when the for is written as a statement modifier (i.e. at the end of the statement rather than at the start). The {...} create a lexical scope whereas (...) does not; there are times where one or the other is just what you need.

  • You don't need the $*IN. because there's a lines sub that's equivalent to $*IN.lines().

  • I've dropped the () after lines because they're not needed if there are no arguments after lines (or $*IN.lines) and before the end of the statement.

  • I've used '' instead of "" because I think it's a good habit to use non-interpolating quotes if you don't need interpolating ones.

  • I've used qq[...] because that means you don't have to escape the " in the string.

  • I've used $i++ rather than $i=$i+1 because it achieves the same effect and I think it reads better.

这篇关于“连续两个词”错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆