如何在 ANTLR 中启用 orExpression 和 andExpression 规则的组合?

How to enable combination of orExpression and andExpression rule in ANTLR?

我想用antlr4解析以下内容

isSet(foo) or isSet(bar) and isSet(test)

实际上我可以在解析树中看到只有第一个 or 被识别,我可以添加多个 or 并且解析树增长,但是额外的 and 将不会被识别。我如何在语法中定义它?

这是我当前的语法文件:

        grammar Expr;
        
        prog: (stat)+;
        stat: (command | orExpression | andExpression | notExpression)+;
        orExpression: command ( OR command | XOR command)*;
        andExpression:command ( AND command)*;
        notExpression:NOT command;
        command:IS_SET LPAREN parameter RPAREN
                | IS_EMPTY LPAREN parameter RPAREN;
        parameter: ID;
        
        
        LPAREN : '(';
        RPAREN : ')';
        LBRACE : '{';
        RBRACE : '}';
        LBRACK : '[';
        RBRACK : ']';
        SEMI : ';';
        COMMA : ',';
        DOT : '.';
        ASSIGN : '=';
        GT : '>';
        LT : '<';
        BANG : '!';
        TILDE : '~';
        QUESTION : '?';
        COLON : ':';
        EQUAL : '==';
        LE : '<=';
        GE : '>=';
        NOTEQUAL : '!=';
        AND : 'and';
        OR : 'or';
        XOR :'xor';
        NOT :'not'  ;
        INC : '++';
        DEC : '--';
        ADD : '+';
        SUB : '-';
        MUL : '*';
        DIV : '/';
        
        INT: [0-9]+;
        NEWLINE: '\r'? '\n';
        IS_SET:'isSet';
        IS_EMPTY:'isEmpty';
        WS: [\t]+ -> skip;
        ID
            :   JavaLetter JavaLetterOrDigit*
            ;
        
        fragment
        JavaLetter
            :   [a-zA-Z$_] // these are the "java letters" below 0xFF
            |   // covers all characters above 0xFF which are not a surrogate
                ~[\u0000-\u00FF\uD800-\uDBFF]
                {Character.isJavaIdentifierStart(_input.LA(-1))}?
            |   // covers UTF-16 surrogate pairs encodings for U+10000 to U+10FFFF
                [\uD800-\uDBFF] [\uDC00-\uDFFF]
                {Character.isJavaIdentifierStart(Character.toCodePoint((char)_input.LA(-2), (char)_input.LA(-1)))}?
            ;
        
        fragment
        JavaLetterOrDigit
            :   [a-zA-Z0-9$_] // these are the "java letters or digits" below 0xFF
            |   // covers all characters above 0xFF which are not a surrogate
                ~[\u0000-\u00FF\uD800-\uDBFF]
                {Character.isJavaIdentifierPart(_input.LA(-1))}?
            |   // covers UTF-16 surrogate pairs encodings for U+10000 to U+10FFFF
                [\uD800-\uDBFF] [\uDC00-\uDFFF]
                {Character.isJavaIdentifierPart(Character.toCodePoint((char)_input.LA(-2), (char)_input.LA(-1)))}?
            ;

在这里你可以看到解析树,缺少andExpression

只有第一部分被解析,因为规则 prog: (stat)+; 只被告知要解析至少 1 个 stat,它确实这样做了。如果您希望解析器处理所有标记,请使用 EOF 标记“锚定”您的开始规则:

prog : stat+ EOF;

现在您的输入 isSet(foo) or isSet(bar) and isSet(test) 将产生一条错误消息。第一部分 isSet(foo) or isSet(bar) 仍被识别为 orExpression,但无法匹配最后一部分 and isSet(test)。一般的想法是做这样的事情:

prog          : stat+ EOF;
stat          : orExpression+;
orExpression  : andExpression ( OR andExpression | XOR andExpression)*;
andExpression : notExpression ( AND notExpression)*;
notExpression : NOT? command;
command       : IS_SET LPAREN parameter RPAREN
              | IS_EMPTY LPAREN parameter RPAREN;
parameter     : ID;

但是ANTLR4支持直接左递归规则,所以上面的规则你也可以这样写:

prog: expr+ EOF;

expr
 : NOT expr                  #NotExpr
 | expr AND expr             #AndExpr
 | expr (OR | XOR) expr      #OrExpr
 | IS_SET LPAREN expr RPAREN #CommandExpr
 | ID                        #IdExpr
 ;

在我看来,这要好得多。