简体   繁体   English

antlr4:运算符优先级更改

[英]antlr4: operator precedence changes

I have a question concerning antlr4 and the precedence of its tokens.我有一个关于 antlr4 及其令牌优先级的问题。 I have the following grammar:我有以下语法:

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
;

It is used to do some propositional logic.它用于做一些命题逻辑。 I want it to first evaluate and or or , and the implication afterwards.我希望它先评估andor ,然后再评估。 If I am using the proposed grammar, it works as expected.如果我使用建议的语法,它会按预期工作。 Please notice, that the value_assignment -rules are commented out.请注意, value_assignment规则已被注释掉。 I have some test-cases to play around with the functionality:我有一些测试用例可以使用该功能:

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

}

I think that I also need to show (a smaller version of) my visitor to make the behaviour clear.我认为我还需要展示(缩小版)我的访客以明确行为。 The implementation is straight-forward as you would expect it:正如您所期望的那样,实现是直截了当的:

public class TestGrammarVisitor extends TestGrammarBaseVisitor<Set<Object>> {

    final Set<Object> states;

    public TestGrammarVisitor(final Set<Object> theStates) {
        states = Collections.unmodifiableSet(theStates);
    }

    @Override
    public Set<Object> visitExpressionBoolean(final ExpressionBooleanContext ctx) {
        System.out.println("\nvisitExpressionBoolean called ...\n");
        final TerminalNode node = ctx.BOOL();
        final Set<Object> result;
        if (node.getText().equalsIgnoreCase("true")) {
            result = new HashSet<>(states);
            return result;
        }
        result = Collections.emptySet();
        return result;
    }

    @Override
    public Set<Object> visitExpressionBinaryAndOr(final ExpressionBinaryAndOrContext ctx) {
        System.out.println("\nvisitExpressionBinaryAndOr called ...\n");
        final Set<Object> result = new HashSet<>(super.visit(ctx.leftFormula));
        switch (ctx.operator.getText()) {
        case "&":
            result.retainAll(super.visit(ctx.rightFormula));
            return result;
        case "|":
            result.addAll(super.visit(ctx.rightFormula));
            return result;
        default:
            throw new UnsupportedOperationException();
        }
    }

    @Override
    public Set<Object> visitExpressionBinaryImplies(final ExpressionBinaryImpliesContext ctx) {
        System.out.println("\nvisitExpressionBinaryImplies called ...\n");
        final Set<Object> result = new HashSet<>(states);
        result.removeAll(super.visit(ctx.leftFormula));
        result.addAll(super.visit(ctx.rightFormula));
        return result;
    }

    @Override
    protected Set<Object> aggregateResult(Set<Object> aggregate, Set<Object> nextResult) {
        if (aggregate == null) {
            return nextResult;
        }
        if (nextResult == null) {
            return aggregate;
        }
        Set<Object> clone = new HashSet<>(aggregate);
        clone.addAll(nextResult);
        return clone;
    }

}

I use the println-statements in order to see when the different rules will be called.我使用 println 语句来查看何时调用不同的规则。 If I test the shown grammar where the如果我测试显示的语法,其中

(variable=value_assignment)?

are commented out, the output is as expected:被注释掉,输出如预期:

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])

But, when I include those statements, the precedence changes:但是,当我包含这些语句时,优先级会发生变化:

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 []

As you can see, the implication will be called AFTER the conjunction, which is not what I want.如您所见,蕴涵将在连词之后调用,这不是我想要的。 Also, the first test case passes the test by accident, since the intended operator precedence will not be met.此外,第一个测试用例意外通过了测试,因为将不满足预期的运算符优先级。 Can anyone explain to me why the operator precedence changes because of using the value_assignment -rule (I just deleted the comment symbols around it)?任何人都可以向我解释为什么运算符优先级会因为使用value_assignment -rule 而发生变化(我刚刚删除了它周围的注释符号)?

Thank you very much for your help!非常感谢您的帮助!

After some attempts, I managed to ship around the problem as follows:经过一些尝试,我设法解决了这个问题,如下所示:

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
;

So, I will handle the storage ability as a separate formula.所以,我将把存储能力作为一个单独的公式来处理。 This is not exactly what I wanted to do (it forces me to provide the storage option to each sub-formula, and I have to manage it in the visitor if a storing behaviour is desired or not for a specific sub-formula).这并不是我想要做的(它迫使我为每个子公式提供存储选项,如果特定子公式需要或不需要存储行为,我必须在访问者中管理它)。 But, I can live with that work-around.但是,我可以忍受这种变通办法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM