私はANTLRを初めて使用し、ここに示す簡単な計算機の例を拡張しようとしています。具体的には、ANTLRに慣れるために、いくつかの単純な関数や負の数などを追加してみました。ただし、「暗黙の」乗算を実装しようとすると、少し問題が発生しました(たとえば、3cos(2)sin(2)は3 * cos(2)* sin(2)として解釈されます)。
同じ種類の問題があるStackOverflowに関する質問を見つけました(ここ)。その問題の解決策の一般的な形は、私が自分で見つけたもののように見えるので、私の問題がどこにあるのかわかりません。
私の文法は以下の通りです。| p2 = signExpr {$value *= $p2.value;}
行(の最後の行)がないmultiplicationExpr
場合、私のテストによれば、すべてが正常に機能しているようです。この行を追加して実行するとantlr
、次のエラーが発生します。
error(211): calculator.g:24:3: [fatal] rule multiplicationExpr has non-LL(*) decision due to recursive rule invocations reachable from alts 3,4. Resolve by left-factoring or using syntactic predicates or using backtrack=true option.
warning(200): calculator.g:24:3: Decision can match input such as "'-' FLOAT" using multiple alternatives: 3, 4
As a result, alternative(s) 4 were disabled for that input
有効backtrack
にすると、一部の(通常は機能する)テスト式の計算が間違ってしまいます。さらに、警告はの選択肢3と4についてmultiplicationExpr
説明していますが、そのブロックには3つの選択肢しかないため、混乱しています。
誰かが私の文法の誤りを指摘することができますか?
grammar calculator;
eval returns [double value]
: exp = additionExpr {$value = $exp.value;}
;
additionExpr returns [double value]
: m1 = multiplicationExpr {$value = $m1.value;}
( '+' m2 = multiplicationExpr {$value += $m2.value;}
| '-' m2 = multiplicationExpr {$value -= $m2.value;}
)*
;
multiplicationExpr returns [double value]
: p1 = signExpr {$value = $p1.value;}
( '*' p2 = signExpr {$value *= $p2.value;}
| '/' p2 = signExpr {$value /= $p2.value;}
| p2 = signExpr {$value *= $p2.value;}
)*
;
signExpr returns [double value]
: ( '-' a = funcExpr {$value = -1*$a.value;}
) | ( a = funcExpr {$value = $a.value;}
)
;
funcExpr returns [double value]
: ( 'cos' s = signExpr {$value = Math.cos($s.value);}
) | ( 'sin' s = signExpr {$value = Math.sin($s.value);}
) | ( s = powExpr {$value = s;}
)
;
powExpr returns [double value]
: s1 = atomExpr {$value = $s1.value;}
( '^' s2 = signExpr {$value = Math.pow($value, $s2.value);}
)?
;
atomExpr returns [double value]
: f = FLOAT {$value = Double.parseDouble($f.text);}
| '(' exp = additionExpr ')' {$value = $exp.value;}
;
FLOAT
: ('0'..'9')+ ('.' ('0'..'9')*)? EXPONENT?
| '.' ('0'..'9')+ EXPONENT?
;
WS : ( ' '
| '\t'
| '\r'
| '\n'
) {$channel=HIDDEN;}
;
fragment
EXPONENT : ('e'|'E') ('+'|'-')? ('0'..'9')+ ;