6

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

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

这是我所拥有的:

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);

输出类似于:

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产生相同的输出 - 那么我如何区分它们呢?

我没有看到与右关联运算符相同的问题**

有解决办法吗?

4

3 回答 3

3
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)

产生:

bless(["x", "y", "z"], "foo")
于 2012-09-06T16:02:48.450 回答
2

重载的运算符处理程序有时会以相反的顺序接收操作数,但 Perl 会在接收时通过将 swapped 参数设置为 true 来通知处理程序。

过载

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

您忽略了传递给处理程序的第三个参数。根本问题是您忘记从pipe.

于 2012-09-07T00:12:33.710 回答
1

您应该检查 Marpa,我认为解析这样的事情会更好。

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

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

我认为这是您脚本中的错字:

my $p3 = $x || $y || $z;
于 2012-09-06T07:21:28.940 回答