6

(編集:pipe以下の関数は、オーバーロードが正しく機能するために祝福されたオブジェクトを返す必要があります。受け入れられた答えを参照してください。)

私はperlのoverload機能を使用して単純な解析ツリーを構築しようとしています。私は多くを必要としません-実際、私が必要とするのは、左結合である1つの演算子だけです。しかし、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 はスワップされた引数を true に設定することによって、その場合にハンドラーに通知します。

オーバーロード:

use overload ディレクティブで指定されたすべてのサブルーチンに 3 つの引数が渡されます (例外が 1 つあります。nomethod を参照してください)。[...] 2 つのオペランドが交換された場合 (およびその場合にのみ)、3 番目の引数は TRUE に設定されます。Perl は、最初の引数 ($self ) がオーバーロードされた操作を実装するオブジェクトであることを保証するために、一般的なオブジェクト呼び出し規約に従ってこれを行うことがあります。[...]

ハンドラーに渡された 3 番目の引数を無視しました。根本的な問題は、 からfooオブジェクトを返すのを忘れたことですpipe

于 2012-09-07T00:12:33.710 に答える
1

マルパをチェックする必要があります。このような構文解析の方が良いと思います。

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 に答える