首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么perl将$x | $y | $z解析为$z | ($x | $y)?

为什么perl将$x | $y | $z解析为$z | ($x | $y)?
EN

Stack Overflow用户
提问于 2012-09-06 13:43:18
回答 3查看 293关注 0票数 6

(编辑:下面的pipe函数应该返回一个受祝福的对象,以便重载正常工作。请参阅接受的答案。)

我正在尝试使用perl的overload功能来构建一个简单的解析树。我不需要太多-事实上,我只需要一个左联结运算符。但是,perl解析$x op $y的方式与$x op $y op $z op ...这样的长链解析方式似乎不一致。

这就是我所拥有的:

代码语言:javascript
复制
package foo;

use overload '|' => \&pipe,
             "**" => \&pipe,
             ">>" => \&pipe;

sub pipe { [ $_[0], $_[1] ] }

package main;

my $x = bless ["x"], "foo";
my $y = bless ["y"], "foo";
my $z = bless ["z"], "foo";
my $w = bless ["w"], "foo";

                               # how perl parses it:
my $p2 = $x | $y;              # Cons x y
my $p3 = $x | $y | $z;         # Cons z (Cons x y)
my $p4 = $x | $y | $z | $w;    # Cons w (Cons z (Cons x y))
my $p5 = $z | ($x | $y);       # same as p3???

my $s2 = $x ** $y;             # Cons x y
my $s3 = $x ** $y ** $z;       # Cons x (Cons y z)
my $s4 = $x ** $y ** $z ** $w; # Cons x (Cons y (Cons z w))

sub d { Dumper(\@_) }

say "p2 = ".d($p2);
say "p3 = ".d($p3);
say "p4 = ".d($p4);
say "p5 = ".d($p5);

say "s2 = ".d($s2);
say "s3 = ".d($s3);
say "s4 = ".d($s4);

输出类似于:

代码语言:javascript
复制
p2 = [bless( ['x'], 'foo' ),bless( ['y'], 'foo' )]
p3 = [bless( ['z'], 'foo' ),[bless( ['x'], 'foo' ),bless( ['y'], 'foo' )]]
p4 = [bless( ['w'], 'foo' ),[bless( ['z'], 'foo' ),[bless( ['x'], 'foo' ),bless( ['y'], 'foo' )]]]
p5 = [bless( ['z'], 'foo' ),[bless( ['x'], 'foo' ),bless( ['y'], 'foo' )]]

s2 = [bless( ['x'], 'foo' ),bless( ['y'], 'foo' )]
s3 = [bless( ['x'], 'foo' ),[bless( ['y'], 'foo' ),bless( ['z'], 'foo' )]]
s4 = [bless( ['x'], 'foo' ),[bless( ['y'], 'foo' ),[bless( ['z'], 'foo' ),bless( ['w'], 'foo' )]]]

难道p2不应该颠倒x和y来与其他情况保持一致吗?注意,p3p5产生相同的输出-那么我如何区分它们呢?

对于右关联操作符**,我没有看到同样的问题。

有没有解决这个问题的办法?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2012-09-07 00:02:48

代码语言:javascript
复制
use feature ":5.14";
use warnings FATAL => qw(all);
use strict;
use Data::Dump qw(dump pp);

sub foo() 
 {package foo;

  use overload '|' => \&p;

  sub p {bless [@{$_[0]},@{$_[1]}]}
 }

my $x = bless ["x"], "foo";
my $y = bless ["y"], "foo";
my $z = bless ["z"], "foo";

my $p = $x | $y | $z;

pp($p)

产生:

代码语言:javascript
复制
bless(["x", "y", "z"], "foo")
票数 3
EN

Stack Overflow用户

发布于 2012-09-07 08:12:34

重载运算符处理程序有时会以相反的顺序接收操作数,但是当Perl这样做时,它会通过将交换的参数设置为true来通知处理程序。

overload

将三个参数传递给use overload指令中指定的所有子例程(有一个例外-参见nomethod)。..。当(且仅当)两个操作数被交换时,第三个参数被设置为TRUE。Perl可以这样做,以确保第一个参数($self )是实现重载操作的对象,这符合一般的对象调用约定。...

您忽略了传递给处理程序的第三个参数。潜在的问题是您忘记从pipe返回一个foo对象。

票数 2
EN

Stack Overflow用户

发布于 2012-09-06 15:21:29

你应该检查一下Marpa,我认为它更适合解析这样的东西。

http://blogs.perl.org/users/jeffrey_kegler/2010/05/bnf-parsing-and-linear-time.html

https://metacpan.org/pod/Marpa::PP

我认为这是你的脚本中的一个打字错误:

代码语言:javascript
复制
my $p3 = $x || $y || $z;
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/12293640

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档