2009-06-04 11 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ルールの内容を表示できますか? –

+0

Event_listは何も返しません。 object_listが追加されました。 –

答えて

6

あなたのスクリプトにuse strictを追加する場合は、致命的なエラーがで使用中「はrefs」しながら、ハッシュリファレンスとして文字列(「1」)を使用することはできません取得します[ merge_hash_refs]に電話してください。 <defer>ディレクティブによって作成されたクロージャは、@itemの内容を、最終的にサブルールによって返されたhashrefsの代わりにプロダクションが一致したものにしているように見えます。これは、より高いレベルのルールは(バックトラックを含む)が失敗した場合でも$ ::オブジェクトが成功object制作によって更新された副作用があり、もちろん

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

<defer>ディレクティブを削除すると、私はこの出力を提供します。出力された

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

それは一種の邪悪な感覚を作ります。一口。ありがとうございました。 –

1

おそらくないあなたの質問への答えが、あなたは、ハッシュを介して()ループを開始するときに、(各場合)は、イテレータが指し示していたところから始まるハッシュで使用されていました。安全に行うには、whileループの前にvoidコンテキストのkeys()(たとえばkeys(%$ ref1);)を入れてイテレータをリセットします。古いバージョンのData :: Dumperは、最後の要素の直後を指すイテレータを残して、ハッシュを安全でない(... each ...)ループのように見せかけるようなかわいいバグを持っていました:)

+0

それは答えではありませんでしたが、私があなたに教えてくれてうれしいです。 :-) –