ANTLR 隐式乘法 [英] ANTLR Implicit Multiplication

查看:21
本文介绍了ANTLR 隐式乘法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我是 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