3

ANTLRで値を解析しようとしています。これが私の文法の関連部分です:

root : IDENTIFIER | SELF | literal | constructor | call | indexer;

hierarchy : root (SUB^ (IDENTIFIER | call | indexer))*;

factor  : hierarchy ((MULT^ | DIV^ | MODULO^) hierarchy)*;

sum : factor ((PLUS^ | MINUS^) factor)*;

comparison  : sum (comparison_operator^ sum)*;

value   : comparison | '(' value ')';

それらの名前はそれらの役割を非常に説明しているので、各トークンまたはルールについては説明しません。この文法はうまく機能してコンパイルされるのでvalue、次のようなものを使用して解析できます。

a.b[c(5).d[3] * e()] < e("f")

解釈

値の認識に残されているのは、括弧で囲まれた階層ルートを使用できるようにすることだけです。例えば:

(a.b).c
(3 < d()).e
...

素朴に、そして多くの期待なしに、私は私のrootルールに次の代替案を追加しようとしました:

root : ... | '(' value ')';

ただし、これはvalue非LL(*)ismのためにルールに違反します。

rule value has non-LL(*) decision due to recursive rule invocations reachable
from alts 1,2.  Resolve by left-factoring or using syntactic predicates or using 
backtrack=true option.

壊す

決定的なANTLRリファレンスのほとんどを読んだ後でも、私はまだこれらのエラーを理解していません。しかし、私が理解していることは、括弧が開いているのを見ると、ANTLRは括弧で囲まれた値の先頭を見ているか、括弧で囲まれたルートの先頭を見ているかを知ることができないということです。

括弧で囲まれた階層ルートの動作を明確に定義するにはどうすればよいですか?

編集:要求に応じて、追加のルール:

parameter : type IDENTIFIER -> ^(PARAMETER ^(type IDENTIFIER));

constructor : NEW type PAREN_OPEN (arguments+=value (SEPARATOR arguments+=value)*)? PAREN_CLOSE -> ^(CONSTRUCTOR type ^(ARGUMENTS $arguments*)?);

call : IDENTIFIER PAREN_OPEN (values+=value (SEPARATOR values+=value)*)? PAREN_CLOSE -> ^(CALL IDENTIFIER ^(ARGUMENTS $values*)?);

indexer : IDENTIFIER INDEX_START (values+=value (SEPARATOR values+=value)*)? INDEX_END -> ^(INDEXER IDENTIFIER ^(ARGUMENTS $values*));
4

1 に答える 1

1

'(' value ')'から取り外しvalueて配置しrootます:

root : IDENTIFIER | SELF | literal | constructor | call | indexer | '(' value ')';

...

value : comparison;

(a.b).cこれで、次の解析が行われます。

ここに画像の説明を入力してください

そして(3 < d()).eで:

ここに画像の説明を入力してください

もちろん、ASTから括弧を省略したいと思うかもしれません。

root : IDENTIFIER | SELF | literal | constructor | call | indexer | '('! value ')'!;

また、パーサールールのListusingでトークンを追加する必要はありません。+=以下:

call 
 : IDENTIFIER PAREN_OPEN (values+=value (SEPARATOR values+=value)*)? PAREN_CLOSE 
   -> ^(CALL IDENTIFIER ^(ARGUMENTS $values*)?)
 ;

次のように書き直すことができます。

call 
 : IDENTIFIER PAREN_OPEN (value (SEPARATOR value)*)? PAREN_CLOSE 
   -> ^(CALL IDENTIFIER ^(ARGUMENTS value*)?)
 ;

編集

主な問題は、特定の入力を2つ(またはそれ以上!)の方法で解析できるという事実です。たとえば、入力はルール(a)の代替1と2によって解析できます。value

value 
 : comparison    // alternative 1
 | '(' value ')' // alternative 2
 ;

パーサールールを実行します。a comparison(代替1)はルール(a)に一致するため一致する可能性がrootあり、ルールは次に一致し'(' value ')'ます。しかし、それは代替案2が一致するものでもあります!これで、パーサーは1つの入力を「認識」し、2つの異なる解析を行って、このあいまいさについて報告します。

于 2012-05-02T06:06:06.500 に答える