2009-06-04 72 views
1

我正在使用Perl中的Parse::RecDescent解析器,而且我似乎从中获取信息的时间最为可怕。网上很容易获得的信息似乎没有不平凡的例子。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}; 

应该来输出由 “东西”, “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; 
} 
+0

你能显示object_list和event_list规则的内容吗? – 2009-06-04 16:38:28

+0

Event_list不返回任何内容;添加了object_list。 – 2009-06-04 16:40:03

回答

6

如果添加use strict到你的脚本,你会得到致命错误无法使用字符串(“1”)作为HASH裁判而“严格裁判”在使用中[在致电merge_hash_refs]。看起来,由<defer>指令创建的闭包导致@item的内容是生产匹配时的内容,而不是最终由子规则返回的hashrefs。卸下<defer>指令给了我这样的输出:

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

当然,这有副作用,就是$ ::目标是通过成功的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' 
     }; 
+0

这使一种邪恶的感觉。叹。谢谢。 – 2009-06-04 17:44:31

1

大概不会回答你的问题,但是当你通过散列开始的每一个()循环,如果每个( )之前已经用在散列上,它只是从迭代器指向的任何地方开始。为了安全起见,在while循环之前放置一个void-context keys()(例如键(%$ ref1);)来重置迭代器。较早版本的Data :: Dumper有一个可爱的小错误,它使得迭代器有时会指向最后一个元素,使得哈希似乎是空的(while ...(... each循环)):