2017-07-18 34 views
3

当我只引用下面代码中显示的名称时,我收到了“子例程深度递归”警告。 use 5.016 … __SUB__->()也没有帮助。在Hammer解析器组合器中,你如何实现一个引用自身的规则?

构建提示:git clone; scons bindings = perl test; cd build/opt/src/bindings/perl; $ EDITOR h.pl

use 5.024; 
use strictures; 
use blib; 
use hammer qw(); 

# digits = "0"/"1"/"2"/"3"/"4"/"5"/"6"/"7"/"8"/"9" 
sub digits { hammer::many hammer::in 0..9 } 

# product = digits "*" digits 
sub product { 
    hammer::sequence digits, hammer::ch('*'), digits 
} 

product->parse('23*42'); # [[2, 3], '*', [4, 2]] 


# mproduct = digits "*" mproduct 
sub mproduct; 
sub mproduct { 
    hammer::sequence digits, hammer::ch('*'), mproduct 
} 
mproduct->parse('8*23*42'); 
# Deep recursion on subroutine "main::mproduct" at h.pl line 21. 
+0

如果[hammer](https://github.com/abiggerhammer/hammer)是一个递归下降解析器,那么是否不允许自引用规则? – jeff6times7

+0

你如何认为它是rec.descent? – daxim

+0

我尽可能多地阅读了docs/hammer-presentation.pdf以及一些源文件。我误解了什么?我不熟悉那些代码,我有兴趣找到更快的解析器,这是作者声称的。你的问题激发了我的兴趣。 – jeff6times7

回答

3

你的代码中有一个无限循环:mproduct unconditonally电话mproduct

你的文法也有相同的无限循环:mproduct无条件定义为mproduct

mproduct ::= digits '*' mproduct 

你想要的语法是

mproduct ::= digits '*' mproduct 
      | digits 

mproduct ::= digits mproduct_ 
mproduct_ ::= '*' mproduct_ 
      | ε 

为了更清楚地使用伪BNF,你想要的语法

myproduct ::= digits ('*' digits)* 

hammer提供了一个工具实现这一点:

hammer::sepBy1(digits, hammer::ch('*')) 

这并没有解决更具普遍性的问题。以下是其中的答案一般问题将是有益的情况下:

expr ::= sum 

sum ::= term sum_ 
sum_ ::= '+' sum_ 
     | ε 

term ::= num 
     | '(' expr ')' 

破碎的做法是:

sub num { ... } 

sub term { 
    hammer::choice(
     num(), 
     hammer::sequence(
     hammer::ch('('), 
     expr(), 
     hammer::ch(')'), 
    ) 
    ) 
} 

sub sum { hammer::sepBy1(term, hammer::ch('+')) } 

sub expr { sum() } 

my $parser = expr(); 

的解决这个问题,人们会使用bind_indirect

use feature qw(state); 

sub num { ... } 

sub term { 
    hammer::choice(
     num(), 
     hammer::sequence(
     hammer::ch('('), 
     expr(), 
     hammer::ch(')'), 
    ) 
    ) 
} 

sub sum { hammer::sepBy1(term, hammer::ch('+')) } 

sub _expr { sum() } 
sub expr { state $expr = hammer::indirect(); $expr } 
UNITCHECK { hammer::bind_indirect(expr(), _expr()); } 

my $parser = expr(); 

test file证明在回答这个问题时非常有用。

什么都没有测试。

相关问题