控制解析器规则替代优先级

Controlling parser rule alternatives precedence

我有一个表达式IF 1 THEN 2 ELSE 3 * 4。我希望将其解析为 IF 1 THEN 2 ELSE (3 * 4),但是使用下面的语法(摘录),它将其解析为 (IF 1 THEN 2 ELSE 3) * 4.

formula: expression EOF;

expression
   : LPAREN expression RPAREN #parenthesisExp
   | IF condition=expression THEN thenExpression=expression ELSE elseExpression=expression #ifExp
   | left=expression BINARYOPERATOR right=expression #binaryoperationExp
   | left=expression op=(TIMES|DIV) right=expression    #muldivExp
   | left=expression op=(PLUS|MINUS) right=expression    #addsubtractExp
   | left=expression op=(EQUALS|NOTEQUALS|LT|GT) right=expression #comparisonExp
   | left=expression AMPERSAND right=expression #concatenateExp
   | NOT expression #notExp
   | STRINGLITERAL #stringliteralExp
   | signedAtom #atomExp
   ;

我的理解是,因为我在 muldivExp 之前有 ifExp 替代项,所以应该首先使用它,然后因为我在 atomExp 之前有 muldivExp (它处理数字)它应该做 3 * 4 来结束 ELSE,而不是只使用 3。在这种情况下,我不明白为什么它使 IF..THEN..ELSE 成为乘法的子项。


我认为语法的其余部分与此处无关,但以防万一,请参阅下文。

grammar AnaplanFormula;

formula: expression EOF;

expression
   : LPAREN expression RPAREN #parenthesisExp
   | IF condition=expression THEN thenExpression=expression ELSE elseExpression=expression #ifExp
   | left=expression BINARYOPERATOR right=expression #binaryoperationExp
   | left=expression op=(TIMES|DIV) right=expression    #muldivExp
   | left=expression op=(PLUS|MINUS) right=expression    #addsubtractExp
   | left=expression op=(EQUALS|NOTEQUALS|LT|GT) right=expression #comparisonExp
   | left=expression AMPERSAND right=expression #concatenateExp
   | NOT expression #notExp
   | STRINGLITERAL #stringliteralExp
   | signedAtom #atomExp
   ;

signedAtom
   : PLUS signedAtom #plusSignedAtom
   | MINUS signedAtom #minusSignedAtom
   | func_ #funcAtom
   | atom #atomAtom
   ;

atom
   : SCIENTIFIC_NUMBER #numberAtom
   | LPAREN expression RPAREN #expressionAtom // Do we need this?
   | entity #entityAtom
   ;

func_: functionname LPAREN (expression (',' expression)*)? RPAREN #funcParameterised
   | entity LSQUARE dimensionmapping (',' dimensionmapping)* RSQUARE #funcSquareBrackets
   ;

dimensionmapping: WORD COLON entity; // Could make WORD more specific here

functionname: WORD; // Could make WORD more specific here

entity: QUOTELITERAL #quotedEntity
   | WORD+ #wordsEntity
   | left=entity DOT right=entity #dotQualifiedEntity
   ;

WS: [ \r\n\t]+ -> skip;

/////////////////
//  Fragments  //
/////////////////

fragment NUMBER: DIGIT+ (DOT DIGIT+)?;

fragment DIGIT: [0-9];
fragment LOWERCASE: [a-z];
fragment UPPERCASE: [A-Z];
fragment WORDSYMBOL: [#?_£%];

//////////////////
//    Tokens    //
//////////////////

IF: 'IF' | 'if';
THEN: 'THEN' | 'then';
ELSE: 'ELSE' | 'else';
BINARYOPERATOR: 'AND' | 'and' | 'OR' | 'or';
NOT: 'NOT' | 'not';

WORD: (DIGIT* (LOWERCASE | UPPERCASE | WORDSYMBOL)) (LOWERCASE | UPPERCASE | DIGIT | WORDSYMBOL)*;

STRINGLITERAL: DOUBLEQUOTES (~'"' | ('""'))* DOUBLEQUOTES;

QUOTELITERAL: '\'' (~'\'' | ('\'\''))* '\'';

LSQUARE: '[';
RSQUARE: ']';
LPAREN: '(';
RPAREN: ')';
PLUS: '+';
MINUS: '-';
TIMES: '*';
DIV: '/';
COLON: ':';
EQUALS: '=';
NOTEQUALS: LT GT;
LT: '<';
GT: '>';
AMPERSAND: '&';
DOUBLEQUOTES: '"';
UNDERSCORE: '_';
QUESTIONMARK: '?';
HASH: '#';
POUND: '£';
PERCENT: '%';
DOT: '.';
PIPE: '|';

SCIENTIFIC_NUMBER: NUMBER (('e' | 'E') (PLUS | MINUS)? NUMBER)?;

将您的 ifExpr 向下移动到备选方案的末尾。 (特别是,在您希望匹配您的 elseExpression

的任何备选方案下方

您的“如果...那么...其他...”低于 muldivExp 正是因为您将其设置为更高的优先级。树中较低的项目在树中较高的项目之前被评估,因此优先级较高的项目属于树中较低的项目。

有:

expression:
    LPAREN expression RPAREN                                                                        # parenthesisExp
    | left = expression BINARYOPERATOR right = expression                                           # binaryoperationExp
    | left = expression op = (TIMES | DIV) right = expression                                       # muldivExp
    | left = expression op = (PLUS | MINUS) right = expression                                      # addsubtractExp
    | left = expression op = (EQUALS | NOTEQUALS | LT | GT) right = expression                      # comparisonExp
    | left = expression AMPERSAND right = expression                                                # concatenateExp
    | NOT expression                                                                                # notExp
    | STRINGLITERAL                                                                                 # stringliteralExp
    | signedAtom                                                                                    # atomExp
    | IF condition = expression THEN thenExpression = expression ELSE elseExpression = expression   #
        ifExp
    ;

我明白了