Nested Boolean Expression Parser using ANTLR

后端 未结 1 1057
野的像风
野的像风 2020-12-29 07:46

I\'m trying to parse a Nested Boolean Expression and get the individual conditions within the expression separately. For e.g., if the input string is:

(A = a OR B =

相关标签:
1条回答
  • 2020-12-29 08:11

    I'd just wrap all the expressions into a single expression rule. Be sure to define the comparator expressions alternative before your binary expression alternative to make sure comparator operators bind more tightly than OR and AND:

    grammar SimpleBoolean;
    
    parse
     : expression EOF
     ;
    
    expression
     : LPAREN expression RPAREN                       #parenExpression
     | NOT expression                                 #notExpression
     | left=expression op=comparator right=expression #comparatorExpression
     | left=expression op=binary right=expression     #binaryExpression
     | bool                                           #boolExpression
     | IDENTIFIER                                     #identifierExpression
     | DECIMAL                                        #decimalExpression
     ;
    
    comparator
     : GT | GE | LT | LE | EQ
     ;
    
    binary
     : AND | OR
     ;
    
    bool
     : TRUE | FALSE
     ;
    
    AND        : 'AND' ;
    OR         : 'OR' ;
    NOT        : 'NOT';
    TRUE       : 'TRUE' ;
    FALSE      : 'FALSE' ;
    GT         : '>' ;
    GE         : '>=' ;
    LT         : '<' ;
    LE         : '<=' ;
    EQ         : '=' ;
    LPAREN     : '(' ;
    RPAREN     : ')' ;
    DECIMAL    : '-'? [0-9]+ ( '.' [0-9]+ )? ;
    IDENTIFIER : [a-zA-Z_] [a-zA-Z_0-9]* ;
    WS         : [ \r\t\u000C\n]+ -> skip;
    

    To test the grammar above, use the following quick-and-dirty test classes:

    public class Main {
    
      public static void main(String[] args) throws Exception {
    
        Map<String, Object> variables = new HashMap<String, Object>() {{
          put("A", true);
          put("a", true);
          put("B", false);
          put("b", false);
          put("C", 42.0);
          put("c", 42.0);
          put("D", -999.0);
          put("d", -1999.0);
          put("E", 42.001);
          put("e", 142.001);
          put("F", 42.001);
          put("f", 42.001);
          put("G", -1.0);
          put("g", -1.0);
        }};
    
        String[] expressions = {
            "1 > 2",
            "1 >= 1.0",
            "TRUE = FALSE",
            "FALSE = FALSE",
            "A OR B",
            "B",
            "A = B",
            "c = C",
            "E > D",
            "B OR (c = B OR (A = A AND c = C AND E > D))",
            "(A = a OR B = b OR C = c AND ((D = d AND E = e) OR (F = f AND G = g)))"
        };
    
        for (String expression : expressions) {
          SimpleBooleanLexer lexer = new SimpleBooleanLexer(new ANTLRInputStream(expression));
          SimpleBooleanParser parser = new SimpleBooleanParser(new CommonTokenStream(lexer));
          Object result = new EvalVisitor(variables).visit(parser.parse());
          System.out.printf("%-70s -> %s\n", expression, result);
        }
      }
    }
    
    class EvalVisitor extends SimpleBooleanBaseVisitor<Object> {
    
      private final Map<String, Object> variables;
    
      public EvalVisitor(Map<String, Object> variables) {
        this.variables = variables;
      }
    
      @Override
      public Object visitParse(SimpleBooleanParser.ParseContext ctx) {
        return super.visit(ctx.expression());
      }
    
      @Override
      public Object visitDecimalExpression(SimpleBooleanParser.DecimalExpressionContext ctx) {
        return Double.valueOf(ctx.DECIMAL().getText());
      }
    
      @Override
      public Object visitIdentifierExpression(SimpleBooleanParser.IdentifierExpressionContext ctx) {
        return variables.get(ctx.IDENTIFIER().getText());
      }
    
      @Override
      public Object visitNotExpression(SimpleBooleanParser.NotExpressionContext ctx) {
        return !((Boolean)this.visit(ctx.expression()));
      }
    
      @Override
      public Object visitParenExpression(SimpleBooleanParser.ParenExpressionContext ctx) {
        return super.visit(ctx.expression());
      }
    
      @Override
      public Object visitComparatorExpression(SimpleBooleanParser.ComparatorExpressionContext ctx) {
        if (ctx.op.EQ() != null) {
          return this.visit(ctx.left).equals(this.visit(ctx.right));
        }
        else if (ctx.op.LE() != null) {
          return asDouble(ctx.left) <= asDouble(ctx.right);
        }
        else if (ctx.op.GE() != null) {
          return asDouble(ctx.left) >= asDouble(ctx.right);
        }
        else if (ctx.op.LT() != null) {
          return asDouble(ctx.left) < asDouble(ctx.right);
        }
        else if (ctx.op.GT() != null) {
          return asDouble(ctx.left) > asDouble(ctx.right);
        }
        throw new RuntimeException("not implemented: comparator operator " + ctx.op.getText());
      }
    
      @Override
      public Object visitBinaryExpression(SimpleBooleanParser.BinaryExpressionContext ctx) {
        if (ctx.op.AND() != null) {
          return asBoolean(ctx.left) && asBoolean(ctx.right);
        }
        else if (ctx.op.OR() != null) {
          return asBoolean(ctx.left) || asBoolean(ctx.right);
        }
        throw new RuntimeException("not implemented: binary operator " + ctx.op.getText());
      }
    
      @Override
      public Object visitBoolExpression(SimpleBooleanParser.BoolExpressionContext ctx) {
        return Boolean.valueOf(ctx.getText());
      }
    
      private boolean asBoolean(SimpleBooleanParser.ExpressionContext ctx) {
        return (boolean)visit(ctx);
      }
    
      private double asDouble(SimpleBooleanParser.ExpressionContext ctx) {
        return (double)visit(ctx);
      }
    }
    

    Running the Main class will result in the following output:

    1 > 2                                                                  -> false
    1 >= 1.0                                                               -> true
    TRUE = FALSE                                                           -> false
    FALSE = FALSE                                                          -> true
    A OR B                                                                 -> true
    B                                                                      -> false
    A = B                                                                  -> false
    c = C                                                                  -> true
    E > D                                                                  -> true
    B OR (c = B OR (A = A AND c = C AND E > D))                            -> true
    (A = a OR B = b OR C = c AND ((D = d AND E = e) OR (F = f AND G = g))) -> true
    
    0 讨论(0)
提交回复
热议问题