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;
}
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. –