Java antlr4:运算符优先级更改

Java antlr4:运算符优先级更改,java,antlr,antlr4,Java,Antlr,Antlr4,我有一个关于antlr4及其标记的优先级的问题。我的语法如下: grammar TestGrammar; @header { package some.package; } fragment A : ('A'|'a') ; fragment E : ('E'|'e') ; fragment F : ('F'|'f') ; fragment L : ('L'|'l') ; fragment R : ('R'|'r') ; fragment S : ('S'|'s') ; fragment T

我有一个关于antlr4及其标记的优先级的问题。我的语法如下:

grammar TestGrammar;

@header {
package some.package;
}

fragment A : ('A'|'a') ;
fragment E : ('E'|'e') ;
fragment F : ('F'|'f') ;
fragment L : ('L'|'l') ;
fragment R : ('R'|'r') ;
fragment S : ('S'|'s') ;
fragment T : ('T'|'t') ;
fragment U : ('U'|'u') ;
BOOL : (T R U E | F A L S E) ;

AND : '&' ;
OR : '|' ;
IMPLIES : '=>' ;

AS : 'als' ;

ID : [a-zA-Z_][a-zA-Z0-9_]+ ;

value_assignment : AS name=ID ;

formula  :
  BOOL /*(variable=value_assignment)?*/  #ExpressionBoolean
  | identifier=ID /*(variable=value_assignment)?*/  #ExpressionIdentifier
  | leftFormula=formula operator=(AND | OR) rightFormula=formula /*(variable=value_assignment)?*/  #ExpressionBinaryAndOr
  | leftFormula=formula operator=IMPLIES rightFormula=formula /*(variable=value_assignment)?*/  #ExpressionBinaryImplies
;

它被用来做一些命题逻辑。我希望它首先评估and或or,然后再评估其含义。如果我正在使用建议的语法,它将按预期工作。请注意,赋值规则已被注释掉。我有一些测试用例可以使用这些功能:

public class TestGrammarTest {

    private static ParserRuleContext parse(final String input) {
        final TestGrammarLexer lexer = new TestGrammarLexer(CharStreams.fromString(input));
        final CommonTokenStream tokens = new CommonTokenStream(lexer);
        return new TestGrammarParser(tokens).formula();
    }

    private static Set<Object> states() {
        final Set<Object> states = new HashSet<Object>();

        states.add(0);
        states.add(1);
        states.add(2);

        return states;
    }

    @DataProvider (name = "testEvaluationData")
    public Object[][] testEvaluationData() {
        return new Object [][] {
            {"true & false => true", states(), states()},
            {"false & true => true", states(), states()},
        };
    }

    @Test (dataProvider = "testEvaluationData")
    public void testEvaluation(final String input, final Set<Object> states, final Set<Object> expectedResult) {
        System.out.println("test evaluation of <" + input + ">");
        Assert.assertEquals(
                new TestGrammarVisitor(states).visit(parse(input)),
                expectedResult
            );
    }

}
注释掉后,输出如预期:

test evaluation of <true & false => true>
visitExpressionBinaryImplies called ...
visitExpressionBinaryAndOr called ...
visitExpressionBoolean called ...
visitExpressionBoolean called ...
visitExpressionBoolean called ...

test evaluation of <false & true => true>
visitExpressionBinaryImplies called ...
visitExpressionBinaryAndOr called ...
visitExpressionBoolean called ...
visitExpressionBoolean called ...
visitExpressionBoolean called ...

PASSED: testEvaluation("true & false => true", [0, 1, 2], [0, 1, 2])
PASSED: testEvaluation("false & true => true", [0, 1, 2], [0, 1, 2])
测试评估真值>
VisitePressionBinary名为。。。
VisitePressionBinaryand和或调用。。。
VisitePressionBoolean调用。。。
VisitePressionBoolean调用。。。
VisitePressionBoolean调用。。。
真实性的测试评估>
VisitePressionBinary名为。。。
VisitePressionBinaryand和或调用。。。
VisitePressionBoolean调用。。。
VisitePressionBoolean调用。。。
VisitePressionBoolean调用。。。
通过:testEvaluation(“true&false=>true”、[0,1,2]、[0,1,2])
通过:testEvaluation(“false&true=>true”、[0,1,2]、[0,1,2])
但是,当我包含这些语句时,优先级会发生变化:

test evaluation of <true & false => true>
visitExpressionBinaryAndOr called ...
visitExpressionBoolean called ...
visitExpressionBinaryImplies called ...
visitExpressionBoolean called ...
visitExpressionBoolean called ...

test evaluation of <false & true => true>
visitExpressionBinaryAndOr called ...
visitExpressionBoolean called ...
visitExpressionBinaryImplies called ...
visitExpressionBoolean called ...
visitExpressionBoolean called ...

