为什么除法被解析为正则表达式?

Why is division parsed as regular expression?

这是我的代码的一部分:

        my $suma =  U::round $item->{ suma };  # line 36 
        $ts   +=  $suma;
        $tnds +=  U::round $suma /6;
    }

    return( $ts, $tnds );
}



sub create { #line 46
    my( $c ) =  shift;

    my $info =  $c->req->json;
    my $header  =  @$info[0];
    my $details =  @$info[1];

    my $agre =  D::T Agreement =>  $header->{ agreement_id };
    my( $total_suma, $total_nds ) =  total( $details );

    my $saldo    =  0;
    my $iid      =  @$details[0]->{ period };
    my $interval =  D::T Period => $iid //7; # line 58
    # This is first Invoice if operator do not provide activation date
    my $is_first =  !$details->[0]{valid_from}  &&  $iid  &&  $interval;

加载此模块时出现错误:

Can't load application from file "lib/MaitreD/Controller/ManualDocument.pm line 38, near "my $interval =  D::T Period => $iid /"
Unknown regexp modifier "/6" at lib/MaitreD/Controller/ManualDocument.pm line 38, at end of line
Global symbol "$pkg" requires explicit package name (did you forget to declare "my $pkg"?) at lib/MaitreD/Controller/ManualDocument.pm line 41.
...

这个间接对象调用有罪吗?

因为我在 U::round( $suma /6 ) 处加上括号时没有错误

Perl 认为符号 / 是正则表达式的开始而不是除法运算符。 https://perldoc.perl.org/perlre - 您可以检查 perldoc 中的正则表达式。 您可以尝试在 6 之前添加一个空白字符,如下所示:$tnds += U::round $suma / 6;

这里有一些关于此的想法,以及一个似是而非的解释。简单再现

perl -wE'sub tt { say "@_" }; $v = 7; tt $v /3'

给我

Search pattern not terminated at -e line 1.

因此它会尝试在该子例程调用中解析正则表达式,如前所述,问题是:为什么?

在参数周围加上括号,它按预期工作。如果后面有更多参数,它也会以同样的方式失败,但如果前面有参数,它就可以工作

perl -wE'sub tt { say "@_" }; $v = 7; tt $v /3, 3'  # fails the same way
perl -wE'sub tt { say "@_" }; $v = 7; tt 3, $v /3'  # works

tt 潜艇配备原型并不会改变这一切。

错误似乎是 / 触发了 search for the closing delimiter and once it's not found 整个事情都失败了。那么为什么这被解释为正则表达式而不是除法?

似乎 tt $v 在解析中被分组,并被解释为一个 sub 及其参数,因为它们后面跟着一个 space;然后 /3 被单独使用,然后它看起来像一个正则表达式。 这仍然会因为语法错误而失败,但也许正则表达式解析失败首先出现。

那么前面或后面的其他逗号分隔的术语之间的区别就很明显了——tt 3, ... 后面的 $v /3 是下一个参数的术语,并被解析为除法。

这还有一个问题。我尝试过的所有内置函数都没有这个问题,无论是列表运算符还是一元运算符,都有各种原型(pushchrsplice 等)——除了 print,它确实有同样的问题。并且无论有无括号都失败了。

perl -wE'$v=110; say for unpack "A1A1", $v /2'  #--> 5 5
perl -wE'$v=200; say chr $v /2'                 #--> d
perl -wE'$v=3; push @ary, $v /2; say "@ary"'    #--> 1.5

perl -wE'$v = 7; say $v /3'                     # fails, the same way
perl -wE'$v = 7; say( $v /3 )'                  # fails as well, same way

不同之处在于 print 遵循“特殊”解析规则,并且允许第一个参数是文件句柄。 (此外,它没有原型,但这似乎并不重要。)

那么表达式print $v /3...确实可以被解析为print filehandle EXPR,而/开头的EXPR被解析为正则表达式。同样适用于括号。

所有这些都涉及一些猜测,因为我不知道解析器是如何做到的。但这显然是如何解析子程序调用的细节问题,什么(不小心?)也包括 print

在我看来,在(用户定义的)子例程上使用括号的明显补救措施是合理的。另一个修复是与围绕数学运算符的 spaces 保持一致,要么不在任何一侧使用它们,要么在两侧都使用它们——这也很好,即使它很痒(spaces?真的吗?)。

虽然 say( $v /3 ) 存在问题,但我不知道该说些什么。

关于这个问题的更多评论。

根据问题中错误消息的文本 Unknown regexp modifier "/6",似乎 / 被用作结束分隔符,这与上面的示例不同。该消息中还有更多内容,尚不清楚。最后,我们确实有一个非常相似的解析问题。

至于

Is this indirect object call guilty?

我在那里没有看到间接对象调用,只有正常的子例程调用。此外,此答案中的示例显示了非常相似的行为并排除了间接对象语法。


另一种可能性是 $v /3 被解析为一个术语,因为它跟在(可识别的!)子例程名称 tt 之后。然后,正则表达式绑定运算符 =~ binds 比除法更紧密,这里暗示默认情况下明确尝试绑定到 $_

我发现这不太可能,而且它也无法解释内置函数的行为,尤其是 print


然后可以推断出其他具有可选的无逗号第一个参数(因此没有原型)的内置函数以相同的方式进行,但我不能轻易想到任何一个。