Search code examples
antlrantlr3antlrworks

How to resolve this ambiguous grammar?


I have written this grammar:

expr        : multExpr ( ('+' | '-') multExpr )*;
multExpr    : atom ( ('*' | '/') atom )*;
atom    : INT | FLOAT | ID | '(' expr ')';
condition   : cond ('or' cond)*;
cond    : c1 ('and' c1)*;
c1      : ('not')? c2;
c2      : '(' condition ')' | boolean;
boolean : expr (relop expr | ²) | 'true' | 'false';
relop   : '<' | '<=' | '>' | '>=' | '==' | '!=';

I have omitted the lexer rules for INT,FLOAT,ID as it is obvious.

The problem is c2 rule, it is ambiguous because of '(', I could not find the solution, can you offer me a solution?


Solution

  • Why not simply do:

    expr      : orExpr; 
    orExpr    : andExpr ('or' andExpr)*;
    andExpr   : relExpr ('and' relExpr)*;
    relExpr   : addExpr (relop addExpr)?;
    relop     : '<' | '<=' | '>' | '>=' | '==' | '!=';
    addExpr   : multExpr (('+' | '-') multExpr)*;
    multExpr  : unaryExpr (('*' | '/') unaryExpr)*;
    unaryExpr : 'not'? atom;
    atom      : INT | FLOAT | ID | 'true' | 'false' | '(' expr ')';
    

    The unary not usually has a higher precedence than you're trying to do now.

    This will allow for expressions like 42 > true, but checking such semantics can come when you're walking the AST/tree.

    EDIT

    The input "not(a+b >= 2 * foo/3.14159) == false" would now be parsed like this (ignoring spaces):

    enter image description here

    And if you set the output to AST and mix in some tree rewrite operators (^ and !):

    options {
      output=AST;
    }
    
    // ...
    
    expr      : orExpr; 
    orExpr    : andExpr ('or'^ andExpr)*;
    andExpr   : relExpr ('and'^ relExpr)*;
    relExpr   : addExpr (relop^ addExpr)?;
    relop     : '<' | '<=' | '>' | '>=' | '==' | '!=';
    addExpr   : multExpr (('+' | '-')^ multExpr)*;
    multExpr  : unaryExpr (('*' | '/')^ unaryExpr)*;
    unaryExpr : 'not'^ atom | atom;
    atom      : INT | FLOAT | ID | 'true' | 'false' | '('! expr ')'!;
    

    you'd get:

    enter image description here