2013-07-30 4 views
5

Sono nuovo di Marpa. Ho provato un paio di modi per descrivere un elenco di 0 o più termini nella mia grammatica, e voglio evitare più alberi di analisi.Modo conciso per creare una lista di lunghezza 0+ nella grammatica di Marpa?

La mia lingua avrà esattamente 1 componente seguito da 0+ sottocomponenti:

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

quello che ho provato prima era questa: (. Codice completo alla fine del post)

{ 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' }, 

Ecco il mio input:

$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'); 

Ottengo due alberi di analisi, il primo con undef indesiderato e il secondo che preferisco. Entrambi restituiscono la lista come intrinsecamente un albero.

$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' 
      } 
      ] 
     ]; 

La regola nullable per sottocomponente-list era quella di permettere il caso di 0 sottocomponenti, ma introduce l'elemento nullo sulla parte anteriore di un elenco di 1+ sottocomponenti, che è un parse alternativo. (Marpa scende il ciclo solo una volta, grazie a Dio.)

altra mia idea era di fare sottocomponente-list non annullabile, e introdurre una regola intermedia che è 0 o 1 sottocomponente liste:

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

Questo almeno ha eliminato l'analisi multipla, ma ho ancora un ciclo e un albero annidato disordinato da comprimere.

Esiste un modo più diretto per creare un elenco di lunghezza 0+ o rendere un simbolo facoltativo?

codice di esempio completa:

#!/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; 
} 

risposta

6

Specificare un sequence rule con l'argomento min. Il valore può essere 0 (ovvero il quantificatore * in espressioni regolari) o 1 (ovvero il quantificatore +). È possibile farlo rimuovendo le regole subcomponents e subcomponent-list. Aggiungi invece:

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

La grammatica quindi viene eseguita senza ulteriori modifiche.

Utilizzare le regole di sequenza è preferibile: non è necessario eseguire l'appiattimento e la grammatica dovrebbe essere più efficiente.


Nota che è consigliabile utilizzare l'interfaccia senza scansione. Il DSL astrae ben oltre questo numero:

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

Grazie per il link più in profondità le pagine man (I riceve sulla blog e la panoramica.) Ho riscritto il mio codice per non digitalizzati e sono per la mia strada. –