PASSED: testEvaluation("true & false => true", [0, 1, 2], [0, 1, 2])
FAILED: testEvaluation("false & true => true", [0, 1, 2], [0, 1, 2])
java.lang.AssertionError: Sets differ: expected [0, 1, 2] but got []
测试评估真值>
VisitePressionBinaryand和或调用。。。
VisitePressionBoolean调用。。。
VisitePressionBinary名为。。。
VisitePressionBoolean调用。。。
VisitePressionBoolean调用。。。
真实性的测试评估>
VisitePressionBinaryand和或调用。。。
VisitePressionBoolean调用。。。
VisitePressionBinary名为。。。
VisitePressionBoolean调用。。。
VisitePressionBoolean调用。。。
通过:testEvaluation(“true&false=>true”、[0,1,2]、[0,1,2])
失败:testEvaluation(“false&true=>true”,[0,1,2],[0,1,2])
java.lang.AssertionError:集合不同:预期为[0,1,2],但实际为[]
正如你所看到的,这个暗示将在连接之后被调用,这不是我想要的。此外,第一个测试用例意外通过测试,因为不满足预期的操作员优先级。有人能向我解释为什么运算符优先级会因为使用赋值规则而改变(我刚刚删除了它周围的注释符号)


非常感谢你的帮助

经过一些尝试,我成功地解决了这个问题,如下所示:

grammar TestGrammar;

@header {
package some.package;
}

fragment A : ('A'|'a') ;
fragment E : ('E'|'e') ;
fragment F : ('F'|'f') ;
fragment L : ('L'|'l') ;
fragment R : ('R'|'r') ;
fragment S : ('S'|'s') ;
fragment T : ('T'|'t') ;
fragment U : ('U'|'u') ;
BOOL : (T R U E | F A L S E) ;

AND : '&' ;
OR : '|' ;
IMPLIES : '=>' ;

AS : 'als' ;

ID : [a-zA-Z_][a-zA-Z0-9_]+ ;

formula  :
  BOOL #ExpressionBoolean
  | leftFormula=formula operator=(AND | OR) rightFormula=formula #ExpressionBinaryAndOr
  | leftFormula=formula operator=IMPLIES rightFormula=formula #ExpressionBinaryImplies
  | innerFormula=formula AS storageName=ID  #ExpressionAssignment
  | identifier=ID #ExpressionIdentifier
;

因此,我将把存储能力作为一个单独的公式来处理。这并不是我想要做的(它迫使我为每个子公式提供存储选项,如果需要或不需要特定子公式的存储行为,我必须在访问者中管理它)。但是,我可以接受这种工作方式。

我忘了在语法末尾添加以下行:WS:[\t\n\r]+->skip;这将跳过空白,并使错误消息消失。但是,这对所描述的行为没有任何影响。
as
类似于
公式的运算符。可能值得尝试为操作符的
formula
添加一个alt,例如
formula:formula as ID |…|公式(和|或)公式|。此外,我会丢弃大部分标签。它混淆了Parr生成的语法和访问器函数。但是,这是一个有趣的例子。对不起,我在发布我的答案后读到了你的评论。你的建议或多或少符合我最终得出的解决方案。我决定保留标签,因为它有助于阅读和理解TestGrammarVisitor类的实现。
test evaluation of <true & false => true>
visitExpressionBinaryAndOr called ...
visitExpressionBoolean called ...
visitExpressionBinaryImplies called ...
visitExpressionBoolean called ...
visitExpressionBoolean called ...

test evaluation of <false & true => true>
visitExpressionBinaryAndOr called ...
visitExpressionBoolean called ...
visitExpressionBinaryImplies called ...
visitExpressionBoolean called ...
visitExpressionBoolean called ...

PASSED: testEvaluation("true & false => true", [0, 1, 2], [0, 1, 2])
FAILED: testEvaluation("false & true => true", [0, 1, 2], [0, 1, 2])
java.lang.AssertionError: Sets differ: expected [0, 1, 2] but got []
grammar TestGrammar;

@header {
package some.package;
}

fragment A : ('A'|'a') ;
fragment E : ('E'|'e') ;
fragment F : ('F'|'f') ;
fragment L : ('L'|'l') ;
fragment R : ('R'|'r') ;
fragment S : ('S'|'s') ;
fragment T : ('T'|'t') ;
fragment U : ('U'|'u') ;
BOOL : (T R U E | F A L S E) ;

AND : '&' ;
OR : '|' ;
IMPLIES : '=>' ;

AS : 'als' ;

ID : [a-zA-Z_][a-zA-Z0-9_]+ ;

formula  :
  BOOL #ExpressionBoolean
  | leftFormula=formula operator=(AND | OR) rightFormula=formula #ExpressionBinaryAndOr
  | leftFormula=formula operator=IMPLIES rightFormula=formula #ExpressionBinaryImplies
  | innerFormula=formula AS storageName=ID  #ExpressionAssignment
  | identifier=ID #ExpressionIdentifier
;