2017-07-18 10 views
3

以下のコードに示すように、名前を参照するときに「サブルーチンで深い再帰」警告が表示されます。 use 5.016 … __SUB__->()も役に立ちません。Hammerパーサーコンビネータでは、それ自体を参照するルールをどのように実装しますか?

ビルドヒント:git clone; scons bindings = perlテスト。 cdビルド/ opt/src/bindings/perl; mproductはunconditonally mproductを呼び出します。$ 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は、無条件でmproductで定義されています。

mproduct ::= digits '*' mproduct 

したい文法は、あなたがしたい文法は

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

hammerで、疑似BNFを使用して、より明確に言えば

mproduct ::= digits '*' mproduct 
      | digits 

または

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

ですツールを提供するこれを実装するには:より一般的な質問には対応していません

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(); 

この問題を解決するため、1が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は、この質問に答えるのに有用であることが判明しました。

何もテストされていません。

関連する問題