2013-07-30 12 views
5

Jestem nowy w Marpa. Próbowałem kilka sposobów, aby opisać listę 0 lub więcej terminów w mojej gramatyce, i chcę uniknąć wielu drzew parsowanych.Zwięzły sposób, aby utworzyć listę długości 0+ w gramatyce Marpy?

Mój język będzie miał dokładnie 1 komponent następnie 0+ składowych:

package => component-rule [subcomponent-rule ...] 

co starałem pierwszy było to: (. Pełny kod na końcu postu)

{ lhs => 'Package', rhs => [qw/component-rule subcomponents/] }, 
{ lhs => 'subcomponents', rhs => [qw/subcomponent-list/] }, 
{ lhs => 'subcomponent-list', rhs => [qw/subcomponent-rule/], action => 'do_subcomponent_list' }, 
{ lhs => 'subcomponent-list', rhs => [qw/subcomponent-list subcomponent-rule/], action => 'do_subcomponent_list' }, 
{ lhs => 'subcomponent-list', rhs => [qw//], action => 'do_subcomponent_empty_list' }, 
{ lhs => 'subcomponent-rule', rhs => [qw/subcomponent subcomponent-name/], action => 'do_subcomponent' }, 

Oto moje dane wejściowe:

$recce->read('component',); 
$recce->read('String', 'MO Factory'); 
$recce->read('subcomponent',); 
$recce->read('String', 'Memory Wipe Station'); 
$recce->read('subcomponent',); 
$recce->read('String', 'DMO Tour Robot'); 

Dostaję dwa parsy, pierwszy z niepożądanym undefem, a drugi, który wolę. Obie nadają liście z powrotem jako naturalne drzewo.

$VAR1 = [ 
      { 
      'Component' => 'MO Factory' 
      }, 
      [ 
      [ 
       { 
       'Subcomponent' => undef 
       }, 
       { 
       'Subcomponent' => 'Memory Wipe Station' 
       } 
      ], 
      { 
       'Subcomponent' => 'DMO Tour Robot' 
      } 
      ] 
     ]; 
$VAR2 = [ 
      { 
      'Component' => 'MO Factory' 
      }, 
      [ 
      { 
       'Subcomponent' => 'Memory Wipe Station' 
      }, 
      { 
       'Subcomponent' => 'DMO Tour Robot' 
      } 
      ] 
     ]; 

pustych zasada podkomponentu liście było umożliwienie przypadek 0 składowych, ale to wprowadza pustego elementu na przód listy 1+ składowych, który jest alternatywnym analizy składniowej. (Marpa zstępuje cyklu tylko raz, dzięki Bogu).

Mój inny pomysł był aby podkomponent-lista nie pustych, oraz wprowadzenie pośredniego regułę wynosi 0 lub 1 podkomponent wykazach:

{ lhs => 'subcomponents', rhs => [qw//] }, 
{ lhs => 'subcomponents', rhs => [qw/subcomponent-list/] }, 

To przynajmniej wyeliminowało wielokrotny parse, ale nadal mam cykl i niechlujne zagnieżdżone drzewo do kompresji.

Czy istnieje bardziej bezpośredni sposób utworzenia listy długości 0+ lub w inny sposób uczynienia symbolu opcjonalnym?

Pełny kod przykładowy:

#!/usr/bin/perl 

use Marpa::R2; 
use Data::Dumper; 

my $grammar = Marpa::R2::Grammar->new(
    { start => 'Package', 
     actions => 'My_Actions', 
     default_action => 'do_what_I_mean', 
     rules => [ 
     { lhs => 'Package', rhs => [qw/component-rule subcomponents/] }, 
     { lhs => 'component-name', rhs => [qw/String/] }, 
     { lhs => 'component-rule', rhs => [qw/component component-name/], action => 'do_component' }, 
     { lhs => 'subcomponent-name', rhs => [qw/String/] }, 
     { lhs => 'subcomponent-rule', rhs => [qw/subcomponent subcomponent-name/], action => 'do_subcomponent' }, 
     { lhs => 'subcomponents', rhs => [qw//] }, 
     { lhs => 'subcomponents', rhs => [qw/subcomponent-list/] }, 
     { lhs => 'subcomponent-list', rhs => [qw/subcomponent-rule/], action => 'do_subcomponent_list' }, 
     { lhs => 'subcomponent-list', rhs => [qw/subcomponent-list subcomponent-rule/], action => 'do_subcomponent_list' }, 
#  { lhs => 'subcomponent-list', rhs => [qw//], action => 'do_subcomponent_empty_list' }, 
#  { lhs => 'subcomponent-list', rhs => [qw//], }, 
     ], 
    } 
); 

$grammar->precompute(); 

my $recce = Marpa::R2::Recognizer->new({ grammar => $grammar }); 

$recce->read('component',); 
$recce->read('String', 'MO Factory'); 

if (1) { 
$recce->read('subcomponent',); 
$recce->read('String', 'Memory Wipe Station'); 
$recce->read('subcomponent',); 
$recce->read('String', 'DMO Tour Robot'); 
$recce->read('subcomponent',); 
$recce->read('String', 'SMO Break Room'); 
} 


my @values =(); 
while (defined(my $value_ref = $recce->value())) { 
    push @values, ${$value_ref}; 
} 

print "result is ",Dumper(@values),"\n"; 

sub My_Actions::do_what_I_mean { 

    print STDERR "do_what_I_mean\n"; 

    # The first argument is the per-parse variable. 
    # At this stage, just throw it away 
    shift; 

    # Throw away any undef's 
    my @children = grep { defined } @_; 

    # Return what's left 
    return scalar @children > 1 ? \@children : shift @children; 
} 

sub My_Actions::do_component { 
    my (undef, $t1) = @_; 
    print STDERR "do_component $t1\n"; 
    my $href = { 'Component' => $t1 }; 
    return $href; 
} 
sub My_Actions::do_subcomponent{ 
    my (undef, $t1) = @_; 
    print STDERR "do_subcomponent $t1\n"; 
    my $href = { 'Subcomponent' => $t1 }; 
    return $href; 
} 

sub My_Actions::do_subcomponent_empty_list 
{ 
    print STDERR "do_subcomponent_empty_list\n"; 
    my $href = { 'Subcomponent' => undef }; 
    return $href; 
} 

sub My_Actions::do_subcomponent_list{ 
    # The first argument is the per-parse variable. 
    # At this stage, just throw it away 
    shift; 

    # Throw away any undef's 
    my @children = grep { defined } @_; 

    print STDERR "do_subcomponent_list size ",scalar(@children),"\n"; 
# Do this to collapse recursive trees to a list: 
# @children = map { ref $_ eq "ARRAY" ? @{$_} : $_; } @children; 

    return scalar @children > 1 ? \@children : shift @children; 
} 

Odpowiedz

6

Określ sequence rule z min argument. Wartością może być 0 (zwany również wyrażeniem * w wyrażeniach regularnych) lub 1 (zwany również kwantyfikatorem +). Możesz to zrobić, usuwając reguły subcomponents i subcomponent-list. Zamiast tego dodaj:

{ 
    lhs => 'subcomponents', 
    rhs => ['subcomponent-rule'], 
    min => 0, 
    action => 'do_subcomponent_list', 
} 

Twoja gramatyka działa bez dalszych modyfikacji.

Preferowane są reguły sekwencji: nie ma potrzeby spłaszczania, a gramatyka powinna być bardziej wydajna.


Należy pamiętać, że zachęcamy do korzystania z interfejsu bez skanera. DSL abstrahuje ładnie w tej kwestii:

subcomponents ::= <subcomponent rule>* action => do_subcomponent_list 
+0

Dzięki za głębszym łącza do stron man (ja przyszedłem z blogów i przegląd.) I przepisał mój kod dla Scanless i jestem na mojej drodze. –

Powiązane problemy