perl – 在Marpa语法中制作0长度列表的简明方法?
发布时间:2020-12-16 06:26:15 所属栏目:大数据 来源:网络整理
导读:我是Marpa的新手.我已经尝试了几种方法来描述我的语法中的0个或更多个术语的列表,我想避免使用多个解析树. 我的语言将只有1个组件,后跟0个子组件: package = component-rule [subcomponent-rule ...] 我首先尝试的是这样的: { lhs = 'Package',rhs = [qw/c
我是Marpa的新手.我已经尝试了几种方法来描述我的语法中的0个或更多个术语的列表,我想避免使用多个解析树.
我的语言将只有1个组件,后跟0个子组件: package => component-rule [subcomponent-rule ...] 我首先尝试的是这样的: { lhs => 'Package',rhs => [qw/component-rule subcomponents/] },{ lhs => 'subcomponents',rhs => [qw/subcomponent-list/] },{ lhs => 'subcomponent-list',rhs => [qw/subcomponent-rule/],action => 'do_subcomponent_list' },rhs => [qw/subcomponent-list subcomponent-rule/],rhs => [qw//],action => 'do_subcomponent_empty_list' },{ lhs => 'subcomponent-rule',rhs => [qw/subcomponent subcomponent-name/],action => 'do_subcomponent' }, (帖子末尾的完整代码.) 这是我的意见: $recce->read( 'component',); $recce->read( 'String','MO Factory'); $recce->read( 'subcomponent','Memory Wipe Station'); $recce->read( 'subcomponent','DMO Tour Robot'); 我得到两个解析树,第一个是不受欢迎的undef,第二个是我喜欢的.两者都将列表作为固有的树提供回来. $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' } ] ]; subcomponent-list的可空规则是允许0个子组件的情况,但它在1个子组件列表的前面引入了null元素,这是一个备用解析. (Marpa只下载了一次周期,谢天谢地.) 我的另一个想法是使子组件列表不可为空,并引入一个0或1个子组件列表的中间规则: { lhs => 'subcomponents',rhs => [qw//] }, 这至少消除了多重解析,但我仍然有一个循环,一个凌乱的嵌套树来压缩. 是否有更直接的方法来制作0长度列表或以其他方式使符号可选? 完整示例代码: #!/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',{ lhs => 'component-name',rhs => [qw/String/] },{ lhs => 'component-rule',rhs => [qw/component component-name/],action => 'do_component' },{ lhs => 'subcomponent-name',# { lhs => 'subcomponent-list',},],} ); $grammar->precompute(); my $recce = Marpa::R2::Recognizer->new( { grammar => $grammar } ); $recce->read( 'component','MO Factory'); if (1) { $recce->read( 'subcomponent','DMO Tour Robot'); $recce->read( 'subcomponent','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_meann"; # 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 $t1n"; my $href = { 'Component' => $t1 }; return $href; } sub My_Actions::do_subcomponent{ my ( undef,$t1 ) = @_; print STDERR "do_subcomponent $t1n"; my $href = { 'Subcomponent' => $t1 }; return $href; } sub My_Actions::do_subcomponent_empty_list { print STDERR "do_subcomponent_empty_listn"; 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; } 解决方法
使用min参数指定
sequence rule.该值可以是0(也就是正则表达式中的*量词)或1(也就是量词).您可以通过删除子组件和子组件列表规则来完成此操作.而是添加:
{ lhs => 'subcomponents',rhs => ['subcomponent-rule'],min => 0,action => 'do_subcomponent_list',} 然后您的语法无需进一步修改即可运行. 使用序列规则是优选的:不必进行展平,语法应该更有效. 请注意,建议您使用“无扫描接口”. DSL在这个问题上很好地抽象: subcomponents ::= <subcomponent rule>* action => do_subcomponent_list (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |