Parse::RecDescent - 从中​​获取信息

发布于 2024-07-23 08:38:22 字数 2103 浏览 3 评论 0原文

我正在 Perl 中使用 Parse::RecDescent 解析器,我似乎从中获取信息是最糟糕的。 网上现成的信息似乎没有重要的例子。

这是代码:

event_function: object_list ':' event_list ';'
        <defer:
        {       #item is a special character with Parse::Recdescent.
            print Dumper($item{object_list});
            $return = $item[1];
        }
        >
        | object_list ':' ';'
        <defer:
        { 
            print Dumper($item{object_list});
            $return = $item[1];
        }
        >

这是输出

PS W:\developers\paulnathan\rd_dir> perl parser.pl testfile
$VAR1 = 4;
$VAR1 = 8;
PS W:\developers\paulnathan\rd_dir>

输入文件解析正确。

stuff, stuff2: pre-operation event = {foo1, foo2};

应该输出一个以“stuff”、“stuff2”为键的哈希值。

想法?

编辑:

object_list : 
        object ',' object_list
        <defer:
        {

            my $retval = ();
            $retval = ::merge_hash_refs($item[1], $item[3]);

            $return = $retval;
        }
        >
        | object
        <defer:
        { 
            #print Dumper($item{object});
            $return = $item{object};
        }
        >       

    object : 
        '/' /[a-z0-9_][a-z0-9_]*/ '/' '...'
            <defer:
            {
                $::objects->{$item[2]} = "stuff";
                $return = $::objects;
            }
            >
        |  /[a-z0-9_][a-z0-9_]*/
            <defer:
            { 
                $::objects->{$item[1]} = "stuff";
                $return = $::objects;
            }
            >

编辑2: Merge_hash_refs,以防万一。 :-)

#takes two hash references.
sub merge_hash_refs {
    my($ref1, $ref2) = @_;
    my $retref = ();
    while( my ($k, $v) = each %$ref1 ) {
        $retref->{$k} = $v;
    }
    while( my ($k, $v) = each %$ref2 ) {
        $retref->{$k} = $v;
    }

    return $retref;
}

I'm working with the Parse::RecDescent parser in Perl, and I seem to have the most terrible time getting information from it. The information readily available online does not seem to have non-trivial examples.

Here is the code:

event_function: object_list ':' event_list ';'
        <defer:
        {       #item is a special character with Parse::Recdescent.
            print Dumper($item{object_list});
            $return = $item[1];
        }
        >
        | object_list ':' ';'
        <defer:
        { 
            print Dumper($item{object_list});
            $return = $item[1];
        }
        >

Here is the output

PS W:\developers\paulnathan\rd_dir> perl parser.pl testfile
$VAR1 = 4;
$VAR1 = 8;
PS W:\developers\paulnathan\rd_dir>

The input file parses correctly.

stuff, stuff2: pre-operation event = {foo1, foo2};

It should be outputting a hash keyed by "stuff", "stuff2".

Thoughts?

edit:

object_list : 
        object ',' object_list
        <defer:
        {

            my $retval = ();
            $retval = ::merge_hash_refs($item[1], $item[3]);

            $return = $retval;
        }
        >
        | object
        <defer:
        { 
            #print Dumper($item{object});
            $return = $item{object};
        }
        >       

    object : 
        '/' /[a-z0-9_][a-z0-9_]*/ '/' '...'
            <defer:
            {
                $::objects->{$item[2]} = "stuff";
                $return = $::objects;
            }
            >
        |  /[a-z0-9_][a-z0-9_]*/
            <defer:
            { 
                $::objects->{$item[1]} = "stuff";
                $return = $::objects;
            }
            >

edit2:
Merge_hash_refs, just in case. :-)

