ANTLR隐式乘法 [英] ANTLR Implicit Multiplication

查看:108
本文介绍了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 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会导致我的某些(正常工作)测试表达式的计算错误.此外,警告还讨论了multiplicationExpr的替代3和4,但是在该块中我只有三个替代,这使我感到困惑.

有人可以指出我语法中的错误吗?

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')+ ;

解决方案

在将BernardK的解决方案按摩到我以前的语法中之后,这是新的multiplicationExpr,它可以帮助我完成所有工作:

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;}
                )*
        ;

经过更多的玩耍,接近我原来的东西也可以工作:

multiplicationExpr      returns [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天全站免登陆