2009-06-04 5 views
1

Ich arbeite mit dem Parse::RecDescent Parser in Perl, und ich habe die schrecklichste Zeit, Informationen von ihm zu bekommen. Die online verfügbaren Informationen scheinen keine nicht-trivialen Beispiele zu haben. HierParse :: RecDescent - bekommen Informationen von ihm

ist der 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]; 
     } 
     > 

Hier ist der Ausgang

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

Die Eingabedatei korrekt analysiert ist.

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

Es sollte einen Hash werden zur Ausgabe von "Stoff" verkeilt "stuff2".

Gedanken?

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, nur für den Fall. im Einsatz, während „strict refs“ auf [die :-)

#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

Können Sie den Inhalt der Regeln object_list und event_list anzeigen? –

+0

Event_list gibt nichts zurück; object_list hinzugefügt. –

Antwort

6

Wenn Sie ein use strict zu Ihrem Skript fügen Sie den fatalen Fehler bekommen nicht Zeichenfolge („1“) als HASH ref verwenden können Anruf an merge_hash_refs]. Es scheint, dass die durch die <defer>-Direktiven erzeugten Schließungen bewirken, dass die Inhalte von @item diejenigen sind, bei denen die Produktion anstelle der von den Unterregeln schließlich zurückgegebenen Hash-Regeln übereinstimmte. Das Entfernen der <defer> Richtlinien gibt mir diese Ausgabe:

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

Natürlich ist dies den Nebeneffekt hat, die $ :: Objekt durch erfolgreiche object Produktionen aktualisiert wird, auch wenn die höheren Niveau Regeln scheitern (einschließlich Rückzieher). Ich würde es auf diese Weise schreiben:

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

Die Ausgabe lautet:

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

Das macht eine Art bösen Sinn. Seufzer. Vielen Dank. –

1

Wahrscheinlich nicht eine Antwort auf Ihre Frage, aber wenn Sie eine each() Schleife durch einen Hash zu starten, wenn jede () wurde zuvor für den Hash verwendet, der nur dort beginnt, wo der Iterator hinwies. Um sicher zu sein, lege vor der while-Schleife einen void-context keys() (z. B. keys (% $ ref1);)), um den Iterator zurückzusetzen. Ältere Versionen von Data :: Dumper hatten einen netten kleinen Fehler, den Iterator manchmal direkt nach dem letzten Element zu zeigen, wodurch der Hash als leer zu einer unsicheren while (... jeder ...) Schleife erschien :)

+0

Das war nicht die Antwort, aber ich bin froh, dass du es mir erzählt hast. :-) –

Verwandte Themen