2013-07-30 31 views
5

Tôi mới đến Marpa. Tôi đã thử một vài cách để mô tả một danh sách gồm 0 hoặc nhiều thuật ngữ trong ngữ pháp của tôi, và tôi muốn tránh nhiều cây phân tích cú pháp.Cách ngắn gọn để tạo danh sách độ dài 0+ trong ngữ pháp Marpa?

Ngôn ngữ của tôi sẽ có chính xác 1 phần tiếp theo 0+ subcomponents:

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

gì tôi đã cố gắng đầu tiên là thế này: (. Full mã tại cuối bài)

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

Đây là thông tin đầu vào của tôi:

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

Tôi nhận được hai cây phân tích cú pháp, cái đầu tiên với một undefirable không mong muốn, và cái thứ hai mà tôi thích. Cả hai cung cấp cho danh sách trở lại như vốn một cây.

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

Nguyên tắc nullable cho tiểu hợp phần-list là cho phép các trường hợp 0 ​​subcomponents, nhưng nó giới thiệu các yếu tố null trên mặt trước của một danh sách các 1+ subcomponents, mà là một phân tích cú pháp thay thế. (Marpa xuống chu kỳ chỉ một lần, cảm ơn lòng tốt.)

ý tưởng khác của tôi là làm cho tiểu hợp phần-list không nullable, và giới thiệu một nguyên tắc trung gian là 0 hoặc 1 tiểu hợp phần-danh sách:

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

Điều này ít nhất là loại bỏ nhiều phân tích cú pháp, nhưng tôi vẫn có một chu kỳ, và một cây lồng nhau lộn xộn để nén.

Có cách nào trực tiếp hơn để tạo danh sách độ dài 0+ hoặc tạo biểu tượng tùy chọn khác không?

Full code mẫu:

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

Trả lời

6

Chỉ định sequence rule với lập luận min. Giá trị có thể là 0 (còn gọi là mã định danh * trong regex) hoặc 1 (còn gọi là số phân tích +). Bạn có thể thực hiện việc này bằng cách xóa các quy tắc subcomponentssubcomponent-list. Thay vào đó, hãy thêm:

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

Ngữ pháp của bạn sẽ chạy mà không cần sửa đổi thêm.

Sử dụng quy tắc trình tự thích hợp hơn: Không cần làm phẳng và ngữ pháp sẽ hiệu quả hơn.


Lưu ý rằng bạn được khuyến khích sử dụng Giao diện không cần quét. DSL tóm tắt độc đáo về vấn đề này:

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

Cảm ơn bạn đã liên kết sâu hơn vào các trang hướng dẫn (Tôi đến từ blog và tổng quan). Tôi viết lại mã của mình cho Scanless và tôi đang trên đường. –

Các vấn đề liên quan