#takes two hash references.
sub merge_hash_refs {
    my($ref1, $ref2) = @_;
    my $retref = ();
    while( my ($k, $v) = each %$ref1 ) {
        $retref->{$k} = $v;
    }
    while( my ($k, $v) = each %$ref2 ) {
        $retref->{$k} = $v;
    }

    return $retref;
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

悍妇囚夫 2024-07-30 08:38:22

如果您在脚本中添加 use strict ,您将收到致命错误 Can't use string ("1") as a HASH ref while "strict refs" in use at [the调用merge_hash_refs]。 看来由 指令创建的闭包导致 @item 的内容成为产生式匹配时的内容,而不是最终由子规则。 删除 指令会给出以下输出:

$VAR1 = {
          'stuff2' => 'stuff',
          'stuff' => 'stuff'
        };

当然,这会产生副作用,即 $::object 会被成功的 object 生成更新,即使更高级别也是如此规则失败(包括回溯)。 我会这样写:

use strict;
use warnings;
use Parse::RecDescent;
use Data::Dumper;

my $parser = Parse::RecDescent->new(<<'EOT');
event_function: object_list ':' event_list(?) ';'
    {
        $return = $item[1];
    }

object_list : <leftop: object ',' object>
    {
        $return = { map { %$_ } @{$item[1]} };
    }

object : 
    '/' /[a-z0-9_][a-z0-9_]*/ '/' '...'
        {
            $return = { $item[2] => 'stuff' };
        }
    |  /[a-z0-9_][a-z0-9_]*/
        { 
            $return = { $item[1] => 'stuff' };
        }

# stub, don't know what this should be
event_list : /[^;]+/

EOT

my %object;

while (<DATA>) {
    my $x = $parser->event_function($_);

    next unless $x;

    # merge objects into master list
    while (my ($k, $v) = each %$x) {
        $object{$k} = $v;
    }
}

print Dumper \%object;

__DATA__
stuff, stuff2: pre-operation event = {foo1, foo2};
stuff3, stuff4: ;

输出是:

$VAR1 = {
          'stuff2' => 'stuff',
          'stuff3' => 'stuff',
          'stuff' => 'stuff',
          'stuff4' => 'stuff'
        };

If you add a use strict to your script you'll get the fatal error Can't use string ("1") as a HASH ref while "strict refs" in use at [the call to merge_hash_refs]. It appears that the closures created by the <defer> directives are causing the contents of @item to be the ones when the production matched instead of the hashrefs eventually returned by the subrules. Removing the <defer> directives gives me this output:

$VAR1 = {
          'stuff2' => 'stuff',
          'stuff' => 'stuff'
        };

Of course, this has the side effect that $::object is updated by successful object productions even if the higher level rules fail (including backtracking). I'd write it this way:

use strict;
use warnings;
use Parse::RecDescent;
use Data::Dumper;

my $parser = Parse::RecDescent->new(<<'EOT');
event_function: object_list ':' event_list(?) ';'
    {
        $return = $item[1];
    }

object_list : <leftop: object ',' object>
    {
        $return = { map { %$_ } @{$item[1]} };
    }

object : 
    '/' /[a-z0-9_][a-z0-9_]*/ '/' '...'
        {
            $return = { $item[2] => 'stuff' };
        }
    |  /[a-z0-9_][a-z0-9_]*/
        { 
            $return = { $item[1] => 'stuff' };
        }

# stub, don't know what this should be
event_list : /[^;]+/

EOT

my %object;

while (<DATA>) {
    my $x = $parser->event_function($_);

    next unless $x;

    # merge objects into master list
    while (my ($k, $v) = each %$x) {
        $object{$k} = $v;
    }
}

print Dumper \%object;

__DATA__
stuff, stuff2: pre-operation event = {foo1, foo2};
stuff3, stuff4: ;

The output is:

$VAR1 = {
          'stuff2' => 'stuff',
          'stuff3' => 'stuff',
          'stuff' => 'stuff',
          'stuff4' => 'stuff'
        };
缺⑴份安定 2024-07-30 08:38:22

可能不是您问题的答案,但是当您通过哈希启动each()循环时,如果之前在哈希上使用过each(),那么它只会从迭代器指向的位置开始。 为了安全起见,请在 while 循环之前放置一个 void-contextkeys()(例如,keys(%$ref1);)以重置迭代器。 旧版本的 Data::Dumper 有一个可爱的小错误,有时让迭代器指向最后一个元素之后,使得散列对于不安全的 while(...each...) 循环来说似乎是空的:)

Probably not an answer to your question, but when you start an each() loop through a hash, if each() had previously been used on the hash it just starts from wherever the iterator was pointing. To be safe, put a void-context keys() (e.g. keys(%$ref1);) before the while loop to reset the iterator. Older versions of Data::Dumper had a cute little bug of leaving the iterator pointing just after the last element sometimes, making the hash appear to be empty to an unsafe while(...each...) loop :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文