ANTLR 隐式乘法 [英] ANTLR Implicit Multiplication
问题描述
我是 ANTLR 的新手,我正在尝试扩展此处提供的简单计算器示例.具体来说,我尝试添加一些简单的函数、负数等,以熟悉 ANTLR.但是,我在尝试实现隐式"乘法时遇到了一些问题(例如,3cos(2)sin(2) 将被解释为 3*cos(2)*sin(2)).>
我在 Stack Overflow 上发现了一个有同样问题的问题(此处).该问题的解决方案的一般形式看起来像我自己发现的,所以我不确定我的问题出在哪里.
我的语法如下.没有<代码>|p2 = signExpr {$value *= $p2.value;} 行(multiplicationExpr
中的最后一行),根据我的测试,一切似乎都正常.当我添加这一行并通过 antlr
运行它时,我收到以下错误:
error(211):calculator.g:24:3: [fatal] rule multiplicationExpr 由于递归规则调用可从 alts 3,4 获得非 LL(*) 决定.通过左因子分解或使用句法谓词或使用 backtrack=true 选项解决.警告(200):calculator.g:24:3:Decision 可以使用多种选择来匹配输入,例如'-' FLOAT":3, 4结果,该输入禁用了备选方案 4
启用 backtrack
会导致我的一些(正常工作)测试表达式计算错误.此外,警告谈到了 multiplicationExpr
的替代方案 3 和 4,但我在该块中只有三个替代方案,这让我感到困惑.
有人能指出我语法中的错误吗?
语法计算器;eval 返回 [双倍值]: exp = addExpr {$value = $exp.value;};addExpr 返回 [double value]: m1 = multiplicationExpr {$value = $m1.value;}( '+' m2 = multiplicationExpr {$value += $m2.value;}|'-' m2 = multiplicationExpr {$value -= $m2.value;})*;multiplicationExpr 返回 [double value]: p1 = signExpr {$value = $p1.value;}( '*' p2 = signExpr {$value *= $p2.value;}|'/' p2 = signExpr {$value/= $p2.value;}|p2 = signExpr {$value *= $p2.value;})*;signExpr 返回 [double value]:( '-' a = funcExpr {$value = -1*$a.value;}) |( a = funcExpr {$value = $a.value;});funcExpr 返回 [double 值]:('cos' s = signExpr {$value = Math.cos($s.value);}) |('sin' s = signExpr {$value = Math.sin($s.value);}) |( s = powExpr {$value = s;});powExpr 返回 [double value]: s1 = atomExpr {$value = $s1.value;}( '^' s2 = signExpr {$value = Math.pow($value, $s2.value);})?;atomExpr 返回 [double value]: f = FLOAT {$value = Double.parseDouble($f.text);}|'(' exp = addExpr ')' {$value = $exp.value;};漂浮: ('0'..'9')+ ('.' ('0'..'9')*)?指数?|'.'('0'..'9')+ 指数?;WS : ( ' '|'\t'|'\r'|'\n') {$channel=隐藏;};分段指数 : ('e'|'E') ('+'|'-')?('0'..'9')+;
随着 BernardK 的解决方案融入我以前的语法,这里是新的 multiplicationExpr
,它让我的一切都为我工作:
multiplicationExpr 返回 [double value]:p1 = signExpr {$value = $p1.value;}( (signExpr funcExpr*) => p2 = funcExpr {$value *= $p2.value;}|'*' p2 = signExpr {$value *= $p2.value;}|'/' p2 = signExpr {$value/= $p2.value;})*;
经过更多的尝试,一些接近我最初拥有的东西也有效:
multiplicationExpr 返回 [double value]: p1 = signExpr {$value = $p1.value;}( p2 = funcExpr {$value *= $p2.value;}|'*' p2 = signExpr {$value *= $p2.value;}|'/' p2 = signExpr {$value/= $p2.value;})*;
再次感谢你,伯纳德.
I'm new to ANTLR, and I'm trying to expand upon the example of a simple calculator presented here. Specifically, I've tried adding some simple functions, negative numbers and so on, to familiarize myself with ANTLR. However, I've run into a bit of a problem trying to implement "implicit" multiplication (for example, 3cos(2)sin(2) would be interpreted as 3*cos(2)*sin(2)).
I've found a question on Stack Overflow with the same kind of problem (here). The general form of the solution to that problem looks like what I'd found on my own, so I'm not sure where my problem lies.
My grammar is below. Without the | p2 = signExpr {$value *= $p2.value;}
line (the last line in the multiplicationExpr
), everything seems to work fine according to my tests. When I add this line and run it through antlr
, I receive the following errors:
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
Enabling backtrack
results in wrong calculations for some of my (normally working) test expressions. Further, the warning talks about alternatives 3 and 4 for multiplicationExpr
, but I only have three alternatives in that block, which has me confused.
Would someone be able to point out the error in my grammar, given below?
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')+ ;
With BernardK's solution massaged into my previous grammar, here is the new multiplicationExpr
that gets everything working for me:
multiplicationExpr returns [double value]
:
p1 = signExpr {$value = $p1.value;}
( (signExpr funcExpr*) => p2 = funcExpr {$value *= $p2.value;}
| '*' p2 = signExpr {$value *= $p2.value;}
| '/' p2 = signExpr {$value /= $p2.value;}
)*
;
After a bit more playing around, something close to what I originally had works as well:
multiplicationExpr returns [double value]
: p1 = signExpr {$value = $p1.value;}
( p2 = funcExpr {$value *= $p2.value;}
| '*' p2 = signExpr {$value *= $p2.value;}
| '/' p2 = signExpr {$value /= $p2.value;}
)*
;
Thank you again, Bernard.
这篇关于ANTLR 隐式乘法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!