Parse :: RecDescent - получение информации от него - PullRequest
1 голос
/ 04 июня 2009

Я работаю с парсером Parse :: RecDescent в Perl, и мне кажется, что у меня самое ужасное время для получения информации. Информация, легко доступная в Интернете, кажется, не имеет нетривиальных примеров.

Вот код:

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

edit2: 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;
}

Ответы [ 2 ]

6 голосов
/ 04 июня 2009

Если вы добавите use strict к вашему сценарию, вы получите фатальную ошибку Невозможно использовать строку ("1") в качестве ссылки HASH, в то время как "строгие ссылки" используются при [вызове merge_hash_refs] . Похоже, что замыкания, созданные директивами <defer>, приводят к тому, что содержимое @item становится тем, когда совпадает продукция вместо хеш-ссылок, которые в конечном итоге возвращаются подправилами. Удаление директив <defer> дает мне такой вывод:

$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'
        };
1 голос
/ 04 июня 2009

Возможно, это не ответ на ваш вопрос, но когда вы запускаете цикл each () через хеш, если каждый () ранее использовался в хэше, он просто начинается с того места, куда указывал итератор. Чтобы быть в безопасности, поместите void-context keys () (например, keys (% $ ref1);) перед циклом while для сброса итератора. В старых версиях Data :: Dumper была небольшая ошибка: иногда итератор оставлял указатель сразу после последнего элемента, в результате чего хэш казался пустым для небезопасного цикла while (... each ...):)

...